[clang] [Clang] Handle consteval expression in array bounds expressions (PR #66222)

via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 13 08:54:18 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang
            
<details>
<summary>Changes</summary>
The bounds of a c++ array is a _constant-expression_. And in C++ it is also a constant expression.

But we also support VLAs, ie arrays with non-constant bounds.

We need to take care to handle the case of a consteval function (which are specified to be only immediately called in non-constant contexts) that appear in arrays bounds.

This introduces `Sema::isAlwayConstantEvaluatedContext`, and a flag in ExpressionEvaluationContextRecord, such that immediate functions in array bounds are always immediately invoked.

Sema had both `isConstantEvaluatedContext` and
`isConstantEvaluated`, so I took the opportunity to cleanup that.

The change in `TimeProfilerTest.cpp` is an unfortunate manifestation of the problem that #66203 seeks to address.

Fixes #65520
--

Patch is 20.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66222.diff

11 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+4) 
- (modified) clang/include/clang/Parse/Parser.h (+1) 
- (modified) clang/include/clang/Sema/Sema.h (+32-28) 
- (modified) clang/lib/Parse/ParseDecl.cpp (+1-1) 
- (modified) clang/lib/Parse/ParseExpr.cpp (+9) 
- (modified) clang/lib/Sema/SemaCUDA.cpp (+1-1) 
- (modified) clang/lib/Sema/SemaChecking.cpp (+30-25) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+2-2) 
- (modified) clang/lib/Sema/TreeTransform.h (+3) 
- (modified) clang/test/SemaCXX/cxx2a-consteval.cpp (+15) 
- (modified) clang/unittests/Support/TimeProfilerTest.cpp (+1) 


<pre>
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3cdad2f7b9f0e5a..1d2c0830b2910d5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -281,6 +281,10 @@ Bug Fixes to C++ Support
   a non-template inner-class between the function and the class template.
   (`#65810 &lt;https://github.com/llvm/llvm-project/issues/65810&gt;`_)
 
+- Fix a crash when calling a consteval function in an expression used as
+  the size of an array.
+  (`#65520 &lt;https://github.com/llvm/llvm-project/issues/65520&gt;`_)
+
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 - Fixed an import failure of recursive friend class template.
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index f599b8b98d031fb..7303db939de7fe0 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1766,6 +1766,7 @@ class Parser : public CodeCompletionHandler {
   ExprResult ParseConstantExpressionInExprEvalContext(
       TypeCastState isTypeCast = NotTypeCast);
   ExprResult ParseConstantExpression();
+  ExprResult ParseArrayBoundExpression();
   ExprResult ParseCaseExpression(SourceLocation CaseLoc);
   ExprResult ParseConstraintExpression();
   ExprResult
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 304108df9f8d029..77a8cb67be16c91 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1062,20 +1062,6 @@ class Sema final {
     }
   };
 
-  /// Whether the AST is currently being rebuilt to correct immediate
-  /// invocations. Immediate invocation candidates and references to consteval
-  /// functions aren&#x27;t tracked when this is set.
-  bool RebuildingImmediateInvocation = false;
-
-  /// Used to change context to isConstantEvaluated without pushing a heavy
-  /// ExpressionEvaluationContextRecord object.
-  bool isConstantEvaluatedOverride;
-
-  bool isConstantEvaluated() const {
-    return ExprEvalContexts.back().isConstantEvaluated() ||
-           isConstantEvaluatedOverride;
-  }
-
   /// RAII object to handle the state changes required to synthesize
   /// a function body.
   class SynthesizedFunctionScope {
@@ -1361,6 +1347,10 @@ class Sema final {
 
     bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false;
 
+    // We are in a constant context, but we also allow
+    // non constant expressions, for example for array bounds (which may be VLAs).
+    bool InConditionallyConstantEvaluateContext = false;
+
     // When evaluating immediate functions in the initializer of a default
     // argument or default member initializer, this is the declaration whose
     // default initializer is being evaluated and the location of the call
@@ -9844,30 +9834,44 @@ class Sema final {
   /// diagnostics that will be suppressed.
   std::optional&lt;sema::TemplateDeductionInfo *&gt; isSFINAEContext() const;
 
-  /// Determines whether we are currently in a context that
-  /// is not evaluated as per C++ [expr] p5.
-  bool isUnevaluatedContext() const {
+  /// Whether the AST is currently being rebuilt to correct immediate
+  /// invocations. Immediate invocation candidates and references to consteval
+  /// functions aren&#x27;t tracked when this is set.
+  bool RebuildingImmediateInvocation = false;
+
+  /// Used to change context to isConstantEvaluated without pushing a heavy
+  /// ExpressionEvaluationContextRecord object.
+  bool isConstantEvaluatedOverride;
+
+  const ExpressionEvaluationContextRecord &amp;currentEvaluationContext() const {
     assert(!ExprEvalContexts.empty() &amp;&amp;
            &quot;Must be in an expression evaluation context&quot;);
-    return ExprEvalContexts.back().isUnevaluated();
-  }
+    return ExprEvalContexts.back();
+  };
 
   bool isConstantEvaluatedContext() const {
-    assert(!ExprEvalContexts.empty() &amp;&amp;
-           &quot;Must be in an expression evaluation context&quot;);
-    return ExprEvalContexts.back().isConstantEvaluated();
+    return currentEvaluationContext().isConstantEvaluated() ||
+           isConstantEvaluatedOverride;
+  }
+
+  bool isAlwaysConstantEvaluatedContext() const {
+    const ExpressionEvaluationContextRecord &amp;Ctx = currentEvaluationContext();
+    return (Ctx.isConstantEvaluated() || isConstantEvaluatedOverride) &amp;&amp;
+           !Ctx.InConditionallyConstantEvaluateContext;
+  }
+
+  /// Determines whether we are currently in a context that
+  /// is not evaluated as per C++ [expr] p5.
+  bool isUnevaluatedContext() const {
+    return currentEvaluationContext().isUnevaluated();
   }
 
   bool isImmediateFunctionContext() const {
-    assert(!ExprEvalContexts.empty() &amp;&amp;
-           &quot;Must be in an expression evaluation context&quot;);
-    return ExprEvalContexts.back().isImmediateFunctionContext();
+    return currentEvaluationContext().isImmediateFunctionContext();
   }
 
   bool isCheckingDefaultArgumentOrInitializer() const {
-    assert(!ExprEvalContexts.empty() &amp;&amp;
-           &quot;Must be in an expression evaluation context&quot;);
-    const ExpressionEvaluationContextRecord &amp;Ctx = ExprEvalContexts.back();
+    const ExpressionEvaluationContextRecord &amp;Ctx = currentEvaluationContext();
     return (Ctx.Context ==
             ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed) ||
            Ctx.IsCurrentlyCheckingDefaultArgumentOrInitializer;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 748b9d53c9f5b33..5114e181582d91a 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7687,7 +7687,7 @@ void Parser::ParseBracketDeclarator(Declarator &amp;D) {
     // Parse the constant-expression or assignment-expression now (depending
     // on dialect).
     if (getLangOpts().CPlusPlus) {
-      NumElements = ParseConstantExpression();
+      NumElements = ParseArrayBoundExpression();
     } else {
       EnterExpressionEvaluationContext Unevaluated(
           Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index f8bf785da2896a3..e6de742a01f3f6d 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -221,6 +221,15 @@ ExprResult Parser::ParseConstantExpression() {
   return ParseConstantExpressionInExprEvalContext(NotTypeCast);
 }
 
+ExprResult Parser::ParseArrayBoundExpression() {
+  EnterExpressionEvaluationContext ConstantEvaluated(
+      Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+  // If we parse the bound of a VLA... we parse a non-constant
+  // constant-expression!
+  Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true;
+  return ParseConstantExpressionInExprEvalContext(NotTypeCast);
+}
+
 ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
   EnterExpressionEvaluationContext ConstantEvaluated(
       Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 88f5484575db17a..bc676be371b8cf3 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -803,7 +803,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
   assert(getLangOpts().CUDA &amp;&amp; &quot;Should only be called during CUDA compilation&quot;);
   assert(Callee &amp;&amp; &quot;Callee may not be null.&quot;);
 
-  auto &amp;ExprEvalCtx = ExprEvalContexts.back();
+  const auto &amp;ExprEvalCtx = currentEvaluationContext();
   if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated())
     return true;
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index fad70223362eddd..5208dbd9d3c8f58 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1068,7 +1068,7 @@ static bool ProcessFormatStringLiteral(const Expr *FormatExpr,
 void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
                                                CallExpr *TheCall) {
   if (TheCall-&gt;isValueDependent() || TheCall-&gt;isTypeDependent() ||
-      isConstantEvaluated())
+      isConstantEvaluatedContext())
     return;
 
   bool UseDABAttr = false;
@@ -3175,7 +3175,7 @@ bool Sema::CheckCDEBuiltinFunctionCall(const TargetInfo &amp;TI, unsigned BuiltinID,
 
 bool Sema::CheckARMCoprocessorImmediate(const TargetInfo &amp;TI,
                                         const Expr *CoprocArg, bool WantCDE) {
-  if (isConstantEvaluated())
+  if (isConstantEvaluatedContext())
     return false;
 
   // We can&#x27;t check the value of a dependent argument.
@@ -6595,7 +6595,7 @@ static void CheckNonNullArguments(Sema &amp;S,
   assert((FDecl || Proto) &amp;&amp; &quot;Need a function declaration or prototype&quot;);
 
   // Already checked by constant evaluator.
-  if (S.isConstantEvaluated())
+  if (S.isConstantEvaluatedContext())
     return;
   // Check the attributes attached to the method/function itself.
   llvm::SmallBitVector NonNullArgs;
@@ -8952,7 +8952,7 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
 /// TheCall is a constant expression in the range [Low, High].
 bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum,
                                        int Low, int High, bool RangeIsError) {
-  if (isConstantEvaluated())
+  if (isConstantEvaluatedContext())
     return false;
   llvm::APSInt Result;
 
@@ -9666,7 +9666,7 @@ checkFormatStringExpr(Sema &amp;S, const Expr *E, ArrayRef&lt;const Expr *&gt; Args,
                       llvm::SmallBitVector &amp;CheckedVarArgs,
                       UncoveredArgHandler &amp;UncoveredArg, llvm::APSInt Offset,
                       bool IgnoreStringsWithoutSpecifiers = false) {
-  if (S.isConstantEvaluated())
+  if (S.isConstantEvaluatedContext())
     return SLCT_NotALiteral;
 tryAgain:
   assert(Offset.isSigned() &amp;&amp; &quot;invalid offset&quot;);
@@ -9706,8 +9706,8 @@ checkFormatStringExpr(Sema &amp;S, const Expr *E, ArrayRef&lt;const Expr *&gt; Args,
     bool CheckLeft = true, CheckRight = true;
 
     bool Cond;
-    if (C-&gt;getCond()-&gt;EvaluateAsBooleanCondition(Cond, S.getASTContext(),
-                                                 S.isConstantEvaluated())) {
+    if (C-&gt;getCond()-&gt;EvaluateAsBooleanCondition(
+            Cond, S.getASTContext(), S.isConstantEvaluatedContext())) {
       if (Cond)
         CheckRight = false;
       else
@@ -9971,9 +9971,11 @@ checkFormatStringExpr(Sema &amp;S, const Expr *E, ArrayRef&lt;const Expr *&gt; Args,
       Expr::EvalResult LResult, RResult;
 
       bool LIsInt = BinOp-&gt;getLHS()-&gt;EvaluateAsInt(
-          LResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated());
+          LResult, S.Context, Expr::SE_NoSideEffects,
+          S.isConstantEvaluatedContext());
       bool RIsInt = BinOp-&gt;getRHS()-&gt;EvaluateAsInt(
-          RResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated());
+          RResult, S.Context, Expr::SE_NoSideEffects,
+          S.isConstantEvaluatedContext());
 
       if (LIsInt != RIsInt) {
         BinaryOperatorKind BinOpKind = BinOp-&gt;getOpcode();
@@ -10001,7 +10003,7 @@ checkFormatStringExpr(Sema &amp;S, const Expr *E, ArrayRef&lt;const Expr *&gt; Args,
       Expr::EvalResult IndexResult;
       if (ASE-&gt;getRHS()-&gt;EvaluateAsInt(IndexResult, S.Context,
                                        Expr::SE_NoSideEffects,
-                                       S.isConstantEvaluated())) {
+                                       S.isConstantEvaluatedContext())) {
         sumOffsets(Offset, IndexResult.Val.getInt(), BO_Add,
                    /*RHS is int*/ true);
         E = ASE-&gt;getBase();
@@ -13928,7 +13930,7 @@ static bool CheckTautologicalComparison(Sema &amp;S, BinaryOperator *E,
     return false;
 
   IntRange OtherValueRange = GetExprRange(
-      S.Context, Other, S.isConstantEvaluated(), /*Approximate*/ false);
+      S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate*/ false);
 
   QualType OtherT = Other-&gt;getType();
   if (const auto *AT = OtherT-&gt;getAs&lt;AtomicType&gt;())
@@ -14143,8 +14145,9 @@ static void AnalyzeComparison(Sema &amp;S, BinaryOperator *E) {
   }
 
   // Otherwise, calculate the effective range of the signed operand.
-  IntRange signedRange = GetExprRange(
-      S.Context, signedOperand, S.isConstantEvaluated(), /*Approximate*/ true);
+  IntRange signedRange =
+      GetExprRange(S.Context, signedOperand, S.isConstantEvaluatedContext(),
+                   /*Approximate*/ true);
 
   // Go ahead and analyze implicit conversions in the operands.  Note
   // that we skip the implicit conversions on both sides.
@@ -14162,7 +14165,7 @@ static void AnalyzeComparison(Sema &amp;S, BinaryOperator *E) {
   if (E-&gt;isEqualityOp()) {
     unsigned comparisonWidth = S.Context.getIntWidth(T);
     IntRange unsignedRange =
-        GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluated(),
+        GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluatedContext(),
                      /*Approximate*/ true);
 
     // We should never be unable to prove that the unsigned operand is
@@ -15026,7 +15029,7 @@ static void CheckImplicitConversion(Sema &amp;S, Expr *E, QualType T,
     if (Target-&gt;isUnsaturatedFixedPointType()) {
       Expr::EvalResult Result;
       if (E-&gt;EvaluateAsFixedPoint(Result, S.Context, Expr::SE_AllowSideEffects,
-                                  S.isConstantEvaluated())) {
+                                  S.isConstantEvaluatedContext())) {
         llvm::APFixedPoint Value = Result.Val.getFixedPoint();
         llvm::APFixedPoint MaxVal = S.Context.getFixedPointMax(T);
         llvm::APFixedPoint MinVal = S.Context.getFixedPointMin(T);
@@ -15041,7 +15044,7 @@ static void CheckImplicitConversion(Sema &amp;S, Expr *E, QualType T,
       }
     } else if (Target-&gt;isIntegerType()) {
       Expr::EvalResult Result;
-      if (!S.isConstantEvaluated() &amp;&amp;
+      if (!S.isConstantEvaluatedContext() &amp;&amp;
           E-&gt;EvaluateAsFixedPoint(Result, S.Context,
                                   Expr::SE_AllowSideEffects)) {
         llvm::APFixedPoint FXResult = Result.Val.getFixedPoint();
@@ -15064,7 +15067,7 @@ static void CheckImplicitConversion(Sema &amp;S, Expr *E, QualType T,
   } else if (Target-&gt;isUnsaturatedFixedPointType()) {
     if (Source-&gt;isIntegerType()) {
       Expr::EvalResult Result;
-      if (!S.isConstantEvaluated() &amp;&amp;
+      if (!S.isConstantEvaluatedContext() &amp;&amp;
           E-&gt;EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) {
         llvm::APSInt Value = Result.Val.getInt();
 
@@ -15090,8 +15093,9 @@ static void CheckImplicitConversion(Sema &amp;S, Expr *E, QualType T,
   if (SourceBT &amp;&amp; TargetBT &amp;&amp; SourceBT-&gt;isIntegerType() &amp;&amp;
       TargetBT-&gt;isFloatingType() &amp;&amp; !IsListInit) {
     // Determine the number of precision bits in the source integer type.
-    IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated(),
-                                        /*Approximate*/ true);
+    IntRange SourceRange =
+        GetExprRange(S.Context, E, S.isConstantEvaluatedContext(),
+                     /*Approximate*/ true);
     unsigned int SourcePrecision = SourceRange.Width;
 
     // Determine the number of precision bits in the
@@ -15159,8 +15163,8 @@ static void CheckImplicitConversion(Sema &amp;S, Expr *E, QualType T,
 
   IntRange SourceTypeRange =
       IntRange::forTargetOfCanonicalType(S.Context, Source);
-  IntRange LikelySourceRange =
-      GetExprRange(S.Context, E, S.isConstantEvaluated(), /*Approximate*/ true);
+  IntRange LikelySourceRange = GetExprRange(
+      S.Context, E, S.isConstantEvaluatedContext(), /*Approximate*/ true);
   IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
 
   if (LikelySourceRange.Width &gt; TargetRange.Width) {
@@ -15168,7 +15172,7 @@ static void CheckImplicitConversion(Sema &amp;S, Expr *E, QualType T,
     // TODO: this should happen for bitfield stores, too.
     Expr::EvalResult Result;
     if (E-&gt;EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects,
-                         S.isConstantEvaluated())) {
+                         S.isConstantEvaluatedContext())) {
       llvm::APSInt Value(32);
       Value = Result.Val.getInt();
 
@@ -16032,7 +16036,8 @@ class SequenceChecker : public ConstEvaluatedExprVisitor&lt;SequenceChecker&gt; {
       if (!EvalOK || E-&gt;isValueDependent())
         return false;
       EvalOK = E-&gt;EvaluateAsBooleanCondition(
-          Result, Self.SemaRef.Context, Self.SemaRef.isConstantEvaluated());
+          Result, Self.SemaRef.Context,
+          Self.SemaRef.isConstantEvaluatedContext());
       return EvalOK;
     }
 
@@ -17159,7 +17164,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
                             const ArraySubscriptExpr *ASE,
                             bool AllowOnePastEnd, bool IndexNegated) {
   // Already diagnosed by the constant evaluator.
-  if (isConstantEvaluated())
+  if (isConstantEvaluatedContext())
     return;
 
   IndexExpr = IndexExpr-&gt;IgnoreParenImpCasts();
@@ -18548,7 +18553,7 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
   TypeTagData TypeInfo;
   if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context,
                         TypeTagForDatatypeMagicValues.get(), FoundWrongKind,
-                        TypeInfo, isConstantEvaluated())) {
+                        TypeInfo, isConstantEvaluatedContext())) {
     if (FoundWrongKind)
       Diag(TypeTagExpr-&gt;getExprLoc(),
            diag::warn_type_tag_for_datatype_wrong_kind)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 92496b03ecabe54..667444917a9b31e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18282,7 +18282,7 @@ void Sema::MarkExpressionAsImmediateEscalating(Expr *E) {
 
 ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
   if (isUnevaluatedContext() || !E.isUsable() || !Decl ||
-      !Decl-&gt;isImmediateFunction() || isConstantEvaluated() ||
+      !Decl-&gt;isImmediateFunction() || isAlwaysConstantEvaluatedContext() ||
       isCheckingDefaultArgumentOrInitializer() ||
       RebuildingImmediateInvocation || isImmediateFunctionContext())
     return E;
@@ -20668,7 +20668,7 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
       OdrUse = false;
 
   if (auto *FD = dyn_cast&lt;FunctionDecl&gt;(E-&gt;getDecl())) {
-    if (!isUnevaluatedContext() &amp;&amp; !isConstantEvaluated() &amp;&amp;
+    if (!isUnevaluatedContext() &amp;&amp; !isConstantEvaluatedContext() &amp;&amp;
         !isImmediateFunctionContext() &amp;&amp;
         !isCheckingDefaultArgumentOrInitializer() &amp;&amp;
         FD-&gt;isImmediateFunction() &amp;&amp; !RebuildingImmediateInvocation &amp;&amp;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 603a23275889f21..39ac6e9cfbcdcce 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -5486,6 +5486,9 @@ TreeTransform&lt;Derived&gt;::TransformDependentSizedArrayType(TypeLocBuilder &amp;TLB,
   EnterExpressionEvaluationContext Unevaluated(
       SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
 
+  // VLA bounds are not truly constant.
+  SemaRef.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true;
+
   // Prefer the expression from the TypeLoc;  the other may have been uniqued.
   Expr *origSize = TL.getSizeExpr();
   if (!origSize) origSize = T-&gt;getSizeExpr();
diff --git a/clang/test/SemaCX...
<truncated>
</pre>
</details>


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


More information about the cfe-commits mailing list