https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/66222
>From b2475193769051ae4d0c340237fd5df76dfe8c49 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Wed, 13 Sep 2023 17:36:39 +0200 Subject: [PATCH 1/6] [Clang] Handle consteval expression in array bounds expressions 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 --- clang/docs/ReleaseNotes.rst | 3 + clang/include/clang/Parse/Parser.h | 1 + clang/include/clang/Sema/Sema.h | 60 +++++++++++--------- clang/lib/Parse/ParseDecl.cpp | 2 +- clang/lib/Parse/ParseExpr.cpp | 9 +++ clang/lib/Sema/SemaCUDA.cpp | 2 +- clang/lib/Sema/SemaChecking.cpp | 55 ++++++++++-------- clang/lib/Sema/SemaExpr.cpp | 4 +- clang/lib/Sema/TreeTransform.h | 3 + clang/test/SemaCXX/cxx2a-consteval.cpp | 21 +++++-- clang/unittests/Support/TimeProfilerTest.cpp | 1 + 11 files changed, 100 insertions(+), 61 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 68172d5317a13ba..207022331a1b691 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -358,6 +358,9 @@ Bug Fixes to C++ Support - Fix crash caused by a spaceship operator returning a comparision category by reference. Fixes: (`#64162 <https://github.com/llvm/llvm-project/issues/64162>`_) +- Fix a crash when calling a consteval function in an expression used as + the size of an array. + (`#65520 <https://github.com/llvm/llvm-project/issues/65520>`_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ 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 712db0a3dd895d5..ad129bee073c35c 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'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 @@ -9845,30 +9835,44 @@ class Sema final { /// diagnostics that will be suppressed. std::optional<sema::TemplateDeductionInfo *> 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'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 ¤tEvaluationContext() const { assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); - return ExprEvalContexts.back().isUnevaluated(); - } + return ExprEvalContexts.back(); + }; bool isConstantEvaluatedContext() const { - assert(!ExprEvalContexts.empty() && - "Must be in an expression evaluation context"); - return ExprEvalContexts.back().isConstantEvaluated(); + return currentEvaluationContext().isConstantEvaluated() || + isConstantEvaluatedOverride; + } + + bool isAlwaysConstantEvaluatedContext() const { + const ExpressionEvaluationContextRecord &Ctx = currentEvaluationContext(); + return (Ctx.isConstantEvaluated() || isConstantEvaluatedOverride) && + !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() && - "Must be in an expression evaluation context"); - return ExprEvalContexts.back().isImmediateFunctionContext(); + return currentEvaluationContext().isImmediateFunctionContext(); } bool isCheckingDefaultArgumentOrInitializer() const { - assert(!ExprEvalContexts.empty() && - "Must be in an expression evaluation context"); - const ExpressionEvaluationContextRecord &Ctx = ExprEvalContexts.back(); + const ExpressionEvaluationContextRecord &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 &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 74664c34abdbd89..00e1de0d7de84cd 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 && "Should only be called during CUDA compilation"); assert(Callee && "Callee may not be null."); - auto &ExprEvalCtx = ExprEvalContexts.back(); + const auto &ExprEvalCtx = currentEvaluationContext(); if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated()) return true; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 6a3b5fa61d59456..082cfc3474d148b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1076,7 +1076,7 @@ static bool ProcessFormatStringLiteral(const Expr *FormatExpr, void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall) { if (TheCall->isValueDependent() || TheCall->isTypeDependent() || - isConstantEvaluated()) + isConstantEvaluatedContext()) return; bool UseDABAttr = false; @@ -3192,7 +3192,7 @@ bool Sema::CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, bool Sema::CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg, bool WantCDE) { - if (isConstantEvaluated()) + if (isConstantEvaluatedContext()) return false; // We can't check the value of a dependent argument. @@ -6616,7 +6616,7 @@ static void CheckNonNullArguments(Sema &S, assert((FDecl || Proto) && "Need a function declaration or prototype"); // Already checked by constant evaluator. - if (S.isConstantEvaluated()) + if (S.isConstantEvaluatedContext()) return; // Check the attributes attached to the method/function itself. llvm::SmallBitVector NonNullArgs; @@ -8973,7 +8973,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; @@ -9687,7 +9687,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset, bool IgnoreStringsWithoutSpecifiers = false) { - if (S.isConstantEvaluated()) + if (S.isConstantEvaluatedContext()) return SLCT_NotALiteral; tryAgain: assert(Offset.isSigned() && "invalid offset"); @@ -9727,8 +9727,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, bool CheckLeft = true, CheckRight = true; bool Cond; - if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext(), - S.isConstantEvaluated())) { + if (C->getCond()->EvaluateAsBooleanCondition( + Cond, S.getASTContext(), S.isConstantEvaluatedContext())) { if (Cond) CheckRight = false; else @@ -9992,9 +9992,11 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Expr::EvalResult LResult, RResult; bool LIsInt = BinOp->getLHS()->EvaluateAsInt( - LResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated()); + LResult, S.Context, Expr::SE_NoSideEffects, + S.isConstantEvaluatedContext()); bool RIsInt = BinOp->getRHS()->EvaluateAsInt( - RResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated()); + RResult, S.Context, Expr::SE_NoSideEffects, + S.isConstantEvaluatedContext()); if (LIsInt != RIsInt) { BinaryOperatorKind BinOpKind = BinOp->getOpcode(); @@ -10022,7 +10024,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Expr::EvalResult IndexResult; if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context, Expr::SE_NoSideEffects, - S.isConstantEvaluated())) { + S.isConstantEvaluatedContext())) { sumOffsets(Offset, IndexResult.Val.getInt(), BO_Add, /*RHS is int*/ true); E = ASE->getBase(); @@ -13953,7 +13955,7 @@ static bool CheckTautologicalComparison(Sema &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->getType(); if (const auto *AT = OtherT->getAs<AtomicType>()) @@ -14168,8 +14170,9 @@ static void AnalyzeComparison(Sema &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. @@ -14187,7 +14190,7 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { if (E->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 @@ -15051,7 +15054,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (Target->isUnsaturatedFixedPointType()) { Expr::EvalResult Result; if (E->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); @@ -15066,7 +15069,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } else if (Target->isIntegerType()) { Expr::EvalResult Result; - if (!S.isConstantEvaluated() && + if (!S.isConstantEvaluatedContext() && E->EvaluateAsFixedPoint(Result, S.Context, Expr::SE_AllowSideEffects)) { llvm::APFixedPoint FXResult = Result.Val.getFixedPoint(); @@ -15089,7 +15092,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } else if (Target->isUnsaturatedFixedPointType()) { if (Source->isIntegerType()) { Expr::EvalResult Result; - if (!S.isConstantEvaluated() && + if (!S.isConstantEvaluatedContext() && E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) { llvm::APSInt Value = Result.Val.getInt(); @@ -15115,8 +15118,9 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (SourceBT && TargetBT && SourceBT->isIntegerType() && TargetBT->isFloatingType() && !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 @@ -15184,8 +15188,8 @@ static void CheckImplicitConversion(Sema &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 > TargetRange.Width) { @@ -15193,7 +15197,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // TODO: this should happen for bitfield stores, too. Expr::EvalResult Result; if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects, - S.isConstantEvaluated())) { + S.isConstantEvaluatedContext())) { llvm::APSInt Value(32); Value = Result.Val.getInt(); @@ -16057,7 +16061,8 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> { if (!EvalOK || E->isValueDependent()) return false; EvalOK = E->EvaluateAsBooleanCondition( - Result, Self.SemaRef.Context, Self.SemaRef.isConstantEvaluated()); + Result, Self.SemaRef.Context, + Self.SemaRef.isConstantEvaluatedContext()); return EvalOK; } @@ -17184,7 +17189,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->IgnoreParenImpCasts(); @@ -18573,7 +18578,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->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->isImmediateFunction() || isConstantEvaluated() || + !Decl->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<FunctionDecl>(E->getDecl())) { - if (!isUnevaluatedContext() && !isConstantEvaluated() && + if (!isUnevaluatedContext() && !isConstantEvaluatedContext() && !isImmediateFunctionContext() && !isCheckingDefaultArgumentOrInitializer() && FD->isImmediateFunction() && !RebuildingImmediateInvocation && diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 0fc5ad8e3bde6c6..9a03be105c2ca12 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -5490,6 +5490,9 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &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->getSizeExpr(); diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index a091fadfa3094bd..1dcff1a9ef81365 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -8,7 +8,7 @@ consteval int f1(int i) { return i; } -consteval constexpr int f2(int i) { +consteval constexpr int f2(int i) { //expected-error@-1 {{cannot combine}} return i; } @@ -195,7 +195,7 @@ auto ptr = ret1(0); struct A { consteval int f(int) { // expected-note@-1+ {{declared here}} - return 0; + return 0; } }; @@ -239,7 +239,7 @@ constexpr int f_c(int i) { int t = f(i); // expected-error@-1 {{is not a constant expression}} // expected-note@-2 {{function parameter}} - return f(0); + return f(0); } consteval int f_eval(int i) { @@ -675,7 +675,7 @@ Bar<derp> a; // expected-note {{in instantiation of member function 'issue_55601 struct constantDerp { // Can be used in a constant expression. - consteval constantDerp(int) {} + consteval constantDerp(int) {} consteval operator int() const { return 5; } }; Bar<constantDerp> b; @@ -1175,4 +1175,17 @@ struct T { static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}} }; +namespace GH65520 { + +consteval int bar (int i) { if (i != 1) return 1/0; return 0; } +// expected-note@-1{{division by zero}} + +void +g () +{ + int a_ok[bar(1)]; + int a_err[bar(3)]; // expected-error {{call to consteval function 'GH65520::bar' is not a constant expression}} \ + // expected-note {{in call to 'bar(3)'}} +} + } diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp index fdfbbfe4e3a9dff..a7ca2bf91e474ef 100644 --- a/clang/unittests/Support/TimeProfilerTest.cpp +++ b/clang/unittests/Support/TimeProfilerTest.cpp @@ -190,6 +190,7 @@ Frontend | EvaluateAsInitializer (slow_value) | EvaluateAsConstantExpr (<test.cc:17:33, col:59>) | EvaluateAsConstantExpr (<test.cc:18:11, col:37>) +| EvaluateAsConstantExpr (<test.cc:23:31, col:57>) | EvaluateAsRValue (<test.cc:22:14, line:23:58>) | EvaluateAsInitializer (slow_init_list) | PerformPendingInstantiations >From 8d38d4d19f15c9c467ab1a3dee77fd8a8f49231b Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 14 Sep 2023 09:21:05 +0200 Subject: [PATCH 2/6] Move the initialization of isConstantEvaluatedOverride --- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Sema/Sema.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ad129bee073c35c..94e2f180e227f11 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9842,7 +9842,7 @@ class Sema final { /// Used to change context to isConstantEvaluated without pushing a heavy /// ExpressionEvaluationContextRecord object. - bool isConstantEvaluatedOverride; + bool isConstantEvaluatedOverride = false; const ExpressionEvaluationContextRecord ¤tEvaluationContext() const { assert(!ExprEvalContexts.empty() && diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index a401017d4c1c0b8..14d6694edc5ad96 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -221,7 +221,6 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, CurScope(nullptr), Ident_super(nullptr) { assert(pp.TUKind == TUKind); TUScope = nullptr; - isConstantEvaluatedOverride = false; LoadedExternalKnownNamespaces = false; for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I) >From 2309c6e414734934904f9eae5266fa72f1a38917 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Tue, 26 Sep 2023 20:54:25 +0200 Subject: [PATCH 3/6] Add test in immediate context --- clang/lib/Sema/SemaChecking.cpp | 4 ++-- clang/test/SemaCXX/cxx2a-consteval.cpp | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 082cfc3474d148b..441a4fc0b0a3311 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -13955,7 +13955,7 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, return false; IntRange OtherValueRange = GetExprRange( - S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate*/ false); + S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/ false); QualType OtherT = Other->getType(); if (const auto *AT = OtherT->getAs<AtomicType>()) @@ -15189,7 +15189,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, IntRange SourceTypeRange = IntRange::forTargetOfCanonicalType(S.Context, Source); IntRange LikelySourceRange = GetExprRange( - S.Context, E, S.isConstantEvaluatedContext(), /*Approximate*/ true); + S.Context, E, S.isConstantEvaluatedContext(), /*Approximate=*/ true); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); if (LikelySourceRange.Width > TargetRange.Width) { diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index 1dcff1a9ef81365..7243233d38069e2 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -1188,4 +1188,12 @@ g () // expected-note {{in call to 'bar(3)'}} } +consteval int undefined(); // expected-note {{declared here}} + +consteval void immediate() { + int a [undefined()]; // expected-note {{undefined function 'undefined' cannot be used in a constant expression}} \ + // expected-error {{call to consteval function 'GH65520::undefined' is not a constant expression}} +} + + } >From d36330174f5bd1e8c91c6c7d66f1ce6477a4a98c Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Wed, 27 Sep 2023 11:32:02 +0200 Subject: [PATCH 4/6] Fix rebase and format --- clang/lib/Sema/SemaChecking.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 441a4fc0b0a3311..7addc9d8daa36c6 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -13955,7 +13955,7 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, return false; IntRange OtherValueRange = GetExprRange( - S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/ false); + S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/false); QualType OtherT = Other->getType(); if (const auto *AT = OtherT->getAs<AtomicType>()) @@ -15189,7 +15189,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, IntRange SourceTypeRange = IntRange::forTargetOfCanonicalType(S.Context, Source); IntRange LikelySourceRange = GetExprRange( - S.Context, E, S.isConstantEvaluatedContext(), /*Approximate=*/ true); + S.Context, E, S.isConstantEvaluatedContext(), /*Approximate=*/true); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); if (LikelySourceRange.Width > TargetRange.Width) { >From a22f4a6cbb4cf08751d4d45dbfde2cc5c5b2540c Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Wed, 27 Sep 2023 12:20:09 +0200 Subject: [PATCH 5/6] Fix test --- clang/test/SemaCXX/cxx2a-consteval.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index 7243233d38069e2..38cc4be32a27c20 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -1175,6 +1175,8 @@ struct T { static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}} }; +} + namespace GH65520 { consteval int bar (int i) { if (i != 1) return 1/0; return 0; } @@ -1192,7 +1194,8 @@ consteval int undefined(); // expected-note {{declared here}} consteval void immediate() { int a [undefined()]; // expected-note {{undefined function 'undefined' cannot be used in a constant expression}} \ - // expected-error {{call to consteval function 'GH65520::undefined' is not a constant expression}} + // expected-error {{call to consteval function 'GH65520::undefined' is not a constant expression}} \ + // expected-error {{variable of non-literal type 'int[undefined()]' cannot be defined in a constexpr function before C++23}} } >From 2872661f277b52bc52c7ce896177bf2e5392e69c Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Wed, 27 Sep 2023 22:21:43 +0200 Subject: [PATCH 6/6] Improve comment using Shafik's suggestion --- clang/lib/Sema/TreeTransform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 9a03be105c2ca12..bcaad0950fa923b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -5490,7 +5490,7 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); - // VLA bounds are not truly constant. + // If we have a VLA then it won't be a constant. SemaRef.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true; // Prefer the expression from the TypeLoc; the other may have been uniqued. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits