[clang] [clang] Introduce `SemaCodeCompletion` (PR #92311)

2024-05-17 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/92311
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][ThreadSafety] Skip past implicit cast in `translateAttrExpr` (PR #92277)

2024-05-17 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/92277
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-repl] Extend the C support. (PR #89804)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -2282,7 +2282,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
 
 // Remove this name from our lexical scope, and warn on it if we haven't
 // already.
-IdResolver.RemoveDecl(D);
+if (!PP.isIncrementalProcessingEnabled())
+  IdResolver.RemoveDecl(D);

AaronBallman wrote:

so in incremental processing mode, we never remove declarations from the id 
resolver, so they always stay available? e.g.,
```
{
  int i = 12;
}
printf("%d", i); // Fine?
```


https://github.com/llvm/llvm-project/pull/89804
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-repl] Extend the C support. (PR #89804)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -407,6 +406,16 @@ void IncrementalParser::CleanUpPTU(PartialTranslationUnit 
) {
   }
 }
   }
+
+  // FIXME: We should de-allocate MostRecentTU
+  for (Decl *D : MostRecentTU->decls()) {
+if (!isa(D))
+  continue;
+// Check if we need to clean up the IdResolver chain.
+NamedDecl *ND = cast(D);

AaronBallman wrote:

```suggestion
const auto *ND = dyn_cast(D);
if (!ND)
  continue;
// Check if we need to clean up the IdResolver chain.
```

https://github.com/llvm/llvm-project/pull/89804
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Sema] Fix crash when diagnosing near-match for 'constexpr' redeclaration in C++11 (PR #92452)

2024-05-17 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/92452
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -4639,6 +4645,303 @@ class FunctionNoProtoType : public FunctionType, public 
llvm::FoldingSetNode {
   }
 };
 
+// 
--
+
+/// Represents an abstract function effect, using just an enumeration 
describing
+/// its kind.
+class FunctionEffect {
+public:
+  /// Identifies the particular effect.
+  enum class Kind : uint8_t {
+None = 0,
+NonBlocking = 1,
+NonAllocating = 2,
+Blocking = 3,
+Allocating = 4
+  };
+
+  /// Flags describing some behaviors of the effect.
+  using Flags = unsigned;
+  enum FlagBit : Flags {
+// Can verification inspect callees' implementations? (e.g. nonblocking:
+// yes, tcb+types: no). This also implies the need for 2nd-pass
+// verification.
+FE_InferrableOnCallees = 0x1,
+
+// Language constructs which effects can diagnose as disallowed.
+FE_ExcludeThrow = 0x2,
+FE_ExcludeCatch = 0x4,
+FE_ExcludeObjCMessageSend = 0x8,
+FE_ExcludeStaticLocalVars = 0x10,
+FE_ExcludeThreadLocalVars = 0x20
+  };
+
+private:
+  LLVM_PREFERRED_TYPE(Kind)
+  unsigned FKind : 3;
+
+  // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
+  // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
+  // be considered for uniqueness.
+
+public:
+  FunctionEffect() : FKind(unsigned(Kind::None)) {}
+
+  explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {}
+
+  /// The kind of the effect.
+  Kind kind() const { return Kind(FKind); }
+
+  /// Return the opposite kind, for effects which have opposites.
+  Kind oppositeKind() const;
+
+  /// For serialization.
+  uint32_t toOpaqueInt32() const { return FKind; }
+  static FunctionEffect fromOpaqueInt32(uint32_t Value) {
+return FunctionEffect(Kind(Value));
+  }
+
+  /// Flags describing some behaviors of the effect.
+  Flags flags() const {
+switch (kind()) {
+case Kind::NonBlocking:
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
+ FE_ExcludeThreadLocalVars;
+case Kind::NonAllocating:
+  // Same as NonBlocking, except without FE_ExcludeStaticLocalVars
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
+case Kind::Blocking:
+case Kind::Allocating:
+  return 0;
+case Kind::None:
+  break;
+}
+llvm_unreachable("unknown effect kind");
+  }
+
+  /// The description printed in diagnostics, e.g. 'nonblocking'.
+  StringRef name() const;
+
+  /// Return true if the effect is allowed to be inferred on the callee,
+  /// which is either a FunctionDecl or BlockDecl.
+  /// This is only used if the effect has FE_InferrableOnCallees flag set.
+  /// Example: This allows nonblocking(false) to prevent inference for the
+  /// function.
+  bool canInferOnFunction(const Decl ) const;
+
+  // Return false for success. When true is returned for a direct call, then 
the
+  // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+  // diagnostic. Caller should be assumed to have the effect (it may not have 
it
+  // explicitly when inferring).
+  bool shouldDiagnoseFunctionCall(bool Direct,
+  ArrayRef CalleeFX) const;
+
+  friend bool operator==(const FunctionEffect , const FunctionEffect ) 
{
+return LHS.FKind == RHS.FKind;
+  }
+  friend bool operator!=(const FunctionEffect , const FunctionEffect ) 
{
+return !(LHS == RHS);
+  }
+  friend bool operator<(const FunctionEffect , const FunctionEffect ) {
+return LHS.FKind < RHS.FKind;
+  }
+};
+
+/// Wrap a function effect's condition expression in another struct so
+/// that FunctionProtoType's TrailingObjects can treat it separately.
+class FunctionEffectCondition {
+  Expr *Cond = nullptr; // if null, unconditional
+
+public:
+  FunctionEffectCondition() = default;
+  FunctionEffectCondition(Expr *E) : Cond(E) {} // implicit OK
+
+  Expr *expr() const { return Cond; }
+
+  bool operator==(const FunctionEffectCondition ) const {
+return Cond == RHS.Cond;
+  }
+};
+
+/// A FunctionEffect plus a potential boolean expression determining whether
+/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
+/// expression when present, is dependent.
+struct FunctionEffectWithCondition {
+  FunctionEffect Effect;
+  FunctionEffectCondition Cond;
+
+  FunctionEffectWithCondition() = default;
+  FunctionEffectWithCondition(const FunctionEffect ,
+  const FunctionEffectCondition )
+  : Effect(E), Cond(C) {}
+
+  /// Return a textual description of the effect, and its condition, if any.
+  std::string description() const;
+
+  friend bool operator<(const FunctionEffectWithCondition ,
+const FunctionEffectWithCondition ) {
+if (LHS.Effect < RHS.Effect)
+   

[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -1435,6 +1435,38 @@ def CXX11NoReturn : InheritableAttr {
   let Documentation = [CXX11NoReturnDocs];
 }
 
+def NonBlocking : TypeAttr {
+  let Spellings = [CXX11<"clang", "nonblocking">,

AaronBallman wrote:

Present Aaron thanks you and Past Aaron apologized for the churn. ;-)

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -4639,6 +4645,303 @@ class FunctionNoProtoType : public FunctionType, public 
llvm::FoldingSetNode {
   }
 };
 
+// 
--
+
+/// Represents an abstract function effect, using just an enumeration 
describing
+/// its kind.
+class FunctionEffect {
+public:
+  /// Identifies the particular effect.
+  enum class Kind : uint8_t {
+None = 0,
+NonBlocking = 1,
+NonAllocating = 2,
+Blocking = 3,
+Allocating = 4
+  };
+
+  /// Flags describing some behaviors of the effect.
+  using Flags = unsigned;
+  enum FlagBit : Flags {
+// Can verification inspect callees' implementations? (e.g. nonblocking:
+// yes, tcb+types: no). This also implies the need for 2nd-pass
+// verification.
+FE_InferrableOnCallees = 0x1,
+
+// Language constructs which effects can diagnose as disallowed.
+FE_ExcludeThrow = 0x2,
+FE_ExcludeCatch = 0x4,
+FE_ExcludeObjCMessageSend = 0x8,
+FE_ExcludeStaticLocalVars = 0x10,
+FE_ExcludeThreadLocalVars = 0x20
+  };
+
+private:
+  LLVM_PREFERRED_TYPE(Kind)
+  unsigned FKind : 3;
+
+  // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
+  // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
+  // be considered for uniqueness.
+
+public:
+  FunctionEffect() : FKind(unsigned(Kind::None)) {}
+
+  explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {}
+
+  /// The kind of the effect.
+  Kind kind() const { return Kind(FKind); }
+
+  /// Return the opposite kind, for effects which have opposites.
+  Kind oppositeKind() const;
+
+  /// For serialization.
+  uint32_t toOpaqueInt32() const { return FKind; }
+  static FunctionEffect fromOpaqueInt32(uint32_t Value) {
+return FunctionEffect(Kind(Value));
+  }
+
+  /// Flags describing some behaviors of the effect.
+  Flags flags() const {
+switch (kind()) {
+case Kind::NonBlocking:
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
+ FE_ExcludeThreadLocalVars;
+case Kind::NonAllocating:
+  // Same as NonBlocking, except without FE_ExcludeStaticLocalVars
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
+case Kind::Blocking:
+case Kind::Allocating:
+  return 0;
+case Kind::None:
+  break;
+}
+llvm_unreachable("unknown effect kind");
+  }
+
+  /// The description printed in diagnostics, e.g. 'nonblocking'.
+  StringRef name() const;
+
+  /// Return true if the effect is allowed to be inferred on the callee,
+  /// which is either a FunctionDecl or BlockDecl.
+  /// This is only used if the effect has FE_InferrableOnCallees flag set.
+  /// Example: This allows nonblocking(false) to prevent inference for the
+  /// function.
+  bool canInferOnFunction(const Decl ) const;
+
+  // Return false for success. When true is returned for a direct call, then 
the
+  // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+  // diagnostic. Caller should be assumed to have the effect (it may not have 
it
+  // explicitly when inferring).
+  bool shouldDiagnoseFunctionCall(bool Direct,
+  ArrayRef CalleeFX) const;
+
+  friend bool operator==(const FunctionEffect , const FunctionEffect ) 
{
+return LHS.FKind == RHS.FKind;
+  }
+  friend bool operator!=(const FunctionEffect , const FunctionEffect ) 
{
+return !(LHS == RHS);
+  }
+  friend bool operator<(const FunctionEffect , const FunctionEffect ) {
+return LHS.FKind < RHS.FKind;
+  }
+};
+
+/// Wrap a function effect's condition expression in another struct so
+/// that FunctionProtoType's TrailingObjects can treat it separately.
+class FunctionEffectCondition {
+  Expr *Cond = nullptr; // if null, unconditional
+
+public:
+  FunctionEffectCondition() = default;
+  FunctionEffectCondition(Expr *E) : Cond(E) {} // implicit OK
+
+  Expr *expr() const { return Cond; }
+
+  bool operator==(const FunctionEffectCondition ) const {
+return Cond == RHS.Cond;
+  }
+};
+
+/// A FunctionEffect plus a potential boolean expression determining whether
+/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
+/// expression when present, is dependent.
+struct FunctionEffectWithCondition {
+  FunctionEffect Effect;
+  FunctionEffectCondition Cond;
+
+  FunctionEffectWithCondition() = default;
+  FunctionEffectWithCondition(const FunctionEffect ,
+  const FunctionEffectCondition )
+  : Effect(E), Cond(C) {}
+
+  /// Return a textual description of the effect, and its condition, if any.
+  std::string description() const;
+
+  friend bool operator<(const FunctionEffectWithCondition ,
+const FunctionEffectWithCondition ) {
+if (LHS.Effect < RHS.Effect)
+   

[clang] [clang-tools-extra] [llvm] [clang-query] Remove support for srcloc output (PR #92442)

2024-05-17 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman closed 
https://github.com/llvm/llvm-project/pull/92442
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Sema] Fix crash when diagnosing near-match for 'constexpr' redeclaration in C++11 (PR #92452)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -1527,20 +1527,20 @@ struct DeclaratorChunk {
 
 /// Retrieve the location of the 'const' qualifier.
 SourceLocation getConstQualifierLoc() const {
-  assert(MethodQualifiers);
-  return MethodQualifiers->getConstSpecLoc();
+  return MethodQualifiers ? MethodQualifiers->getConstSpecLoc()

AaronBallman wrote:

`DeclSpec.h` is basically used only to gather information from the parser, and 
so from that perspective, I think the `assert` makes sense. If the caller is 
asking for the location of the `const` qualifier and one wasn't written in 
source, the caller is doing something out of the ordinary.

I think the fix-it code should be guarded by a call to 
`hasMethodTypeQualifiers()` instead.

https://github.com/llvm/llvm-project/pull/92452
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Sema] Fix crash when diagnosing near-match for 'constexpr' redeclaration in C++11 (PR #92452)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -9203,15 +9203,15 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
 << Idx << FDParam->getType()
 << NewFD->getParamDecl(Idx - 1)->getType();
 } else if (FDisConst != NewFDisConst) {
-  SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match)
-  << NewFDisConst << FD->getSourceRange().getEnd()
-  << (NewFDisConst
-  ? FixItHint::CreateRemoval(ExtraArgs.D.getFunctionTypeInfo()
- .getConstQualifierLoc())
-  : 
FixItHint::CreateInsertion(ExtraArgs.D.getFunctionTypeInfo()
-   .getRParenLoc()
-   .getLocWithOffset(1),
-   " const"));
+  auto DB = SemaRef.Diag(FD->getLocation(),
+ diag::note_member_def_close_const_match)
+<< NewFDisConst << FD->getSourceRange().getEnd();
+  if (const auto  = ExtraArgs.D.getFunctionTypeInfo(); !NewFDisConst)
+DB << 
FixItHint::CreateInsertion(FTI.getRParenLoc().getLocWithOffset(1),
+ " const");
+  else if (SourceLocation ConstLoc = FTI.getConstQualifierLoc();

AaronBallman wrote:

I think that hides subtle issues; the caller should really know the difference 
between "const qualifier as written" and "semantically const".

https://github.com/llvm/llvm-project/pull/92452
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Warn consecutive builtin comparisons in an expression (PR #92200)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -487,6 +487,9 @@ Improvements to Clang's diagnostics
}
  };
 
+- Clang emits a ``-Wparentheses`` warning for expressions with consecutive 
comparisons like ``x < y < z``.
+  It was made a ``-Wparentheses`` warning to be consistent with gcc.

AaronBallman wrote:

```suggestion
- Clang emits a ``-Wparentheses`` warning for expressions with consecutive 
comparisons like ``x < y < z``.
  Fixes #GH20456.
```

https://github.com/llvm/llvm-project/pull/92200
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Warn consecutive builtin comparisons in an expression (PR #92200)

2024-05-17 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

LGTM aside from a small nit with the release notes.

https://github.com/llvm/llvm-project/pull/92200
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Warn consecutive builtin comparisons in an expression (PR #92200)

2024-05-17 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/92200
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Warn consecutive builtin comparisons in an expression (PR #92200)

2024-05-17 Thread Aaron Ballman via cfe-commits


@@ -215,3 +215,10 @@ namespace PR20735 {
 // fix-it:"{{.*}}":{[[@LINE-9]]:20-[[@LINE-9]]:20}:")"
   }
 }
+
+void consecutive_builtin_compare(int x, int y, int z) {
+  (void)(x < y < z);  // expected-warning {{comparisons like 'X<=Y<=Z' don't 
have their mathematical meaning}}
+  (void)(x < y > z);  // expected-warning {{comparisons like 'X<=Y<=Z' don't 
have their mathematical meaning}}
+  (void)(x < y <= z); // expected-warning {{comparisons like 'X<=Y<=Z' don't 
have their mathematical meaning}}
+  (void)(x <= y > z); // expected-warning {{comparisons like 'X<=Y<=Z' don't 
have their mathematical meaning}}

AaronBallman wrote:

> I don't have the capacity to further make clang diagnose case 2 but not case 
> 3.
> I added a TODO note at the bottom of the test lines for now.

SGTM!

https://github.com/llvm/llvm-project/pull/92200
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -7963,6 +7968,154 @@ static Attr *getCCTypeAttr(ASTContext , ParsedAttr 
) {
   llvm_unreachable("unexpected attribute kind!");
 }
 
+std::optional
+Sema::ActOnEffectExpression(Expr *CondExpr, StringRef AttributeName) {
+  auto BadExpr = [&]() {
+Diag(CondExpr->getExprLoc(), diag::err_attribute_argument_type)
+<< ("'" + AttributeName.str() + "'") << AANT_ArgumentIntegerConstant
+<< CondExpr->getSourceRange();
+return std::nullopt;
+  };
+
+  if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
+if (CondExpr->containsUnexpandedParameterPack())
+  return BadExpr();
+return FunctionEffectMode::Dependent;
+  }
+
+  std::optional ConditionValue =
+  CondExpr->getIntegerConstantExpr(Context);
+  if (!ConditionValue)
+return BadExpr();
+  return ConditionValue->getExtValue() ? FunctionEffectMode::True
+   : FunctionEffectMode::False;
+}
+
+static bool
+handleNonBlockingNonAllocatingTypeAttr(TypeProcessingState ,
+   ParsedAttr , QualType ,
+   FunctionTypeUnwrapper ) {
+  // Delay if this is not a function type.
+  if (!Unwrapped.isFunctionType())
+return false;
+
+  Sema  = TPState.getSema();
+
+  // Require FunctionProtoType
+  auto *FPT = Unwrapped.get()->getAs();
+  if (FPT == nullptr) {
+S.Diag(PAttr.getLoc(), diag::err_func_with_effects_no_prototype)
+<< PAttr.getAttrName()->getName();
+return true;
+  }
+
+  // Parse the new  attribute.
+  // non/blocking or non/allocating? Or conditional (computed)?
+  const bool IsNonBlocking = PAttr.getKind() == ParsedAttr::AT_NonBlocking ||

AaronBallman wrote:

Our const correctness story is a story of sadness and woe, but we basically 
don't use top-level const in the project (`const foo *` is encouraged, `const 
foo * const` is not). And we rely on this to some extent with our uses of 
`const_cast` to cast away const presuming that the original definition is not 
actually `const`, so it's usually best to just consistently drop top-level 
const.

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -1435,6 +1435,38 @@ def CXX11NoReturn : InheritableAttr {
   let Documentation = [CXX11NoReturnDocs];
 }
 
+def NonBlocking : TypeAttr {
+  let Spellings = [CXX11<"clang", "nonblocking">,

AaronBallman wrote:

Yeah, Present Aaron regrets Past Aaron's caution there (there was a concern 
that `builtin_alias` really was plausibly going to be used by GCC but with a 
potentially different syntax, but that's the case with all attributes in the 
shared namespace, so I really shouldn't have asked for that prefix. Mea culpa!).

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -1435,6 +1435,38 @@ def CXX11NoReturn : InheritableAttr {
   let Documentation = [CXX11NoReturnDocs];
 }
 
+def NonBlocking : TypeAttr {
+  let Spellings = [CXX11<"clang", "nonblocking">,

AaronBallman wrote:

CC @erichkeane 

`clang_builtin_alias` is the only attribute we prefix in that way; I don't 
think it's a good precedent. GNU attributes are a shared namespace, but we have 
plenty of other examples where we define a GNU attribute that GCC doesn't 
support (overloadable, noderef, preferred_name, etc).

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Sema] Avoid pack expansion for expanded empty PackIndexingExprs (PR #92385)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -4381,11 +4381,13 @@ class PackIndexingExpr final
 
   PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr, Expr 
*IndexExpr,
-   ArrayRef SubstitutedExprs = {})
+   ArrayRef SubstitutedExprs = {},
+   bool EmptyPack = false)
   : Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
 EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
 SubExprs{PackIdExpr, IndexExpr},
-TransformedExpressions(SubstitutedExprs.size()) {
+TransformedExpressions(EmptyPack ? size_t(-1)

AaronBallman wrote:

FYI: the types of the bit-fields need to be the same, otherwise they won't pack 
together as expected with MSVC.

https://github.com/llvm/llvm-project/pull/92385
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -7963,6 +7968,154 @@ static Attr *getCCTypeAttr(ASTContext , ParsedAttr 
) {
   llvm_unreachable("unexpected attribute kind!");
 }
 
+std::optional
+Sema::ActOnEffectExpression(Expr *CondExpr, StringRef AttributeName) {
+  auto BadExpr = [&]() {
+Diag(CondExpr->getExprLoc(), diag::err_attribute_argument_type)
+<< ("'" + AttributeName.str() + "'") << AANT_ArgumentIntegerConstant
+<< CondExpr->getSourceRange();
+return std::nullopt;
+  };
+
+  if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
+if (CondExpr->containsUnexpandedParameterPack())
+  return BadExpr();
+return FunctionEffectMode::Dependent;
+  }
+
+  std::optional ConditionValue =
+  CondExpr->getIntegerConstantExpr(Context);
+  if (!ConditionValue)
+return BadExpr();
+  return ConditionValue->getExtValue() ? FunctionEffectMode::True
+   : FunctionEffectMode::False;
+}
+
+static bool
+handleNonBlockingNonAllocatingTypeAttr(TypeProcessingState ,
+   ParsedAttr , QualType ,
+   FunctionTypeUnwrapper ) {
+  // Delay if this is not a function type.
+  if (!Unwrapped.isFunctionType())
+return false;
+
+  Sema  = TPState.getSema();
+
+  // Require FunctionProtoType
+  auto *FPT = Unwrapped.get()->getAs();
+  if (FPT == nullptr) {
+S.Diag(PAttr.getLoc(), diag::err_func_with_effects_no_prototype)
+<< PAttr.getAttrName()->getName();
+return true;
+  }
+
+  // Parse the new  attribute.
+  // non/blocking or non/allocating? Or conditional (computed)?
+  const bool IsNonBlocking = PAttr.getKind() == ParsedAttr::AT_NonBlocking ||

AaronBallman wrote:

```suggestion
  bool IsNonBlocking = PAttr.getKind() == ParsedAttr::AT_NonBlocking ||
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -5028,3 +5060,263 @@ void AutoType::Profile(llvm::FoldingSetNodeID , 
const ASTContext ) {
   Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
   getTypeConstraintConcept(), getTypeConstraintArguments());
 }
+
+FunctionEffect::Kind FunctionEffect::oppositeKind() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return Kind::Blocking;
+  case Kind::Blocking:
+return Kind::NonBlocking;
+  case Kind::NonAllocating:
+return Kind::Allocating;
+  case Kind::Allocating:
+return Kind::NonAllocating;
+  case Kind::None:
+return Kind::None;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+StringRef FunctionEffect::name() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return "nonblocking";
+  case Kind::NonAllocating:
+return "nonallocating";
+  case Kind::Blocking:
+return "blocking";
+  case Kind::Allocating:
+return "allocating";
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+bool FunctionEffect::canInferOnFunction(const Decl ) const {
+  switch (kind()) {
+  case Kind::NonAllocating:
+  case Kind::NonBlocking: {
+FunctionEffectsRef CalleeFX;
+if (auto *FD = Callee.getAsFunction())
+  CalleeFX = FD->getFunctionEffects();
+else if (auto *BD = dyn_cast())
+  CalleeFX = BD->getFunctionEffects();
+else
+  return false;
+for (const FunctionEffectWithCondition  : CalleeFX) {
+  // nonblocking/nonallocating cannot call allocating
+  if (CalleeEC.Effect.kind() == Kind::Allocating)
+return false;
+  // nonblocking cannot call blocking
+  if (kind() == Kind::NonBlocking &&
+  CalleeEC.Effect.kind() == Kind::Blocking)
+return false;
+}
+  }
+return true;
+
+  case Kind::Allocating:
+  case Kind::Blocking:
+return false;
+
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+bool FunctionEffect::shouldDiagnoseFunctionCall(
+bool Direct, ArrayRef CalleeFX) const {
+  switch (kind()) {
+  case Kind::NonAllocating:
+  case Kind::NonBlocking: {
+const Kind CallerKind = kind();
+for (const auto  : CalleeFX) {
+  const Kind EK = Effect.kind();
+  // Does callee have same or stronger constraint?
+  if (EK == CallerKind ||
+  (CallerKind == Kind::NonAllocating && EK == Kind::NonBlocking)) {
+return false; // no diagnostic
+  }
+}
+return true; // warning
+  }
+  case Kind::Allocating:
+  case Kind::Blocking:
+return false;
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+// =
+
+void FunctionEffectsRef::Profile(llvm::FoldingSetNodeID ) const {
+  const bool HasConds = !Conditions.empty();
+
+  ID.AddInteger(size() | (HasConds << 31u));
+  for (unsigned Idx = 0, Count = Effects.size(); Idx != Count; ++Idx) {
+ID.AddInteger(Effects[Idx].toOpaqueInt32());
+if (HasConds)
+  ID.AddPointer(Conditions[Idx].expr());
+  }
+}
+
+void FunctionEffectSet::insert(const FunctionEffectWithCondition ,
+   Conflicts ) {
+  const FunctionEffect::Kind NewOppositeKind = NewEC.Effect.oppositeKind();
+
+  // The index at which insertion will take place; default is at end
+  // but we might find an earlier insertion point.
+  unsigned InsertIdx = Effects.size();
+  unsigned Idx = 0;
+  for (const FunctionEffectWithCondition  : *this) {
+if (EC.Effect.kind() == NewEC.Effect.kind()) {
+  if (Conditions[Idx].expr() != NewEC.Cond.expr())
+Errs.push_back({EC, NewEC});
+  return;
+}
+
+if (EC.Effect.kind() == NewOppositeKind) {
+  Errs.push_back({EC, NewEC});
+  return;
+}
+
+if (NewEC.Effect.kind() < EC.Effect.kind() && InsertIdx > Idx)
+  InsertIdx = Idx;
+
+++Idx;
+  }
+
+  if (NewEC.Cond.expr()) {
+if (Conditions.empty() && !Effects.empty())
+  Conditions.resize(Effects.size());
+Conditions.insert(Conditions.begin() + InsertIdx, NewEC.Cond.expr());
+  }
+  Effects.insert(Effects.begin() + InsertIdx, NewEC.Effect);
+}
+
+void FunctionEffectSet::insert(const FunctionEffectsRef , Conflicts ) 
{
+  for (const auto  : Set)
+insert(Item, Errs);
+}
+
+void FunctionEffectSet::insertIgnoringConditions(const FunctionEffectsRef ,
+ Conflicts ) {
+  for (const auto  : Set)
+insert(FunctionEffectWithCondition(Item.Effect, {}), Errs);
+}
+
+void FunctionEffectSet::replaceItem(unsigned Idx,
+const FunctionEffectWithCondition ) {
+  assert(Idx < Conditions.size());
+  Effects[Idx] = Item.Effect;
+  Conditions[Idx] = Item.Cond;
+
+  // Maintain invariant: If all conditions are null, the vector should be 
empty.
+  if (std::all_of(Conditions.begin(), Conditions.end(),

AaronBallman wrote:

```suggestion
  if (llvm::all_of(Conditions,
```

https://github.com/llvm/llvm-project/pull/84983

[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -7963,6 +7968,154 @@ static Attr *getCCTypeAttr(ASTContext , ParsedAttr 
) {
   llvm_unreachable("unexpected attribute kind!");
 }
 
+std::optional
+Sema::ActOnEffectExpression(Expr *CondExpr, StringRef AttributeName) {
+  auto BadExpr = [&]() {
+Diag(CondExpr->getExprLoc(), diag::err_attribute_argument_type)
+<< ("'" + AttributeName.str() + "'") << AANT_ArgumentIntegerConstant
+<< CondExpr->getSourceRange();
+return std::nullopt;
+  };
+
+  if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
+if (CondExpr->containsUnexpandedParameterPack())
+  return BadExpr();
+return FunctionEffectMode::Dependent;
+  }
+
+  std::optional ConditionValue =
+  CondExpr->getIntegerConstantExpr(Context);
+  if (!ConditionValue)
+return BadExpr();
+  return ConditionValue->getExtValue() ? FunctionEffectMode::True
+   : FunctionEffectMode::False;
+}
+
+static bool
+handleNonBlockingNonAllocatingTypeAttr(TypeProcessingState ,
+   ParsedAttr , QualType ,
+   FunctionTypeUnwrapper ) {
+  // Delay if this is not a function type.
+  if (!Unwrapped.isFunctionType())
+return false;
+
+  Sema  = TPState.getSema();
+
+  // Require FunctionProtoType

AaronBallman wrote:

```suggestion
  // Require FunctionProtoType.
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -5028,3 +5060,263 @@ void AutoType::Profile(llvm::FoldingSetNodeID , 
const ASTContext ) {
   Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
   getTypeConstraintConcept(), getTypeConstraintArguments());
 }
+
+FunctionEffect::Kind FunctionEffect::oppositeKind() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return Kind::Blocking;
+  case Kind::Blocking:
+return Kind::NonBlocking;
+  case Kind::NonAllocating:
+return Kind::Allocating;
+  case Kind::Allocating:
+return Kind::NonAllocating;
+  case Kind::None:
+return Kind::None;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+StringRef FunctionEffect::name() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return "nonblocking";
+  case Kind::NonAllocating:
+return "nonallocating";
+  case Kind::Blocking:
+return "blocking";
+  case Kind::Allocating:
+return "allocating";
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+bool FunctionEffect::canInferOnFunction(const Decl ) const {
+  switch (kind()) {
+  case Kind::NonAllocating:
+  case Kind::NonBlocking: {
+FunctionEffectsRef CalleeFX;
+if (auto *FD = Callee.getAsFunction())
+  CalleeFX = FD->getFunctionEffects();
+else if (auto *BD = dyn_cast())
+  CalleeFX = BD->getFunctionEffects();
+else
+  return false;
+for (const FunctionEffectWithCondition  : CalleeFX) {
+  // nonblocking/nonallocating cannot call allocating
+  if (CalleeEC.Effect.kind() == Kind::Allocating)
+return false;
+  // nonblocking cannot call blocking
+  if (kind() == Kind::NonBlocking &&
+  CalleeEC.Effect.kind() == Kind::Blocking)
+return false;
+}
+  }
+return true;
+
+  case Kind::Allocating:
+  case Kind::Blocking:
+return false;
+
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+bool FunctionEffect::shouldDiagnoseFunctionCall(
+bool Direct, ArrayRef CalleeFX) const {
+  switch (kind()) {
+  case Kind::NonAllocating:
+  case Kind::NonBlocking: {
+const Kind CallerKind = kind();
+for (const auto  : CalleeFX) {
+  const Kind EK = Effect.kind();
+  // Does callee have same or stronger constraint?
+  if (EK == CallerKind ||
+  (CallerKind == Kind::NonAllocating && EK == Kind::NonBlocking)) {
+return false; // no diagnostic
+  }
+}
+return true; // warning
+  }
+  case Kind::Allocating:
+  case Kind::Blocking:
+return false;
+  case Kind::None:
+break;

AaronBallman wrote:

`assert`?

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -4639,6 +4645,303 @@ class FunctionNoProtoType : public FunctionType, public 
llvm::FoldingSetNode {
   }
 };
 
+// 
--
+
+/// Represents an abstract function effect, using just an enumeration 
describing
+/// its kind.
+class FunctionEffect {
+public:
+  /// Identifies the particular effect.
+  enum class Kind : uint8_t {
+None = 0,
+NonBlocking = 1,
+NonAllocating = 2,
+Blocking = 3,
+Allocating = 4
+  };
+
+  /// Flags describing some behaviors of the effect.
+  using Flags = unsigned;
+  enum FlagBit : Flags {
+// Can verification inspect callees' implementations? (e.g. nonblocking:
+// yes, tcb+types: no). This also implies the need for 2nd-pass
+// verification.
+FE_InferrableOnCallees = 0x1,
+
+// Language constructs which effects can diagnose as disallowed.
+FE_ExcludeThrow = 0x2,
+FE_ExcludeCatch = 0x4,
+FE_ExcludeObjCMessageSend = 0x8,
+FE_ExcludeStaticLocalVars = 0x10,
+FE_ExcludeThreadLocalVars = 0x20
+  };
+
+private:
+  LLVM_PREFERRED_TYPE(Kind)
+  unsigned FKind : 3;
+
+  // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
+  // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
+  // be considered for uniqueness.
+
+public:
+  FunctionEffect() : FKind(unsigned(Kind::None)) {}
+
+  explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {}
+
+  /// The kind of the effect.
+  Kind kind() const { return Kind(FKind); }
+
+  /// Return the opposite kind, for effects which have opposites.
+  Kind oppositeKind() const;
+
+  /// For serialization.
+  uint32_t toOpaqueInt32() const { return FKind; }
+  static FunctionEffect fromOpaqueInt32(uint32_t Value) {
+return FunctionEffect(Kind(Value));
+  }
+
+  /// Flags describing some behaviors of the effect.
+  Flags flags() const {
+switch (kind()) {
+case Kind::NonBlocking:
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
+ FE_ExcludeThreadLocalVars;
+case Kind::NonAllocating:
+  // Same as NonBlocking, except without FE_ExcludeStaticLocalVars
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
+case Kind::Blocking:
+case Kind::Allocating:
+  return 0;
+case Kind::None:
+  break;
+}
+llvm_unreachable("unknown effect kind");
+  }
+
+  /// The description printed in diagnostics, e.g. 'nonblocking'.
+  StringRef name() const;
+
+  /// Return true if the effect is allowed to be inferred on the callee,
+  /// which is either a FunctionDecl or BlockDecl.
+  /// This is only used if the effect has FE_InferrableOnCallees flag set.
+  /// Example: This allows nonblocking(false) to prevent inference for the
+  /// function.
+  bool canInferOnFunction(const Decl ) const;
+
+  // Return false for success. When true is returned for a direct call, then 
the
+  // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+  // diagnostic. Caller should be assumed to have the effect (it may not have 
it
+  // explicitly when inferring).
+  bool shouldDiagnoseFunctionCall(bool Direct,
+  ArrayRef CalleeFX) const;
+
+  friend bool operator==(const FunctionEffect , const FunctionEffect ) 
{
+return LHS.FKind == RHS.FKind;
+  }
+  friend bool operator!=(const FunctionEffect , const FunctionEffect ) 
{
+return !(LHS == RHS);
+  }
+  friend bool operator<(const FunctionEffect , const FunctionEffect ) {
+return LHS.FKind < RHS.FKind;
+  }
+};
+
+/// Wrap a function effect's condition expression in another struct so
+/// that FunctionProtoType's TrailingObjects can treat it separately.
+class FunctionEffectCondition {
+  Expr *Cond = nullptr; // if null, unconditional
+
+public:
+  FunctionEffectCondition() = default;
+  FunctionEffectCondition(Expr *E) : Cond(E) {} // implicit OK
+
+  Expr *expr() const { return Cond; }
+
+  bool operator==(const FunctionEffectCondition ) const {
+return Cond == RHS.Cond;
+  }
+};
+
+/// A FunctionEffect plus a potential boolean expression determining whether
+/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
+/// expression when present, is dependent.
+struct FunctionEffectWithCondition {
+  FunctionEffect Effect;
+  FunctionEffectCondition Cond;
+
+  FunctionEffectWithCondition() = default;
+  FunctionEffectWithCondition(const FunctionEffect ,
+  const FunctionEffectCondition )
+  : Effect(E), Cond(C) {}
+
+  /// Return a textual description of the effect, and its condition, if any.
+  std::string description() const;
+
+  friend bool operator<(const FunctionEffectWithCondition ,
+const FunctionEffectWithCondition ) {
+if (LHS.Effect < RHS.Effect)
+   

[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -3649,6 +3649,35 @@ FunctionProtoType::FunctionProtoType(QualType result, 
ArrayRef params,
 auto  = *getTrailingObjects();
 EllipsisLoc = epi.EllipsisLoc;
   }
+
+  if (!epi.FunctionEffects.empty()) {
+auto  = *getTrailingObjects();
+const size_t EffectsCount = epi.FunctionEffects.size();

AaronBallman wrote:

```suggestion
size_t EffectsCount = epi.FunctionEffects.size();
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -2743,3 +2759,153 @@ bool Sema::isDeclaratorFunctionLike(Declarator ) {
   });
   return Result;
 }
+
+FunctionEffectDifferences::FunctionEffectDifferences(
+const FunctionEffectsRef , const FunctionEffectsRef ) {
+
+  FunctionEffectsRef::iterator POld = Old.begin();
+  FunctionEffectsRef::iterator OldEnd = Old.end();
+  FunctionEffectsRef::iterator PNew = New.begin();
+  FunctionEffectsRef::iterator NewEnd = New.end();
+
+  while (true) {
+int cmp = 0;
+if (POld == OldEnd) {
+  if (PNew == NewEnd)
+break;
+  cmp = 1;
+} else if (PNew == NewEnd)
+  cmp = -1;
+else {
+  FunctionEffectWithCondition Old = *POld;
+  FunctionEffectWithCondition New = *PNew;
+  if (Old.Effect.kind() < New.Effect.kind())
+cmp = -1;
+  else if (New.Effect.kind() < Old.Effect.kind())
+cmp = 1;
+  else {
+cmp = 0;
+if (Old.Cond.expr() != New.Cond.expr()) {
+  // TODO: Cases where the expressions are equivalent but
+  // don't have the same identity.
+  push_back(FunctionEffectDiff{
+  Old.Effect.kind(), FunctionEffectDiff::Kind::ConditionMismatch,
+  Old, New});
+}
+  }
+}
+
+if (cmp < 0) {
+  // removal
+  FunctionEffectWithCondition Old = *POld;
+  push_back(FunctionEffectDiff{
+  Old.Effect.kind(), FunctionEffectDiff::Kind::Removed, Old, {}});
+  ++POld;
+} else if (cmp > 0) {
+  // addition
+  FunctionEffectWithCondition New = *PNew;
+  push_back(FunctionEffectDiff{
+  New.Effect.kind(), FunctionEffectDiff::Kind::Added, {}, New});
+  ++PNew;
+} else {
+  ++POld;
+  ++PNew;
+}
+  }
+}
+
+bool FunctionEffectDiff::shouldDiagnoseConversion(
+QualType SrcType, const FunctionEffectsRef , QualType DstType,
+const FunctionEffectsRef ) const {
+
+  switch (EffectKind) {
+  case FunctionEffect::Kind::NonAllocating:
+// nonallocating can't be added (spoofed) during a conversion, unless we
+// have nonblocking
+if (DiffKind == Kind::Added) {
+  for (const auto  : SrcFX) {
+if (CFE.Effect.kind() == FunctionEffect::Kind::NonBlocking)
+  return false;
+  }
+}
+[[fallthrough]];
+  case FunctionEffect::Kind::NonBlocking:
+// nonblocking can't be added (spoofed) during a conversion.
+switch (DiffKind) {
+case Kind::Added:
+  return true;
+case Kind::Removed:
+  return false;
+case Kind::ConditionMismatch:
+  // TODO: Condition mismatches are too coarse right now -- expressions

AaronBallman wrote:

```suggestion
  // FIXME: Condition mismatches are too coarse right now -- expressions
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -4639,6 +4645,303 @@ class FunctionNoProtoType : public FunctionType, public 
llvm::FoldingSetNode {
   }
 };
 
+// 
--
+
+/// Represents an abstract function effect, using just an enumeration 
describing
+/// its kind.
+class FunctionEffect {
+public:
+  /// Identifies the particular effect.
+  enum class Kind : uint8_t {
+None = 0,
+NonBlocking = 1,
+NonAllocating = 2,
+Blocking = 3,
+Allocating = 4
+  };
+
+  /// Flags describing some behaviors of the effect.
+  using Flags = unsigned;
+  enum FlagBit : Flags {
+// Can verification inspect callees' implementations? (e.g. nonblocking:
+// yes, tcb+types: no). This also implies the need for 2nd-pass
+// verification.
+FE_InferrableOnCallees = 0x1,
+
+// Language constructs which effects can diagnose as disallowed.
+FE_ExcludeThrow = 0x2,
+FE_ExcludeCatch = 0x4,
+FE_ExcludeObjCMessageSend = 0x8,
+FE_ExcludeStaticLocalVars = 0x10,
+FE_ExcludeThreadLocalVars = 0x20
+  };
+
+private:
+  LLVM_PREFERRED_TYPE(Kind)
+  unsigned FKind : 3;
+
+  // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
+  // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
+  // be considered for uniqueness.
+
+public:
+  FunctionEffect() : FKind(unsigned(Kind::None)) {}
+
+  explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {}
+
+  /// The kind of the effect.
+  Kind kind() const { return Kind(FKind); }
+
+  /// Return the opposite kind, for effects which have opposites.
+  Kind oppositeKind() const;
+
+  /// For serialization.
+  uint32_t toOpaqueInt32() const { return FKind; }
+  static FunctionEffect fromOpaqueInt32(uint32_t Value) {
+return FunctionEffect(Kind(Value));
+  }
+
+  /// Flags describing some behaviors of the effect.
+  Flags flags() const {
+switch (kind()) {
+case Kind::NonBlocking:
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
+ FE_ExcludeThreadLocalVars;
+case Kind::NonAllocating:
+  // Same as NonBlocking, except without FE_ExcludeStaticLocalVars
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
+case Kind::Blocking:
+case Kind::Allocating:
+  return 0;
+case Kind::None:
+  break;
+}
+llvm_unreachable("unknown effect kind");
+  }
+
+  /// The description printed in diagnostics, e.g. 'nonblocking'.
+  StringRef name() const;
+
+  /// Return true if the effect is allowed to be inferred on the callee,
+  /// which is either a FunctionDecl or BlockDecl.
+  /// This is only used if the effect has FE_InferrableOnCallees flag set.
+  /// Example: This allows nonblocking(false) to prevent inference for the
+  /// function.
+  bool canInferOnFunction(const Decl ) const;
+
+  // Return false for success. When true is returned for a direct call, then 
the
+  // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+  // diagnostic. Caller should be assumed to have the effect (it may not have 
it
+  // explicitly when inferring).
+  bool shouldDiagnoseFunctionCall(bool Direct,
+  ArrayRef CalleeFX) const;
+
+  friend bool operator==(const FunctionEffect , const FunctionEffect ) 
{
+return LHS.FKind == RHS.FKind;
+  }
+  friend bool operator!=(const FunctionEffect , const FunctionEffect ) 
{
+return !(LHS == RHS);
+  }
+  friend bool operator<(const FunctionEffect , const FunctionEffect ) {
+return LHS.FKind < RHS.FKind;
+  }
+};
+
+/// Wrap a function effect's condition expression in another struct so
+/// that FunctionProtoType's TrailingObjects can treat it separately.
+class FunctionEffectCondition {
+  Expr *Cond = nullptr; // if null, unconditional
+
+public:
+  FunctionEffectCondition() = default;
+  FunctionEffectCondition(Expr *E) : Cond(E) {} // implicit OK
+
+  Expr *expr() const { return Cond; }
+
+  bool operator==(const FunctionEffectCondition ) const {
+return Cond == RHS.Cond;
+  }
+};
+
+/// A FunctionEffect plus a potential boolean expression determining whether
+/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
+/// expression when present, is dependent.
+struct FunctionEffectWithCondition {
+  FunctionEffect Effect;
+  FunctionEffectCondition Cond;
+
+  FunctionEffectWithCondition() = default;
+  FunctionEffectWithCondition(const FunctionEffect ,
+  const FunctionEffectCondition )
+  : Effect(E), Cond(C) {}
+
+  /// Return a textual description of the effect, and its condition, if any.
+  std::string description() const;
+
+  friend bool operator<(const FunctionEffectWithCondition ,
+const FunctionEffectWithCondition ) {
+if (LHS.Effect < RHS.Effect)
+   

[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -0,0 +1,134 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -x c -std=c23 %s
+
+#if !__has_attribute(clang_nonblocking)
+#error "the 'nonblocking' attribute is not available"
+#endif
+
+// --- ATTRIBUTE SYNTAX: SUBJECTS ---
+
+int nl_var [[clang::nonblocking]]; // expected-warning {{'nonblocking' only 
applies to function types; type here is 'int'}}
+struct nl_struct {} [[clang::nonblocking]]; // expected-warning {{attribute 
'nonblocking' is ignored, place it after "struct" to apply attribute to type 
declaration}}
+struct [[clang::nonblocking]] nl_struct2 {}; // expected-error {{'nonblocking' 
attribute cannot be applied to a declaration}}

AaronBallman wrote:

Might as well test some positive situations as well:
```
typedef void (*fo)() [[clang::nonblocking]];
void (*why_is_aaron_this_way(int val, void (*func)(int) 
[[clang::nonblocking]])[[clang::nonblocking]])(int)[[clang::nonblocking]];
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -4669,6 +4679,13 @@ class BlockDecl : public Decl, public DeclContext {
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
+  FunctionEffectsRef getFunctionEffects() const {
+if (TypeSourceInfo *TSI = getSignatureAsWritten())
+  if (auto *FPT = TSI->getType()->getAs())

AaronBallman wrote:

```suggestion
if (const TypeSourceInfo *TSI = getSignatureAsWritten())
  if (const auto *FPT = TSI->getType()->getAs())
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -2743,3 +2759,153 @@ bool Sema::isDeclaratorFunctionLike(Declarator ) {
   });
   return Result;
 }
+
+FunctionEffectDifferences::FunctionEffectDifferences(
+const FunctionEffectsRef , const FunctionEffectsRef ) {
+
+  FunctionEffectsRef::iterator POld = Old.begin();
+  FunctionEffectsRef::iterator OldEnd = Old.end();
+  FunctionEffectsRef::iterator PNew = New.begin();
+  FunctionEffectsRef::iterator NewEnd = New.end();
+
+  while (true) {
+int cmp = 0;
+if (POld == OldEnd) {
+  if (PNew == NewEnd)
+break;
+  cmp = 1;
+} else if (PNew == NewEnd)
+  cmp = -1;
+else {
+  FunctionEffectWithCondition Old = *POld;
+  FunctionEffectWithCondition New = *PNew;
+  if (Old.Effect.kind() < New.Effect.kind())
+cmp = -1;
+  else if (New.Effect.kind() < Old.Effect.kind())
+cmp = 1;
+  else {
+cmp = 0;
+if (Old.Cond.expr() != New.Cond.expr()) {
+  // TODO: Cases where the expressions are equivalent but
+  // don't have the same identity.
+  push_back(FunctionEffectDiff{
+  Old.Effect.kind(), FunctionEffectDiff::Kind::ConditionMismatch,
+  Old, New});
+}
+  }
+}
+
+if (cmp < 0) {
+  // removal
+  FunctionEffectWithCondition Old = *POld;
+  push_back(FunctionEffectDiff{
+  Old.Effect.kind(), FunctionEffectDiff::Kind::Removed, Old, {}});
+  ++POld;
+} else if (cmp > 0) {
+  // addition
+  FunctionEffectWithCondition New = *PNew;
+  push_back(FunctionEffectDiff{
+  New.Effect.kind(), FunctionEffectDiff::Kind::Added, {}, New});
+  ++PNew;
+} else {
+  ++POld;
+  ++PNew;
+}
+  }
+}
+
+bool FunctionEffectDiff::shouldDiagnoseConversion(
+QualType SrcType, const FunctionEffectsRef , QualType DstType,
+const FunctionEffectsRef ) const {
+
+  switch (EffectKind) {
+  case FunctionEffect::Kind::NonAllocating:
+// nonallocating can't be added (spoofed) during a conversion, unless we
+// have nonblocking
+if (DiffKind == Kind::Added) {
+  for (const auto  : SrcFX) {
+if (CFE.Effect.kind() == FunctionEffect::Kind::NonBlocking)
+  return false;
+  }
+}
+[[fallthrough]];
+  case FunctionEffect::Kind::NonBlocking:
+// nonblocking can't be added (spoofed) during a conversion.
+switch (DiffKind) {
+case Kind::Added:
+  return true;
+case Kind::Removed:
+  return false;
+case Kind::ConditionMismatch:
+  // TODO: Condition mismatches are too coarse right now -- expressions
+  // which are equivalent but don't have the same identity are detected as
+  // mismatches. We're going to diagnose those anyhow until expression
+  // matching is better.
+  return true;
+}
+  case FunctionEffect::Kind::Blocking:
+  case FunctionEffect::Kind::Allocating:
+return false;
+  case FunctionEffect::Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+bool FunctionEffectDiff::shouldDiagnoseRedeclaration(
+const FunctionDecl , const FunctionEffectsRef ,
+const FunctionDecl , const FunctionEffectsRef ) const {
+  switch (EffectKind) {
+  case FunctionEffect::Kind::NonAllocating:
+  case FunctionEffect::Kind::NonBlocking:
+// nonblocking/nonallocating can't be removed in a redeclaration
+switch (DiffKind) {
+case Kind::Added:
+  return false; // No diagnostic.
+case Kind::Removed:
+  return true; // Issue diagnostic

AaronBallman wrote:

```suggestion
  return true; // Issue diagnostic.
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -1870,6 +1870,27 @@ bool Sema::IsFunctionConversion(QualType FromType, 
QualType ToType,
   FromFn = QT->getAs();
   Changed = true;
 }
+
+// For C, when called from checkPointerTypesForAssignment,
+// we need not to alter FromFn, or else even an innocuous cast

AaronBallman wrote:

```suggestion
// we need to not alter FromFn, or else even an innocuous cast
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -4639,6 +4645,303 @@ class FunctionNoProtoType : public FunctionType, public 
llvm::FoldingSetNode {
   }
 };
 
+// 
--
+
+/// Represents an abstract function effect, using just an enumeration 
describing
+/// its kind.
+class FunctionEffect {
+public:
+  /// Identifies the particular effect.
+  enum class Kind : uint8_t {
+None = 0,
+NonBlocking = 1,
+NonAllocating = 2,
+Blocking = 3,
+Allocating = 4
+  };
+
+  /// Flags describing some behaviors of the effect.
+  using Flags = unsigned;
+  enum FlagBit : Flags {
+// Can verification inspect callees' implementations? (e.g. nonblocking:
+// yes, tcb+types: no). This also implies the need for 2nd-pass
+// verification.
+FE_InferrableOnCallees = 0x1,
+
+// Language constructs which effects can diagnose as disallowed.
+FE_ExcludeThrow = 0x2,
+FE_ExcludeCatch = 0x4,
+FE_ExcludeObjCMessageSend = 0x8,
+FE_ExcludeStaticLocalVars = 0x10,
+FE_ExcludeThreadLocalVars = 0x20
+  };
+
+private:
+  LLVM_PREFERRED_TYPE(Kind)
+  unsigned FKind : 3;
+
+  // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
+  // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
+  // be considered for uniqueness.
+
+public:
+  FunctionEffect() : FKind(unsigned(Kind::None)) {}
+
+  explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {}
+
+  /// The kind of the effect.
+  Kind kind() const { return Kind(FKind); }
+
+  /// Return the opposite kind, for effects which have opposites.
+  Kind oppositeKind() const;
+
+  /// For serialization.
+  uint32_t toOpaqueInt32() const { return FKind; }
+  static FunctionEffect fromOpaqueInt32(uint32_t Value) {
+return FunctionEffect(Kind(Value));
+  }
+
+  /// Flags describing some behaviors of the effect.
+  Flags flags() const {
+switch (kind()) {
+case Kind::NonBlocking:
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
+ FE_ExcludeThreadLocalVars;
+case Kind::NonAllocating:
+  // Same as NonBlocking, except without FE_ExcludeStaticLocalVars
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
+case Kind::Blocking:
+case Kind::Allocating:
+  return 0;
+case Kind::None:
+  break;
+}
+llvm_unreachable("unknown effect kind");
+  }
+
+  /// The description printed in diagnostics, e.g. 'nonblocking'.
+  StringRef name() const;
+
+  /// Return true if the effect is allowed to be inferred on the callee,
+  /// which is either a FunctionDecl or BlockDecl.
+  /// This is only used if the effect has FE_InferrableOnCallees flag set.
+  /// Example: This allows nonblocking(false) to prevent inference for the
+  /// function.
+  bool canInferOnFunction(const Decl ) const;
+
+  // Return false for success. When true is returned for a direct call, then 
the
+  // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+  // diagnostic. Caller should be assumed to have the effect (it may not have 
it
+  // explicitly when inferring).
+  bool shouldDiagnoseFunctionCall(bool Direct,
+  ArrayRef CalleeFX) const;
+
+  friend bool operator==(const FunctionEffect , const FunctionEffect ) 
{
+return LHS.FKind == RHS.FKind;
+  }
+  friend bool operator!=(const FunctionEffect , const FunctionEffect ) 
{
+return !(LHS == RHS);
+  }
+  friend bool operator<(const FunctionEffect , const FunctionEffect ) {
+return LHS.FKind < RHS.FKind;
+  }
+};
+
+/// Wrap a function effect's condition expression in another struct so
+/// that FunctionProtoType's TrailingObjects can treat it separately.
+class FunctionEffectCondition {
+  Expr *Cond = nullptr; // if null, unconditional
+
+public:
+  FunctionEffectCondition() = default;
+  FunctionEffectCondition(Expr *E) : Cond(E) {} // implicit OK
+
+  Expr *expr() const { return Cond; }
+
+  bool operator==(const FunctionEffectCondition ) const {
+return Cond == RHS.Cond;
+  }
+};
+
+/// A FunctionEffect plus a potential boolean expression determining whether
+/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
+/// expression when present, is dependent.
+struct FunctionEffectWithCondition {
+  FunctionEffect Effect;
+  FunctionEffectCondition Cond;
+
+  FunctionEffectWithCondition() = default;
+  FunctionEffectWithCondition(const FunctionEffect ,
+  const FunctionEffectCondition )
+  : Effect(E), Cond(C) {}
+
+  /// Return a textual description of the effect, and its condition, if any.
+  std::string description() const;
+
+  friend bool operator<(const FunctionEffectWithCondition ,
+const FunctionEffectWithCondition ) {
+if (LHS.Effect < RHS.Effect)
+   

[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -1870,6 +1870,28 @@ bool Sema::IsFunctionConversion(QualType FromType, 
QualType ToType,
   FromFn = QT->getAs();
   Changed = true;
 }
+
+// For C, when called from checkPointerTypesForAssignment,
+// we need not to alter FromFn, or else even an innocuous cast
+// like dropping effects will fail. In C++ however we do want to
+// alter FromFn. TODO: Is this correct?

AaronBallman wrote:

I think I'm a bit surprised that `IsFunctionConversion()` would need this logic 
as opposed to `MergeFunctionDecl()` handling it.  Testing whether something is 
a function conversion doesn't seem like a time when we know we need to add or 
drop effects, it's only after we've decided to do something about the function 
conversion that would need that, right?

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -x c -std=c11 %s

AaronBallman wrote:

```suggestion
// RUN: %clang_cc1 -fsyntax-only -verify -std=c89 %s
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -5028,3 +5060,263 @@ void AutoType::Profile(llvm::FoldingSetNodeID , 
const ASTContext ) {
   Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
   getTypeConstraintConcept(), getTypeConstraintArguments());
 }
+
+FunctionEffect::Kind FunctionEffect::oppositeKind() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return Kind::Blocking;
+  case Kind::Blocking:
+return Kind::NonBlocking;
+  case Kind::NonAllocating:
+return Kind::Allocating;
+  case Kind::Allocating:
+return Kind::NonAllocating;
+  case Kind::None:
+return Kind::None;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+StringRef FunctionEffect::name() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return "nonblocking";
+  case Kind::NonAllocating:
+return "nonallocating";
+  case Kind::Blocking:
+return "blocking";
+  case Kind::Allocating:
+return "allocating";
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+bool FunctionEffect::canInferOnFunction(const Decl ) const {
+  switch (kind()) {
+  case Kind::NonAllocating:
+  case Kind::NonBlocking: {
+FunctionEffectsRef CalleeFX;
+if (auto *FD = Callee.getAsFunction())
+  CalleeFX = FD->getFunctionEffects();
+else if (auto *BD = dyn_cast())
+  CalleeFX = BD->getFunctionEffects();
+else
+  return false;
+for (const FunctionEffectWithCondition  : CalleeFX) {
+  // nonblocking/nonallocating cannot call allocating
+  if (CalleeEC.Effect.kind() == Kind::Allocating)
+return false;
+  // nonblocking cannot call blocking
+  if (kind() == Kind::NonBlocking &&
+  CalleeEC.Effect.kind() == Kind::Blocking)
+return false;
+}
+  }
+return true;
+
+  case Kind::Allocating:
+  case Kind::Blocking:
+return false;
+
+  case Kind::None:
+break;

AaronBallman wrote:

Should we `assert` here rather than falling into the unreachable?

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -4639,6 +4645,303 @@ class FunctionNoProtoType : public FunctionType, public 
llvm::FoldingSetNode {
   }
 };
 
+// 
--
+
+/// Represents an abstract function effect, using just an enumeration 
describing
+/// its kind.
+class FunctionEffect {
+public:
+  /// Identifies the particular effect.
+  enum class Kind : uint8_t {
+None = 0,
+NonBlocking = 1,
+NonAllocating = 2,
+Blocking = 3,
+Allocating = 4
+  };
+
+  /// Flags describing some behaviors of the effect.
+  using Flags = unsigned;
+  enum FlagBit : Flags {
+// Can verification inspect callees' implementations? (e.g. nonblocking:
+// yes, tcb+types: no). This also implies the need for 2nd-pass
+// verification.
+FE_InferrableOnCallees = 0x1,
+
+// Language constructs which effects can diagnose as disallowed.
+FE_ExcludeThrow = 0x2,
+FE_ExcludeCatch = 0x4,
+FE_ExcludeObjCMessageSend = 0x8,
+FE_ExcludeStaticLocalVars = 0x10,
+FE_ExcludeThreadLocalVars = 0x20
+  };
+
+private:
+  LLVM_PREFERRED_TYPE(Kind)
+  unsigned FKind : 3;
+
+  // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
+  // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
+  // be considered for uniqueness.
+
+public:
+  FunctionEffect() : FKind(unsigned(Kind::None)) {}
+
+  explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {}
+
+  /// The kind of the effect.
+  Kind kind() const { return Kind(FKind); }
+
+  /// Return the opposite kind, for effects which have opposites.
+  Kind oppositeKind() const;
+
+  /// For serialization.
+  uint32_t toOpaqueInt32() const { return FKind; }
+  static FunctionEffect fromOpaqueInt32(uint32_t Value) {
+return FunctionEffect(Kind(Value));
+  }
+
+  /// Flags describing some behaviors of the effect.
+  Flags flags() const {
+switch (kind()) {
+case Kind::NonBlocking:
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
+ FE_ExcludeThreadLocalVars;
+case Kind::NonAllocating:
+  // Same as NonBlocking, except without FE_ExcludeStaticLocalVars
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
+case Kind::Blocking:
+case Kind::Allocating:
+  return 0;
+case Kind::None:
+  break;
+}
+llvm_unreachable("unknown effect kind");
+  }
+
+  /// The description printed in diagnostics, e.g. 'nonblocking'.
+  StringRef name() const;
+
+  /// Return true if the effect is allowed to be inferred on the callee,
+  /// which is either a FunctionDecl or BlockDecl.
+  /// This is only used if the effect has FE_InferrableOnCallees flag set.
+  /// Example: This allows nonblocking(false) to prevent inference for the
+  /// function.
+  bool canInferOnFunction(const Decl ) const;
+
+  // Return false for success. When true is returned for a direct call, then 
the
+  // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+  // diagnostic. Caller should be assumed to have the effect (it may not have 
it
+  // explicitly when inferring).
+  bool shouldDiagnoseFunctionCall(bool Direct,
+  ArrayRef CalleeFX) const;
+
+  friend bool operator==(const FunctionEffect , const FunctionEffect ) 
{
+return LHS.FKind == RHS.FKind;
+  }
+  friend bool operator!=(const FunctionEffect , const FunctionEffect ) 
{
+return !(LHS == RHS);
+  }
+  friend bool operator<(const FunctionEffect , const FunctionEffect ) {
+return LHS.FKind < RHS.FKind;
+  }
+};
+
+/// Wrap a function effect's condition expression in another struct so
+/// that FunctionProtoType's TrailingObjects can treat it separately.
+class FunctionEffectCondition {
+  Expr *Cond = nullptr; // if null, unconditional
+
+public:
+  FunctionEffectCondition() = default;
+  FunctionEffectCondition(Expr *E) : Cond(E) {} // implicit OK
+
+  Expr *expr() const { return Cond; }
+
+  bool operator==(const FunctionEffectCondition ) const {
+return Cond == RHS.Cond;
+  }
+};
+
+/// A FunctionEffect plus a potential boolean expression determining whether
+/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
+/// expression when present, is dependent.
+struct FunctionEffectWithCondition {
+  FunctionEffect Effect;
+  FunctionEffectCondition Cond;
+
+  FunctionEffectWithCondition() = default;
+  FunctionEffectWithCondition(const FunctionEffect ,
+  const FunctionEffectCondition )
+  : Effect(E), Cond(C) {}
+
+  /// Return a textual description of the effect, and its condition, if any.
+  std::string description() const;
+
+  friend bool operator<(const FunctionEffectWithCondition ,
+const FunctionEffectWithCondition ) {
+if (LHS.Effect < RHS.Effect)
+   

[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -5028,3 +5060,263 @@ void AutoType::Profile(llvm::FoldingSetNodeID , 
const ASTContext ) {
   Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
   getTypeConstraintConcept(), getTypeConstraintArguments());
 }
+
+FunctionEffect::Kind FunctionEffect::oppositeKind() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return Kind::Blocking;
+  case Kind::Blocking:
+return Kind::NonBlocking;
+  case Kind::NonAllocating:
+return Kind::Allocating;
+  case Kind::Allocating:
+return Kind::NonAllocating;
+  case Kind::None:
+return Kind::None;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+StringRef FunctionEffect::name() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return "nonblocking";
+  case Kind::NonAllocating:
+return "nonallocating";
+  case Kind::Blocking:
+return "blocking";
+  case Kind::Allocating:
+return "allocating";
+  case Kind::None:
+break;

AaronBallman wrote:

this will fall into the unreachable below, making it reachable -- should this 
return `"none"` or `""`? (I'm thinking about folks calling the function from a 
debugger while trying to debug issues as a use case.)

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -5028,3 +5060,263 @@ void AutoType::Profile(llvm::FoldingSetNodeID , 
const ASTContext ) {
   Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
   getTypeConstraintConcept(), getTypeConstraintArguments());
 }
+
+FunctionEffect::Kind FunctionEffect::oppositeKind() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return Kind::Blocking;
+  case Kind::Blocking:
+return Kind::NonBlocking;
+  case Kind::NonAllocating:
+return Kind::Allocating;
+  case Kind::Allocating:
+return Kind::NonAllocating;
+  case Kind::None:
+return Kind::None;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+StringRef FunctionEffect::name() const {
+  switch (kind()) {
+  case Kind::NonBlocking:
+return "nonblocking";
+  case Kind::NonAllocating:
+return "nonallocating";
+  case Kind::Blocking:
+return "blocking";
+  case Kind::Allocating:
+return "allocating";
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+bool FunctionEffect::canInferOnFunction(const Decl ) const {
+  switch (kind()) {
+  case Kind::NonAllocating:
+  case Kind::NonBlocking: {
+FunctionEffectsRef CalleeFX;
+if (auto *FD = Callee.getAsFunction())
+  CalleeFX = FD->getFunctionEffects();
+else if (auto *BD = dyn_cast())
+  CalleeFX = BD->getFunctionEffects();
+else
+  return false;
+for (const FunctionEffectWithCondition  : CalleeFX) {
+  // nonblocking/nonallocating cannot call allocating
+  if (CalleeEC.Effect.kind() == Kind::Allocating)
+return false;
+  // nonblocking cannot call blocking
+  if (kind() == Kind::NonBlocking &&
+  CalleeEC.Effect.kind() == Kind::Blocking)
+return false;
+}
+  }
+return true;
+
+  case Kind::Allocating:
+  case Kind::Blocking:
+return false;
+
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+bool FunctionEffect::shouldDiagnoseFunctionCall(
+bool Direct, ArrayRef CalleeFX) const {
+  switch (kind()) {
+  case Kind::NonAllocating:
+  case Kind::NonBlocking: {
+const Kind CallerKind = kind();
+for (const auto  : CalleeFX) {
+  const Kind EK = Effect.kind();
+  // Does callee have same or stronger constraint?
+  if (EK == CallerKind ||
+  (CallerKind == Kind::NonAllocating && EK == Kind::NonBlocking)) {
+return false; // no diagnostic
+  }
+}
+return true; // warning
+  }
+  case Kind::Allocating:
+  case Kind::Blocking:
+return false;
+  case Kind::None:
+break;
+  }
+  llvm_unreachable("unknown effect kind");
+}
+
+// =
+
+void FunctionEffectsRef::Profile(llvm::FoldingSetNodeID ) const {
+  const bool HasConds = !Conditions.empty();
+
+  ID.AddInteger(size() | (HasConds << 31u));
+  for (unsigned Idx = 0, Count = Effects.size(); Idx != Count; ++Idx) {
+ID.AddInteger(Effects[Idx].toOpaqueInt32());
+if (HasConds)
+  ID.AddPointer(Conditions[Idx].expr());
+  }
+}
+
+void FunctionEffectSet::insert(const FunctionEffectWithCondition ,
+   Conflicts ) {
+  const FunctionEffect::Kind NewOppositeKind = NewEC.Effect.oppositeKind();

AaronBallman wrote:

```suggestion
  FunctionEffect::Kind NewOppositeKind = NewEC.Effect.oppositeKind();
```

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -4639,6 +4645,303 @@ class FunctionNoProtoType : public FunctionType, public 
llvm::FoldingSetNode {
   }
 };
 
+// 
--
+
+/// Represents an abstract function effect, using just an enumeration 
describing
+/// its kind.
+class FunctionEffect {
+public:
+  /// Identifies the particular effect.
+  enum class Kind : uint8_t {
+None = 0,
+NonBlocking = 1,
+NonAllocating = 2,
+Blocking = 3,
+Allocating = 4
+  };
+
+  /// Flags describing some behaviors of the effect.
+  using Flags = unsigned;
+  enum FlagBit : Flags {
+// Can verification inspect callees' implementations? (e.g. nonblocking:
+// yes, tcb+types: no). This also implies the need for 2nd-pass
+// verification.
+FE_InferrableOnCallees = 0x1,
+
+// Language constructs which effects can diagnose as disallowed.
+FE_ExcludeThrow = 0x2,
+FE_ExcludeCatch = 0x4,
+FE_ExcludeObjCMessageSend = 0x8,
+FE_ExcludeStaticLocalVars = 0x10,
+FE_ExcludeThreadLocalVars = 0x20
+  };
+
+private:
+  LLVM_PREFERRED_TYPE(Kind)
+  unsigned FKind : 3;
+
+  // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
+  // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
+  // be considered for uniqueness.
+
+public:
+  FunctionEffect() : FKind(unsigned(Kind::None)) {}
+
+  explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {}
+
+  /// The kind of the effect.
+  Kind kind() const { return Kind(FKind); }
+
+  /// Return the opposite kind, for effects which have opposites.
+  Kind oppositeKind() const;
+
+  /// For serialization.
+  uint32_t toOpaqueInt32() const { return FKind; }
+  static FunctionEffect fromOpaqueInt32(uint32_t Value) {
+return FunctionEffect(Kind(Value));
+  }
+
+  /// Flags describing some behaviors of the effect.
+  Flags flags() const {
+switch (kind()) {
+case Kind::NonBlocking:
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
+ FE_ExcludeThreadLocalVars;
+case Kind::NonAllocating:
+  // Same as NonBlocking, except without FE_ExcludeStaticLocalVars
+  return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
+case Kind::Blocking:
+case Kind::Allocating:
+  return 0;
+case Kind::None:
+  break;
+}
+llvm_unreachable("unknown effect kind");
+  }
+
+  /// The description printed in diagnostics, e.g. 'nonblocking'.
+  StringRef name() const;
+
+  /// Return true if the effect is allowed to be inferred on the callee,
+  /// which is either a FunctionDecl or BlockDecl.
+  /// This is only used if the effect has FE_InferrableOnCallees flag set.
+  /// Example: This allows nonblocking(false) to prevent inference for the
+  /// function.
+  bool canInferOnFunction(const Decl ) const;
+
+  // Return false for success. When true is returned for a direct call, then 
the
+  // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+  // diagnostic. Caller should be assumed to have the effect (it may not have 
it
+  // explicitly when inferring).
+  bool shouldDiagnoseFunctionCall(bool Direct,
+  ArrayRef CalleeFX) const;
+
+  friend bool operator==(const FunctionEffect , const FunctionEffect ) 
{
+return LHS.FKind == RHS.FKind;
+  }
+  friend bool operator!=(const FunctionEffect , const FunctionEffect ) 
{
+return !(LHS == RHS);
+  }
+  friend bool operator<(const FunctionEffect , const FunctionEffect ) {
+return LHS.FKind < RHS.FKind;
+  }
+};
+
+/// Wrap a function effect's condition expression in another struct so
+/// that FunctionProtoType's TrailingObjects can treat it separately.
+class FunctionEffectCondition {
+  Expr *Cond = nullptr; // if null, unconditional
+
+public:
+  FunctionEffectCondition() = default;
+  FunctionEffectCondition(Expr *E) : Cond(E) {} // implicit OK
+
+  Expr *expr() const { return Cond; }
+
+  bool operator==(const FunctionEffectCondition ) const {
+return Cond == RHS.Cond;
+  }
+};
+
+/// A FunctionEffect plus a potential boolean expression determining whether
+/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
+/// expression when present, is dependent.
+struct FunctionEffectWithCondition {
+  FunctionEffect Effect;
+  FunctionEffectCondition Cond;
+
+  FunctionEffectWithCondition() = default;
+  FunctionEffectWithCondition(const FunctionEffect ,
+  const FunctionEffectCondition )
+  : Effect(E), Cond(C) {}
+
+  /// Return a textual description of the effect, and its condition, if any.
+  std::string description() const;
+
+  friend bool operator<(const FunctionEffectWithCondition ,
+const FunctionEffectWithCondition ) {
+if (LHS.Effect < RHS.Effect)
+   

[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -1435,6 +1435,38 @@ def CXX11NoReturn : InheritableAttr {
   let Documentation = [CXX11NoReturnDocs];
 }
 
+def NonBlocking : TypeAttr {
+  let Spellings = [CXX11<"clang", "nonblocking">,

AaronBallman wrote:

Generally speaking, these would use the `Clang` spelling instead of three 
distinct spellings; is there a reason we need the GNU spelling to be prefixed 
with `clang_`?

https://github.com/llvm/llvm-project/pull/84983
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Use constant rounding mode for floating literals (PR #90877)

2024-05-16 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

The changes should come with a release note so that users know about the 
behavioral change, but otherwise LGTM.

https://github.com/llvm/llvm-project/pull/90877
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [C++23] [CLANG] Adding C++23 constexpr math functions: fmin, fmax and frexp. (PR #88978)

2024-05-16 Thread Aaron Ballman via cfe-commits


@@ -14574,9 +14574,17 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr 
*E) {
   default:
 return false;
 
+  case Builtin::BI__builtin_frexpl:
+// AIX library function `frexpl` has 'long double' type and not
+// PPCDoubleDouble type. To make sure we generate the right value, don't
+// constant evaluate it and instead defer to a libcall.
+if (Info.Ctx.getTargetInfo().getTriple().isPPC() &&
+(().getLongDoubleFormat() !=
+ ::APFloat::PPCDoubleDouble()))
+  return false;
+LLVM_FALLTHROUGH;
   case Builtin::BI__builtin_frexp:
-  case Builtin::BI__builtin_frexpf:
-  case Builtin::BI__builtin_frexpl: {
+  case Builtin::BI__builtin_frexpf: {

AaronBallman wrote:

> For compile-time evaluation, the APFloats associated with long double on AIX 
> have the IEEE double format (and the evaluation works fine).

Does the evaluation produce the same results as would happen at runtime despite 
the different format?

https://github.com/llvm/llvm-project/pull/88978
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CWG2428 "Deprecating a concept" (PR #92295)

2024-05-15 Thread Aaron Ballman via cfe-commits


@@ -10698,7 +10698,7 @@ C++ defect report implementation 
status
 https://cplusplus.github.io/CWG/issues/1815.html;>1815
 CD4
 Lifetime extension in aggregate initialization
-Clang 19
+Yes

AaronBallman wrote:

It's usually better to apply the unrelated changes to the tree first, then base 
the patch on top of that; this way reviewers don't see unrelated changes in the 
patch.

https://github.com/llvm/llvm-project/pull/92295
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CWG2428 "Deprecating a concept" (PR #92295)

2024-05-15 Thread Aaron Ballman via cfe-commits


@@ -45,6 +45,34 @@ void fallthrough(int n) {
 #endif
 }
 
+namespace cwg2428 { // cwg2428: 19
+#if __cplusplus >= 202002L
+template 
+concept C [[deprecated]] = true; // #C

AaronBallman wrote:

I'd like an additional test for rejecting:
```
template 
[[deprecated]] concept C = true;
```
which isn't allowed per the grammar (though I find this slightly surprising and 
it may be an oversight from WG21).

It would also be good to have a test explicitly showing that we reject 
non-C++-style attributes.

https://github.com/llvm/llvm-project/pull/92295
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CWG2428 "Deprecating a concept" (PR #92295)

2024-05-15 Thread Aaron Ballman via cfe-commits


@@ -10698,7 +10698,7 @@ C++ defect report implementation 
status
 https://cplusplus.github.io/CWG/issues/1815.html;>1815
 CD4
 Lifetime extension in aggregate initialization
-Clang 19
+Yes

AaronBallman wrote:

Unrelated changes snuck in.

https://github.com/llvm/llvm-project/pull/92295
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CWG2428 "Deprecating a concept" (PR #92295)

2024-05-15 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman commented:

Please be sure to add a release note about implementing the DR.

https://github.com/llvm/llvm-project/pull/92295
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CWG2428 "Deprecating a concept" (PR #92295)

2024-05-15 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/92295
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Warn consecutive builtin comparisons in an expression (PR #92200)

2024-05-15 Thread Aaron Ballman via cfe-commits


@@ -215,3 +215,10 @@ namespace PR20735 {
 // fix-it:"{{.*}}":{[[@LINE-9]]:20-[[@LINE-9]]:20}:")"
   }
 }
+
+void consecutive_builtin_compare(int x, int y, int z) {
+  (void)(x < y < z);  // expected-warning {{comparisons like 'X<=Y<=Z' don't 
have their mathematical meaning}}
+  (void)(x < y > z);  // expected-warning {{comparisons like 'X<=Y<=Z' don't 
have their mathematical meaning}}
+  (void)(x < y <= z); // expected-warning {{comparisons like 'X<=Y<=Z' don't 
have their mathematical meaning}}
+  (void)(x <= y > z); // expected-warning {{comparisons like 'X<=Y<=Z' don't 
have their mathematical meaning}}

AaronBallman wrote:

I'd like an additional test along the lines of:
```
(void)((x < y) >= z);
```
and what about something along these lines?
```
struct S {
  bool operator<(const S &) const;
} s, t;

(void)(s < t >= z);
```
perhaps that should diagnose while this should not?
```
struct S {
  S operator<(const S &) const;
} a, b;

struct T {
  friend bool operator>=(const S &, const T &);
} c;

bool val = (a < b >= c);
```

https://github.com/llvm/llvm-project/pull/92200
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Warn consecutive builtin comparisons in an expression (PR #92200)

2024-05-15 Thread Aaron Ballman via cfe-commits


@@ -14878,6 +14878,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation 
OpLoc,
   case BO_GT:
 ConvertHalfVec = true;
 ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc);
+
+if (const auto *BI = dyn_cast(LHSExpr))
+  if (BI->isComparisonOp())
+Diag(OpLoc, diag::warn_consecutive_comparison);
+

AaronBallman wrote:

```suggestion
if (const auto *BI = dyn_cast(LHSExpr); BI && 
BI->isComparisonOp())
  Diag(OpLoc, diag::warn_consecutive_comparison);

```

https://github.com/llvm/llvm-project/pull/92200
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix __is_array returning true for zero-sized arrays (PR #86652)

2024-05-15 Thread Aaron Ballman via cfe-commits


@@ -5143,6 +5143,10 @@ static bool EvaluateUnaryTypeTrait(Sema , TypeTrait 
UTT,
   case UTT_IsFloatingPoint:
 return T->isFloatingType();
   case UTT_IsArray:
+// zero-sized arrays aren't considered arrays in partial specializations,

AaronBallman wrote:

```suggestion
// Zero-sized arrays aren't considered arrays in partial specializations,
```

https://github.com/llvm/llvm-project/pull/86652
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix __is_array returning true for zero-sized arrays (PR #86652)

2024-05-15 Thread Aaron Ballman via cfe-commits


@@ -5143,6 +5143,10 @@ static bool EvaluateUnaryTypeTrait(Sema , TypeTrait 
UTT,
   case UTT_IsFloatingPoint:
 return T->isFloatingType();
   case UTT_IsArray:
+// zero-sized arrays aren't considered arrays in partial specializations,
+// so __is_array shouldn't consider them arrays either.
+if (const auto* CAT = C.getAsConstantArrayType(T))

AaronBallman wrote:

```suggestion
if (const auto *CAT = C.getAsConstantArrayType(T))
```

https://github.com/llvm/llvm-project/pull/86652
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix __is_array returning true for zero-sized arrays (PR #86652)

2024-05-15 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/86652
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix __is_array returning true for zero-sized arrays (PR #86652)

2024-05-15 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

Realistically, I don't think we can deprecate the extension in general:
https://sourcegraph.com/search?q=context:global+%5BA-Za-z0-9_%5D%2B%5Cs%5BA-Za-z0-9_%5D%2B%5C%5B0%5C%5D%3B+-file:.*test.*+-file:.*clang.*+count:10=regexp=0

I don't think we can even deprecate it for just C++:
https://sourcegraph.com/search?q=context:global+%5BA-Za-z0-9_%5D%2B%5Cs%5BA-Za-z0-9_%5D%2B%5C%5B0%5C%5D%3B+-file:.*test.*+-file:.*clang.*+count:10+lang:C%2B%2B+=regexp=0

but we might be able to deprecate it for uses where the zero-sized array is not 
the last member of a structure declaration:
https://sourcegraph.com/search?q=context:global+%5BA-Za-z0-9_%5D%2B%5Cs%5BA-Za-z0-9_%5D%2B%5C%5B0%5C%5D%3B%5Cs*%5BA-Za-z_%5D+-file:.*test.*+-file:.*clang.*+lang:C+count:10=regexp=0
 (has a lot of false positives like `sizeof foo[0];` and `return foo[0];`)

I think we should consider deprecation orthogonal to this patch though.

There does not seem to be evidence that this is being used for anything other 
than implementing traits: 
https://sourcegraph.com/search?q=context:global+__is_array%5Cb+lang:C%2B%2B+-file:.*test.*+-file:.*clang.*+-file:.*libcxx.*+-file:.*libc%5C%2B%5C%2B.*+-file:.*trait.*+-repo:.*clang.*=regexp=0

so I think the patch is "correct" insofar as this terrible extension is 
concerned. Some small nits with the changes, but otherwise LGTM.

https://github.com/llvm/llvm-project/pull/86652
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Warn consecutive builtin comparisons in an expression (PR #92200)

2024-05-15 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

> Set the warning to DefaultIgnore, although -Wparentheses is enabled by 
> default 

Do we know why GCC elected to go that route? This seems like something that 
should be enabled by default because the false positive rate should be quite 
low.

https://github.com/llvm/llvm-project/pull/92200
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Allow raw string literals in C as an extension (PR #88265)

2024-05-15 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

Btw, it seems that precommit CI found some valid issues to be addressed

https://github.com/llvm/llvm-project/pull/88265
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Allow raw string literals in C as an extension (PR #88265)

2024-05-15 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

> > I don't think we should allow it for C++11 and later modes
> 
> To clarify, should we allow enabling them in e.g. `c++03` mode if 
> `-fraw-string-literals` is passed? I don’t see why not, but I’m not entirely 
> sure whether you’re saying we should not support that flag in C++ (neither 
> the positive nor the negative variant) at all or just not in C++11 and later.

I think we should allow users to enable them in C++03 modes if 
`-fraw-string-literals` is passed. I think it's fine to have 
`-fno-raw-string-literals` that allows users to disable them in C++03 mode (in 
case an earlier command line option opted into them and the user wants to 
disable the feature for some reason), but I don't know if that's worth the 
effort to support because I don't think we should allow 
`-fno-raw-string-literals` in C++11 mode.

https://github.com/llvm/llvm-project/pull/88265
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Build out AST consumer patterns to reach the entry point into CIRGen (PR #91007)

2024-05-14 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

> Thanks for everyone's input so far. Let me try to summarize discussions in 
> this PR so we can set on an approach and give advice to our CIR community 
> (and encode on our webpage) on how to move forward in upcoming patches. 
> Useful resources:
> 
> * [LLVM Coding Standard](https://llvm.org/docs/CodingStandards.html)
> 
> * [MLIR Style 
> Guide](https://mlir.llvm.org/getting_started/DeveloperGuide/#style-guide)
> 
> 
> CC'ing more people who might care: @seven-mile, @Lancern.
> ## Use of `auto`
> 
> As @joker-eph mentioned, MLIR isn't meant to differ from LLVM/Clang, though 
> they encode the differences as part of their guidelines. The `auto` 
> [guidance](https://llvm.org/docs/CodingStandards.html#use-auto-type-deduction-to-make-code-more-readable)
>  is still in favor of us keeping it for all `isa`, `dyn_cast` and `cast`, 
> which is used in CIR, so it probably doesn't affect most of what we currently 
> care about. Here's my suggestion for the entire `lib/CIR`:
> 
> 1. Use it for function templates such as `isa`, `dyn_cast`, `cast`, 
> `create` and `rewriteOp.*` variants.

Agreed -- anywhere the type is spelled out somewhere in the initializer is fine 
(so also `static_cast`, `getAs`, `new`, etc).

> 2. Use it for things considered obvious/common in MLIR space, examples:
> 
> 
> * `auto loc = op->getLoc()`.

What is obvious in the MLIR space is not necessarily what's obvious in Clang; I 
have no idea whether that returns a `SourceLocation`, a `PresumedLoc`, a 
`FullSourceLoc`, etc, so I don't think that is a use of `auto` I would want to 
have to reason about as a reviewer. That said, if the only use of `loc` is: 
`Diag(loc, diag::err_something);` then the type really doesn't matter and use 
of `auto` is probably fine. It's a judgment call.

> * Getting operands and results from operations (they obey Value 
> Semantics), e.g.: `DepthwiseConv2DNhwcHwcmOp op; ...; auto stride = 
> op.getStrides();`

Again, I have no idea what the type of that is and I have no way to verify that 
it actually *uses* value semantics because the pointer and qualifiers can be 
inferred and references can be dropped. That makes it harder to review the 
code; I would spell out the type in this case as well.

> * Other examples we are happy to provide upon reviewer feedback if it 
> makes sense.

The big things for reviewers are: don't use `auto` if the type isn't incredibly 
obvious (spelled in the initialization or extremely obvious based on 
immediately surrounding code) and don't make us infer important parts the 
declarator (if it's a `const Foo *` and `auto` makes sense for some reason, 
spell it `const auto *` rather than `auto`). And if a reviewer asks for 
something to be converted from `auto` to an explicit type name, assume that 
means the code isn't as readable as it could be and switch to a concrete type 
(we should not be arguing "I think this is clear therefore you should also 
think it's clear" during review, that just makes the review process painful for 
everyone involved).

> Using the logic above, all `auto`s in this current PR have to be changed 
> (since none apply).
> ## Var naming: CamelCase vs camelBack
> 
> From this discussion, seems like @AaronBallman and @erichkeane are fine with 
> us using camelBack and all the other differences from [MLIR Style 
> Guide](https://mlir.llvm.org/getting_started/DeveloperGuide/#style-guide) in 
> CIRGen and the rest of CIR. Is that right? This is based on the comment:
> 
> > The mixed naming conventions in the header should be fixed (preference is 
> > to follow LLVM style if we're changing code around, but if the local 
> > preference is for MLIR, that's fine so long as it's consistent).
>
> However, @AaronBallman also wrote:
> 
> > Also, the fact that the naming keeps being inconsistent is a pretty strong 
> > reason to change to use the LLVM naming convention, at least for external 
> > interfaces.
> 
> Should we ignore this in light of your first comment? If not, can you clarify 
> what do you mean by external interfaces? Just want to make sure we get it 
> right looking fwd.

My thinking is: 1) (most important) the convention should be consistent with 
other nearby code, whatever that convention happens to be. 2) if there's not 
already a convention to follow and if it's code that lives in 
`clang/include/clang`, it should generally follow the LLVM style (it's an 
"external" interface) because those are the APIs that folks outside of CIR will 
be calling into. If it's code that lives in `clang/lib/`, following the MLIR 
style is less of a concern.

So in the case of this review, there's mixed styles being used in the PR and so 
something has to change. If we're changing something anyway, changing to the 
LLVM style is generally preferred over changing to the MLIR style.

One caveat to this is: avoid busywork but use your best judgement on how we 
*eventually* get to a consistent use of the LLVM style. If 

[clang] [CIR] Build out AST consumer patterns to reach the entry point into CIRGen (PR #91007)

2024-05-14 Thread Aaron Ballman via cfe-commits


@@ -42,6 +47,14 @@ CreateFrontendBaseAction(CompilerInstance ) {
   StringRef Action("unknown");
   (void)Action;
 
+  auto UseCIR = CI.getFrontendOpts().UseClangIRPipeline;

AaronBallman wrote:

> Nit: technically the coding standard does not say that, I believe you're 
> mentioning a sufficient condition, not a necessary one, see 
> https://llvm.org/docs/CodingStandards.html#use-auto-type-deduction-to-make-code-more-readable
> 
> > Use auto if and only if it makes the code more readable or easier to 
> > maintain.

Yup. FWIW, the rule of thumb we use in Clang is that "readable" means "type is 
spelled out in the initialization somewhere or is otherwise painful to spell 
but is contextually quite obvious (e.g., use of iterators)" + "any time the 
code reviewer asks to switch away from `auto`"

https://github.com/llvm/llvm-project/pull/91007
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Mark P2552 as implemented. (PR #92007)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/92007
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Mark P2552 as implemented. (PR #92007)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

LGTM aside from a potential improvement to the test for clarity.

https://github.com/llvm/llvm-project/pull/92007
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Mark P2552 as implemented. (PR #92007)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -x c++ -std=c++11 -triple x86_64-pc-linux -fsyntax-only
+// RUN: %clang_cc1 -x c++ -std=c++11 -triple x86_64-windows-msvc -fsyntax-only
+
+// Check we return non-zero values for supported attributes as per
+// wg21.link/p2552r3.pdf
+static_assert(__has_cpp_attribute(assume));
+
+// The standard does not prescribe a behavior for [[carries_dependency]]
+
+static_assert(__has_cpp_attribute(deprecated));
+static_assert(__has_cpp_attribute(fallthrough));
+static_assert(__has_cpp_attribute(likely));
+static_assert(__has_cpp_attribute(unlikely));
+static_assert(__has_cpp_attribute(maybe_unused));
+static_assert(__has_cpp_attribute(nodiscard));
+static_assert(__has_cpp_attribute(noreturn));
+
+#ifdef _MSC_VER

AaronBallman wrote:

I think it's more clear to use `-verify=` instead of using `#ifdef` so it's 
clear that we expect the static assertion to fail in MSVC mode, but I don't 
insist.

https://github.com/llvm/llvm-project/pull/92007
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Add attribute for consteval builtins; Declare constexpr builtins as constexpr in C++ (PR #91894)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -14,13 +14,18 @@ void __builtin_va_copy(double d);
 // expected-error@+2 {{cannot redeclare builtin function '__builtin_va_end'}}
 // expected-note@+1 {{'__builtin_va_end' is a builtin with type}}
 void __builtin_va_end(__builtin_va_list);
-// RUN: %clang_cc1 %s -fsyntax-only -verify 
-// RUN: %clang_cc1 %s -fsyntax-only -verify -x c
 
 void __va_start(__builtin_va_list*, ...);
 
+  void *__builtin_assume_aligned(const void *, size_t, ...);
 #ifdef __cplusplus
-void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
-#else
-void *__builtin_assume_aligned(const void *, size_t, ...);
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...);
+  void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...) noexcept;
+  void *__builtin_assume_aligned(const void *, size_t, ...) throw();
+constexpr void *__builtin_assume_aligned(const void *, size_t, ...) throw();
+

AaronBallman wrote:

Does anyone know why we allow builtins to be redeclared at all? CC @zygoloid 
@rjmccall 

I wonder just how much code we would break by not aiming for backwards 
compatibility here and requiring users to update their declarations on the 
assumption that declaring these at all is undefined behavior (using a reserved 
name) and so it's up to the user to match the compiler's behavior rather than 
make the compiler handle this with weird non-conforming language extension 
behavior.

I'm not looking to punish users in this case, but the workaround to keep things 
backwards compatible is pretty magical and awkward.

https://github.com/llvm/llvm-project/pull/91894
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Report erroneous floating point results in _Complex math (PR #90588)

2024-05-13 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

The changes seem reasonable to me, but I'd like to hear from @jcranmer-intel 
and/or @hubert-reinterpretcast in terms of whether they agree with this 
direction.

https://github.com/llvm/llvm-project/pull/90588
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Introduce `SemaObjC` (PR #89086)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

LGTM! CC @rjmccall for any last-minute concerns.

https://github.com/llvm/llvm-project/pull/89086
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Enable C++17 relaxed template template argument matching by default (PR #89807)

2024-05-13 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

> For publicly-available code, it's not clear to me how much of the burden 
> should fall on people that identify the problem. I want to do as much of this 
> work as I can, it's difficult to balance the urgency of providing some 
> reproducer (it gets hard to push for a fix if we wait a week for a good 
> reproducers), the quality of reduction, and other work/deadlines. (As 
> mentioned, the timing was difficult this time as this landed just before a 
> holiday).

(Not talking about the revert policy, but just about reduced reproducers.)

I don't think we have (or want) hard-and-fast rules for how much of the burden 
falls on folks who find the issue -- we want to encourage people to report 
issues even if they don't have the time or ability to reduce the problem, but 
we also don't want to overload the community with issues that need significant 
reduction work. My suggestion is: initially, provide *anything* that 
demonstrates the issue so that folks are aware a problem exists, but with an 
understanding that the harder it is to reproduce (or the larger the reproducer 
is), the less likely it is the issue will be addressed in a timely manner. So 
if something is of critical importance to you, then the bar is higher for you 
to provide as much help as possible in getting to the point we can fix the 
issue on a timeline that works for you. But it's definitely a balancing act and 
the community should be willing to pitch in to help with reduction and mitigate 
fallout as much as possible (as what seems to have happened in this case).

https://github.com/llvm/llvm-project/pull/89807
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits
Jim M. R. =?utf-8?q?Teichgräber?=,Jim M. R. =?utf-8?q?Teichgräber?Message-ID:
In-Reply-To: 


AaronBallman wrote:

> > > Btw, you can probably move this PR out of Draft status, it seems awfully 
> > > close to finished
> > 
> > 
> > I'll finish implementing your suggestions, run the tests again locally and 
> > then move it out of draft, if that's alright with you :).
> 
> Either way is fine I’d say, but the thing is that I personally at least would 
> use draft prs mainly for something where I’m nowhere close to done and it’s 
> not really ready for review because things are probably going to change, but 
> I just want to signal that I’m working on it. If it’s something that’s mostly 
> done or which is at least mostly review-ready, then I’d just use a regular 
> pr, but that’s just how I do it.

FWIW, that's what I'm used to as well. I usually ignore anything marked "Draft" 
on the assumption it's not ready for review, but I happened to remember the 
discussion on the issue and peeked at this one anyway. :-)

https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits
Jim M. R. =?utf-8?q?Teichgräber?=,Jim M. R. =?utf-8?q?Teichgräber?Message-ID:
In-Reply-To: 


AaronBallman wrote:

> > Please be sure to add a release note to clang/docs/ReleaseNotes.rst so 
> > users know about the fix.
> 
> Oh, sorry, I didn't find anything know how release notes were handled - will 
> do!

No worries!

> A question on that, would you classify this as a breaking change? 
> Technically, it could break the compilation of programs previously compiled 
> with Clang 17 that compile VLA type compound literals, but never execute the 
> code that they're used in; is that enough for it to be listed as a breaking 
> change? If so, would this go under the `C/C++ Language Potentially Breaking 
> Changes` header? Or should I create a new `C Language Potentially Breaking 
> Changes` header, as this does not affect Clang's C++ behavior itself in any 
> way?

Nope -- potentially breaking changes are ones that are likely to be 
significantly disruptive, but I suspect very few folks will have code suddenly 
rejected as a result of your fix.

> PS: I hope multiple commits in this PR are fine, they are squashed in the end 
> anyway, right?

Totally fine!


https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Comments] Attach comments to decl even if preproc directives are in between (PR #88367)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -107,6 +107,24 @@
 ///The 2nd source tile. Max size is 1024 Bytes.
 #define _tile_cmmrlfp16ps(dst, a, b) __builtin_ia32_tcmmrlfp16ps(dst, a, b)
 
+/// Perform matrix multiplication of two tiles containing complex elements and

AaronBallman wrote:

Is this an unrelated change?

https://github.com/llvm/llvm-project/pull/88367
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Comments] Attach comments to decl even if preproc directives are in between (PR #88367)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -533,6 +533,8 @@ __rdtscp(unsigned int *__A) {
 /// \see __rdpmc
 #define _rdpmc(A) __rdpmc(A)
 
+;

AaronBallman wrote:

This is quite surprising; I'm guessing this is so that the previous comment 
does not associate with the function declared below, but this still feels 
pretty unclean.

https://github.com/llvm/llvm-project/pull/88367
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Comments] Attach comments to decl even if preproc directives are in between (PR #88367)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/88367
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Comments] Attach comments to decl even if preproc directives are in between (PR #88367)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman commented:

Because doxygen supports documenting macros 
(https://www.doxygen.nl/manual/commands.html#cmddef), I am worried how often 
this will cause us to associate comments incorrectly on the declaration.

I wonder if we should be a bit smarter and check for `#define` at the start of 
a line when we encounter a `#`. e.g.,
```
/*!
  \def DERP(x)
  Does a derpy thing with x
*/
#define DERP(x) (x)

void derp(void); // Does not get the doxygen comment
```
while
```
/// Does amazing things, like works in the presence of
/// #define doing stupid things.
void func(); // does get the doxygen comment
```

https://github.com/llvm/llvm-project/pull/88367
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman closed 
https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman updated 
https://github.com/llvm/llvm-project/pull/90603

>From 9b1fe59633b5404281b5b9fd754b8a81fae411d0 Mon Sep 17 00:00:00 2001
From: Chris Warner 
Date: Tue, 23 Apr 2024 10:48:44 -0700
Subject: [PATCH 1/5] Load queries and matchers from file during REPL cycle

The clang-query tool has the ability to execute or pre-load queries from
a file when the tool is started, but doesn't have the ability to do the
same from the interactive REPL prompt.  Because the prompt also doesn't
seem to allow multi-line matchers, this can make prototyping and
iterating on more complicated matchers difficult.

Supporting a dynamic load at REPL time allows the cost of reading the
compilation database and building the AST to be imposed just once, and
allows faster prototyping.
---
 clang-tools-extra/clang-query/Query.cpp   | 22 +++
 clang-tools-extra/clang-query/Query.h | 18 ++-
 clang-tools-extra/clang-query/QueryParser.cpp | 10 +++--
 .../clang-query/tool/ClangQuery.cpp   | 18 ++-
 .../test/clang-query/Inputs/file.script   |  1 +
 .../clang-query/Inputs/runtime_file.script|  1 +
 .../test/clang-query/file-query.c | 11 ++
 .../unittests/clang-query/QueryParserTest.cpp |  4 +++-
 8 files changed, 65 insertions(+), 20 deletions(-)
 create mode 100644 clang-tools-extra/test/clang-query/Inputs/file.script
 create mode 100644 
clang-tools-extra/test/clang-query/Inputs/runtime_file.script
 create mode 100644 clang-tools-extra/test/clang-query/file-query.c

diff --git a/clang-tools-extra/clang-query/Query.cpp 
b/clang-tools-extra/clang-query/Query.cpp
index c436d6fa94986..9d5807a52fa8e 100644
--- a/clang-tools-extra/clang-query/Query.cpp
+++ b/clang-tools-extra/clang-query/Query.cpp
@@ -7,6 +7,7 @@
 
//===--===//
 
 #include "Query.h"
+#include "QueryParser.h"
 #include "QuerySession.h"
 #include "clang/AST/ASTDumper.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -281,5 +282,26 @@ const QueryKind SetQueryKind::value;
 const QueryKind SetQueryKind::value;
 #endif
 
+bool FileQuery::run(llvm::raw_ostream , QuerySession ) const {
+  auto Buffer = llvm::MemoryBuffer::getFile(StringRef{File}.trim());
+  if (!Buffer) {
+if (Prefix.has_value())
+  llvm::errs() << *Prefix << ": ";
+llvm::errs() << "cannot open " << File << ": "
+ << Buffer.getError().message() << "\n";
+return false;
+  }
+
+  StringRef FileContentRef(Buffer.get()->getBuffer());
+
+  while (!FileContentRef.empty()) {
+QueryRef Q = QueryParser::parse(FileContentRef, QS);
+if (!Q->run(llvm::outs(), QS))
+  return false;
+FileContentRef = Q->RemainingContent;
+  }
+  return true;
+}
+
 } // namespace query
 } // namespace clang
diff --git a/clang-tools-extra/clang-query/Query.h 
b/clang-tools-extra/clang-query/Query.h
index 7aefa6bb5ee0d..7242479633c24 100644
--- a/clang-tools-extra/clang-query/Query.h
+++ b/clang-tools-extra/clang-query/Query.h
@@ -30,7 +30,8 @@ enum QueryKind {
   QK_SetTraversalKind,
   QK_EnableOutputKind,
   QK_DisableOutputKind,
-  QK_Quit
+  QK_Quit,
+  QK_File
 };
 
 class QuerySession;
@@ -188,6 +189,21 @@ struct DisableOutputQuery : SetNonExclusiveOutputQuery {
   }
 };
 
+struct FileQuery : Query {
+  FileQuery(StringRef File, StringRef Prefix = StringRef())
+  : Query(QK_File), File(File),
+Prefix(!Prefix.empty() ? std::optional(Prefix)
+   : std::nullopt) {}
+
+  bool run(llvm::raw_ostream , QuerySession ) const override;
+
+  static bool classof(const Query *Q) { return Q->Kind == QK_File; }
+
+private:
+  std::string File;
+  std::optional Prefix;
+};
+
 } // namespace query
 } // namespace clang
 
diff --git a/clang-tools-extra/clang-query/QueryParser.cpp 
b/clang-tools-extra/clang-query/QueryParser.cpp
index 162acc1a598dd..85a442bdd7ded 100644
--- a/clang-tools-extra/clang-query/QueryParser.cpp
+++ b/clang-tools-extra/clang-query/QueryParser.cpp
@@ -183,7 +183,8 @@ enum ParsedQueryKind {
   PQK_Unlet,
   PQK_Quit,
   PQK_Enable,
-  PQK_Disable
+  PQK_Disable,
+  PQK_File
 };
 
 enum ParsedQueryVariable {
@@ -222,12 +223,14 @@ QueryRef QueryParser::doParse() {
   .Case("let", PQK_Let)
   .Case("m", PQK_Match, /*IsCompletion=*/false)
   .Case("match", PQK_Match)
-  .Case("q", PQK_Quit,  /*IsCompletion=*/false)
+  .Case("q", PQK_Quit, /*IsCompletion=*/false)
   .Case("quit", PQK_Quit)
   .Case("set", PQK_Set)
   .Case("enable", PQK_Enable)
   .Case("disable", PQK_Disable)
   .Case("unlet", PQK_Unlet)
+  .Case("f", PQK_File, /*IsCompletion=*/false)
+

[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -0,0 +1,14 @@
+// RUN: rm -rf %/t
+// RUN: mkdir %/t
+// RUN: cp %/S/Inputs/file.script %/t/file.script
+// RUN: cp %/S/Inputs/runtime_file.script %/t/runtime_file.script
+// Need to embed the correct temp path in the actual JSON-RPC requests.
+// RUN: sed -e "s|DIRECTORY|%/t|" %/t/file.script > %/t/file.script.temp
+
+// RUN: clang-query -c 'file %/t/file.script.temp' %s -- | FileCheck %s
+
+// CHECK: file-query.c:11:1: note: "f" binds here
+void bar(void) {}
+
+// CHECK: file-query.c:14:1: note: "v" binds here
+int baz{1};

AaronBallman wrote:

```suggestion
int baz{1};

```

https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -0,0 +1,14 @@
+// RUN: rm -rf %/t
+// RUN: mkdir %/t
+// RUN: cp %/S/Inputs/file.script %/t/file.script
+// RUN: cp %/S/Inputs/runtime_file.script %/t/runtime_file.script
+// Need to embed the correct temp path in the actual JSON-RPC requests.
+// RUN: sed -e "s|DIRECTORY|%/t|" %/t/file.script > %/t/file.script.temp
+
+// RUN: clang-query -c 'file %/t/file.script.temp' %s -- | FileCheck %s
+
+// CHECK: file-query.c:11:1: note: "f" binds here
+void bar(void) {}
+
+// CHECK: file-query.c:14:1: note: "v" binds here
+int baz{1};

AaronBallman wrote:

Can you add a newline to the end of the file?

https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -281,5 +282,26 @@ const QueryKind SetQueryKind::value;
 const QueryKind SetQueryKind::value;
 #endif
 
+bool FileQuery::run(llvm::raw_ostream , QuerySession ) const {
+  auto Buffer = llvm::MemoryBuffer::getFile(StringRef{File}.trim());
+  if (!Buffer) {
+if (Prefix.has_value())
+  llvm::errs() << *Prefix << ": ";
+llvm::errs() << "cannot open " << File << ": "
+ << Buffer.getError().message() << "\n";

AaronBallman wrote:

I was thinking of pulling the information from the `ASTUnit` as that's how 
`MatchQuery` works, but then I realized this suggestion isn't fantastic because 
there's no source location to emit the diagnostic for. That got me looking at 
`InvalidQuery` and I see we emit directly to the passed `raw_ostream`, which is 
`llvm::outs()`.

Curiously, `runCommandsInFile()` emits to `llvm::errs()` instead, so we 
sometimes emit to the output stream and sometimes to the error stream. I'd say 
this case can continue to output to the error stream and maybe someday we 
should make this a bit more consistent across the tool.

https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

LGTM! I'll add the newline to the file when landing so you don't have to mess 
with another round of updating the PR. Thank you for the addition!

https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman commented:

Btw, you can probably move this PR out of Draft status, it seems awfully close 
to finished

https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic -Wno-comment %s

AaronBallman wrote:

Ah! That's a perfectly fine reason to use `-Wno-comment` and you can leave the 
test as-is if you'd like, but another option is to use relative verify lines, 
as in:
```
bad_code();
// expected-warning@-1 {{you did the bad thing}}
// expected-note@-2 {{you should feel bad about that}}
```


https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -3371,6 +3371,8 @@ def err_field_with_address_space : Error<
   "field may not be qualified with an address space">;
 def err_compound_literal_with_address_space : Error<
   "compound literal in function scope may not be qualified with an address 
space">;
+def err_compound_literal_with_vla_type : Error<
+  "compound literal has variable-length array type">;

AaronBallman wrote:

```suggestion
  "compound literal cannot be of variable-length array type">;
```

https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits


@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic -Wno-comment %s

AaronBallman wrote:

Why did this test need to add `-Wno-comment`?

https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Disallow VLA type compound literals (PR #91891)

2024-05-13 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman commented:

Oops, we used to diagnose this until Clang 17 (I think I accidentally regressed 
this behavior when implementing empty inits for C23). Thank you for the fix!

Please be sure to add a release note to clang/docs/ReleaseNotes.rst so users 
know about the fix.

https://github.com/llvm/llvm-project/pull/91891
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Don't issue -Wcast-function-type-mismatch for enums with a matching underlying type (PR #87793)

2024-05-09 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman approved this pull request.

Sorry for the delayed review, this fell off my radar. No release note needed 
because this is fixing an issue introduced in this release. LGTM with a small 
testing request.

https://github.com/llvm/llvm-project/pull/87793
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Don't issue -Wcast-function-type-mismatch for enums with a matching underlying type (PR #87793)

2024-05-09 Thread Aaron Ballman via cfe-commits


@@ -19,8 +19,12 @@ f5 *e;
 f6 *f;
 f7 *g;
 
+enum E : long;

AaronBallman wrote:

Another test that would be helpful would be a test not using a fixed underlying 
type but still produces a type compatible with `long`, as in:
```
enum E {
  Big = __LONG_MAX__
};
```

https://github.com/llvm/llvm-project/pull/87793
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Don't issue -Wcast-function-type-mismatch for enums with a matching underlying type (PR #87793)

2024-05-09 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/87793
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][ExprConst] allow single element access of vector object to be constant expression (PR #72607)

2024-05-09 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman commented:

Sorry, this fell off my radar for a while. The only concern I have is with 
accidentally allowing `[0]` to mean something; it would be good to reject 
that and add a test for that situation. Otherwise, this looks reasonable to me.

https://github.com/llvm/llvm-project/pull/72607
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][ExprConst] allow single element access of vector object to be constant expression (PR #72607)

2024-05-09 Thread Aaron Ballman via cfe-commits


@@ -437,6 +442,16 @@ namespace {
   MostDerivedArraySize = 2;
   MostDerivedPathLength = Entries.size();
 }
+void addVectorUnchecked(QualType EltTy, uint64_t Size, uint64_t Idx) {
+  Entries.push_back(PathEntry::ArrayIndex(Idx));
+
+  // This is technically a most-derived object, though in practice this
+  // is unlikely to matter.
+  MostDerivedType = EltTy;
+  MostDerivedIsArrayElement = true;
+  MostDerivedArraySize = Size;

AaronBallman wrote:

Until we have evidence that `[0]` makes sense for vector types, I think we 
should disallow it. It's easier for us to introduce support once we have a use 
case than to have to maintain support should someone start relying on this 
without us intending it as a stable extension.

https://github.com/llvm/llvm-project/pull/72607
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][ExprConst] allow single element access of vector object to be constant expression (PR #72607)

2024-05-09 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/72607
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-09 Thread Aaron Ballman via cfe-commits


@@ -0,0 +1 @@
+m functionDecl()

AaronBallman wrote:

Can you add a few more commands to the file to show that we execute all of the 
commands rather than just one?

It would also be good to have a test where the file is not found and a test 
where the file is empty, just to test boundary conditions.

https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-09 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman edited 
https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-09 Thread Aaron Ballman via cfe-commits


@@ -281,5 +282,26 @@ const QueryKind SetQueryKind::value;
 const QueryKind SetQueryKind::value;
 #endif
 
+bool FileQuery::run(llvm::raw_ostream , QuerySession ) const {
+  auto Buffer = llvm::MemoryBuffer::getFile(StringRef{File}.trim());
+  if (!Buffer) {
+if (Prefix.has_value())
+  llvm::errs() << *Prefix << ": ";
+llvm::errs() << "cannot open " << File << ": "
+ << Buffer.getError().message() << "\n";

AaronBallman wrote:

Rather than printing directly to `errs()`, I think you should construct a 
`TextDiagnostic` object and use that to emit the diagnostic.

https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-query] Load queries and matchers from file during REPL cycle (PR #90603)

2024-05-09 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman commented:

Thank you for working on this, I think it's a good new feature! You should also 
add a release note for it to `clang-tools-extra/docs/ReleaseNotes.rst` so users 
know about the improvement.

https://github.com/llvm/llvm-project/pull/90603
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Comments] Support for parsing headers in Doxygen \par commands (PR #91100)

2024-05-09 Thread Aaron Ballman via cfe-commits


@@ -149,6 +149,63 @@ class TextTokenRetokenizer {
 addToken();
   }
 
+  /// Check if this line starts with @par or \par
+  bool startsWithParCommand() {
+unsigned Offset = 1;
+
+/// Skip all whitespace characters at the beginning.
+/// This needs to backtrack because Pos has already advanced past the
+/// actual \par or @par command by the time this function is called.
+while (isWhitespace(*(Pos.BufferPtr - Offset)))
+  Offset++;

AaronBallman wrote:

Okay, I think what's got me confused is that you calculate `Offset` but never 
actually use it (or modify `Pos.BufferPtr`). I was thinking you would have been 
able to use `ltrim().starts_with(...)` but I see now that the issue is we're at 
the start of the comment, beyond seeing `par`, and we want to backtrack.

But the logic below seems to be that we already know we're parsing a par 
command, so why do we need to do this check in the first place? (e.g., we get 
into this code path via:
```
 else if (Info->IsParCommand)
  S.actOnBlockCommandArgs(BC,
  parseParCommandArgs(Retokenizer, Info->NumArgs));
```
and eventually land here, so don't we already know this is a par command?)

https://github.com/llvm/llvm-project/pull/91100
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Comments] Attach comments to decl even if preproc directives are in between (PR #88367)

2024-05-09 Thread Aaron Ballman via cfe-commits

AaronBallman wrote:

Is this still in Draft status or should this be marked as ready for review?

https://github.com/llvm/llvm-project/pull/88367
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Revise the modules document for clarity (PR #90237)

2024-05-08 Thread Aaron Ballman via cfe-commits

https://github.com/AaronBallman closed 
https://github.com/llvm/llvm-project/pull/90237
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Revise the modules document for clarity (PR #90237)

2024-05-08 Thread Aaron Ballman via cfe-commits


@@ -1753,91 +1742,93 @@ Possible Questions
 How modules speed up compilation
 
 
-A classic theory for the reason why modules speed up the compilation is:
-if there are ``n`` headers and ``m`` source files and each header is included 
by each source file,
-then the complexity of the compilation is ``O(n*m)``;
-But if there are ``n`` module interfaces and ``m`` source files, the 
complexity of the compilation is
-``O(n+m)``. So, using modules would be a big win when scaling.
-In a simpler word, we could get rid of many redundant compilations by using 
modules.
+A classic theory for the reason why modules speed up the compilation is: if
+there are ``n`` headers and ``m`` source files and each header is included by
+each source file, then the complexity of the compilation is ``O(n*m)``.
+However, if there are ``n`` module interfaces and ``m`` source files, the
+complexity of the compilation is ``O(n+m)``. Therefore, using modules would be
+a significant improvement at scale. More simply, use of modules causes many of
+the redundant compilations to no longer be necessary.
 
-Roughly, this theory is correct. But the problem is that it is too rough.
-The behavior depends on the optimization level, as we will illustrate below.
+While this is accurate at a high level, this depends greatly on the
+optimization level, as illustrated below.
 
-First is ``O0``. The compilation process is described in the following graph.
+First is ``-O0``. The compilation process is described in the following graph.
 
 .. code-block:: none
 
   ├-frontend--┼-middle 
end┼backend┤
   │   │   │
   │
   └---parsingsemacodegen--┴- transformations  codegen 
┴ codegen --┘
 
-  
┌---┐
+  
├---┐
   |
   │
   | source file
   │
   |
   │
   
└---┘
 
-  ┌┐
+  ├┐
   ││
   │imported│
   ││
   │  code  │
   ││
   └┘
 
-Here we can see that the source file (could be a non-module unit or a module 
unit) would get processed by the
-whole pipeline.
-But the imported code would only get involved in semantic analysis, which is 
mainly about name lookup,
-overload resolution and template instantiation.
-All of these processes are fast relative to the whole compilation process.
-More importantly, the imported code only needs to be processed once in 
frontend code generation,
-as well as the whole middle end and backend.
-So we could get a big win for the compilation time in O0.
+In this case, the source file (which could be a non-module unit or a module
+unit) would get processed by the entire pipeline. However, the imported code
+would only get involved in semantic analysis, which, for the most part, is name
+lookup, overload resolution, and template instantiation. All of these processes
+are fast relative to the whole compilation process. More importantly, the
+imported code only needs to be processed once during frontend code generation,
+as well as the whole middle end and backend. So we could get a big win for the
+compilation time in ``-O0``.
 
-But with optimizations, things are different:
-
-(we omit ``code generation`` part for each end due to the limited space)
+But with optimizations, things are different (the ``code generation`` part for
+each end is omitted due to limited space):
 
 .. code-block:: none
 
   ├ frontend -┼--- middle end 
┼-- backend ┤
   │   │   
│   │
   └--- parsing  sema -┴--- optimizations --- IPO  
optimizations---┴--- optimizations -┘
 
-  
┌---┐
+  
├---┐
   │
   │
   │ source file
   │
   │
   │
   
└---┘
- 

[clang] Revise the modules document for clarity (PR #90237)

2024-05-08 Thread Aaron Ballman via cfe-commits


@@ -8,109 +8,91 @@ Standard C++ Modules
 Introduction
 
 
-The term ``modules`` has a lot of meanings. For the users of Clang, modules may
-refer to ``Objective-C Modules``, ``Clang C++ Modules`` (or ``Clang Header 
Modules``,
-etc.) or ``Standard C++ Modules``. The implementation of all these kinds of 
modules in Clang
-has a lot of shared code, but from the perspective of users, their semantics 
and
-command line interfaces are very different. This document focuses on
-an introduction of how to use standard C++ modules in Clang.
-
-There is already a detailed document about `Clang modules `_, it
-should be helpful to read `Clang modules `_ if you want to know
-more about the general idea of modules. Since standard C++ modules have 
different semantics
-(and work flows) from `Clang modules`, this page describes the background and 
use of
-Clang with standard C++ modules.
-
-Modules exist in two forms in the C++ Language Specification. They can refer to
-either "Named Modules" or to "Header Units". This document covers both forms.
+The term ``module`` has a lot of meanings. For Clang users, a module may refer
+to an ``Objective-C Module``, `Clang Module `_ (also called a
+``Clang Header Module``) or a ``C++20 Module`` (or a ``Standard C++ Module``).
+The implementation of all these kinds of modules in Clang shares a lot of code,
+but from the perspective of users, their semantics and command line interfaces
+are very different. This document focuses on an introduction to the use of
+C++20 modules in Clang. In the remainder of this document, the term ``module``
+will refer to Standard C++20 modules and the term ``Clang module`` will refer
+to the Clang modules extension.
+
+Modules exist in two forms in the C++ Standard. They can refer to either
+"Named Modules" or "Header Units". This document covers both forms.
 
 Standard C++ Named modules
 ==
 
-This document was intended to be a manual first and foremost, however, we 
consider it helpful to
-introduce some language background here for readers who are not familiar with
-the new language feature. This document is not intended to be a language
-tutorial; it will only introduce necessary concepts about the
-structure and building of the project.
+In order to understand compiler behavior, it is helpful to introduce some
+terms and definitions for readers who are not familiar with the C++ feature.
+This document is not a tutorial on C++; it only introduces necessary concepts
+to better understand use of modules in a project.
 
 Background and terminology
 --
 
-Modules
-~~~
-
-In this document, the term ``Modules``/``modules`` refers to standard C++ 
modules
-feature if it is not decorated by ``Clang``.
-
-Clang Modules
-~
-
-In this document, the term ``Clang Modules``/``Clang modules`` refer to Clang
-c++ modules extension. These are also known as ``Clang header modules``,
-``Clang module map modules`` or ``Clang c++ modules``.
-
 Module and module unit
 ~~
 
-A module consists of one or more module units. A module unit is a special
-translation unit. Every module unit must have a module declaration. The syntax
-of the module declaration is:
+A module consists of one or more module units. A module unit is a special kind
+of translation unit. Every module unit must have a module declaration. The
+syntax of the module declaration is:
 
 .. code-block:: c++
 
   [export] module module_name[:partition_name];
 
-Terms enclosed in ``[]`` are optional. The syntax of ``module_name`` and 
``partition_name``
-in regex form corresponds to ``[a-zA-Z_][a-zA-Z_0-9\.]*``. In particular, a 
literal dot ``.``
-in the name has no semantic meaning (e.g. implying a hierarchy).
+Terms enclosed in ``[]`` are optional. ``module_name`` and ``partition_name``
+are typical C++ identifiers, except that they may contain a period (``.``).
+Note that a ``.`` in the name has no semantic meaning (e.g. implying a
+hierarchy or referring to the file system).
 
-In this document, module units are classified into:
+In this document, module units are classified as:
 
-* Primary module interface unit.
-
-* Module implementation unit.
-
-* Module interface partition unit.
-
-* Internal module partition unit.
+* Primary module interface unit
+* Module implementation unit
+* Module partition interface unit
+* Module partition implementation unit
 
 A primary module interface unit is a module unit whose module declaration is
-``export module module_name;``. The ``module_name`` here denotes the name of 
the
+``export module module_name;`` where ``module_name`` denotes the name of the
 module. A module should have one and only one primary module interface unit.
 
 A module implementation unit is a module unit whose module declaration is
-``module module_name;``. A module could have multiple module implementation
-units with the same declaration.
+``module module_name;``. Multiple module 

<    4   5   6   7   8   9   10   11   12   13   >