hokein updated this revision to Diff 290754. hokein marked an inline comment as done. hokein added a comment.
address review comments. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D84637/new/ https://reviews.llvm.org/D84637 Files: clang/lib/AST/ExprConstant.cpp clang/test/SemaCXX/constexpr-function-recovery-crash.cpp clang/test/SemaCXX/enable_if.cpp clang/test/SemaCXX/invalid-constructor-init.cpp clang/test/SemaCXX/recovery-expr-type.cpp
Index: clang/test/SemaCXX/recovery-expr-type.cpp =================================================================== --- clang/test/SemaCXX/recovery-expr-type.cpp +++ clang/test/SemaCXX/recovery-expr-type.cpp @@ -53,14 +53,12 @@ return 2; } static constexpr int foo2() { - return AA<T>::getB(); // expected-error{{no matching function for call to 'getB'}} \ - // expected-note {{subexpression not valid in a constant expression}} + return AA<T>::getB(); // expected-error{{no matching function for call to 'getB'}} } }; // FIXME: should we suppress the "be initialized by a constant expression" diagnostic? constexpr auto x2 = AA<int>::foo2(); // expected-error {{be initialized by a constant expression}} \ - // expected-note {{in instantiation of member function}} \ - // expected-note {{in call to}} + // expected-note {{in instantiation of member function}} } // verify no assertion failure on violating value category. Index: clang/test/SemaCXX/invalid-constructor-init.cpp =================================================================== --- clang/test/SemaCXX/invalid-constructor-init.cpp +++ clang/test/SemaCXX/invalid-constructor-init.cpp @@ -2,7 +2,7 @@ struct X { int Y; - constexpr X() // expected-error {{constexpr constructor never produces}} + constexpr X() : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}} }; // no crash on evaluating the constexpr ctor. @@ -15,8 +15,8 @@ struct X3 { int Y; - constexpr X3() // expected-error {{constexpr constructor never produces}} - : Y(({foo();})) {} // expected-error {{use of undeclared identifier 'foo'}} + constexpr X3() + : Y(({ foo(); })) {} // expected-error {{use of undeclared identifier 'foo'}} }; struct CycleDelegate { Index: clang/test/SemaCXX/enable_if.cpp =================================================================== --- clang/test/SemaCXX/enable_if.cpp +++ clang/test/SemaCXX/enable_if.cpp @@ -414,8 +414,8 @@ template <int N> constexpr int callTemplated() { return templated<N>(); } -constexpr int B = 10 + // expected-error {{initialized by a constant expression}} - callTemplated<0>(); // expected-error@-3{{no matching function for call to 'templated'}} expected-note{{in instantiation of function template}} expected-note@-10{{candidate disabled}} expected-note {{in call to 'callTemplated()'}} expected-note@-3 {{subexpression not valid in a constant expression}} +constexpr int B = 10 + // expected-error {{initialized by a constant expression}} + callTemplated<0>(); // expected-error@-3{{no matching function for call to 'templated'}} expected-note{{in instantiation of function template}} expected-note@-10{{candidate disabled}} static_assert(callTemplated<1>() == 1, ""); } Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -verify + +// verify no value-dependent-assertion crash in constexpr function body. +class Foo { + constexpr Foo() { + while (invalid()) { + } // expected-error {{use of undeclared identifier}} + if (invalid()) { + } // expected-error {{use of undeclared identifier}} + } +}; + +constexpr void test1() { + while (invalid()) { + } // expected-error {{use of undeclared identifier}} + if (invalid()) { + } // expected-error {{use of undeclared identifier}} +} + +struct A { + int *p = new int(invalid()); // expected-error {{use of undeclared identifier}} + constexpr ~A() { delete p; } +}; +constexpr int test2() { + A a; + return 1; +} + +constexpr int test3() { + return invalid(); // expected-error {{use of undeclared identifier}} +} + +constexpr int test4() { + if (invalid()) // expected-error {{use of undeclared identifier}} + return 1; + else + return 0; +} + +constexpr int test5() { + for (;; a++) + ; // expected-error {{use of undeclared identifier}} + return 1; +} + +constexpr int test6() { + int n = 0; + switch (n) { + for (;; a++) { // expected-error {{use of undeclared identifier}} + case 0:; + } + } + return 0; +} Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -1870,6 +1870,7 @@ /// result. /// \return \c true if the caller should keep evaluating. static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { + assert(!E->isValueDependent()); APValue Scratch; if (!Evaluate(Scratch, Info, E)) // We don't need the value, but we might have skipped a side effect here. @@ -2388,6 +2389,7 @@ static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition"); APValue Val; if (!Evaluate(Val, Info, E)) @@ -4596,9 +4598,11 @@ Info.CurrentCall->createTemporary(VD, VD->getType(), true, Result); const Expr *InitE = VD->getInit(); - if (!InitE) + if (!InitE) { + if (VD->getType()->isDependentType()) + return false; return getDefaultInitValue(VD->getType(), Val); - + } if (InitE->isValueDependent()) return false; @@ -4626,10 +4630,20 @@ return OK; } +static EvalStmtResult EvaluateDependentExpr(const Expr *E, EvalInfo &Info) { + assert(E->isValueDependent()); + if (Info.noteSideEffect()) + return ESR_Succeeded; + assert(E->containsErrors() && "valid value-dependent expression should never " + "reach invalid code path."); + return ESR_Failed; +} /// Evaluate a condition (either a variable declaration or an expression). static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, const Expr *Cond, bool &Result) { + if (Cond->isValueDependent()) + return false; FullExpressionRAII Scope(Info); if (CondDecl && !EvaluateDecl(Info, CondDecl)) return false; @@ -4854,9 +4868,11 @@ EvaluateLoopBody(Result, Info, FS->getBody(), Case); if (ESR != ESR_Continue) return ESR; - if (FS->getInc()) { + if (const auto *Inc = FS->getInc()) { + if (Inc->isValueDependent()) + return EvaluateDependentExpr(Inc, Info); FullExpressionRAII IncScope(Info); - if (!EvaluateIgnoredValue(Info, FS->getInc()) || !IncScope.destroy()) + if (!EvaluateIgnoredValue(Info, Inc) || !IncScope.destroy()) return ESR_Failed; } break; @@ -4887,6 +4903,8 @@ switch (S->getStmtClass()) { default: if (const Expr *E = dyn_cast<Expr>(S)) { + if (E->isValueDependent()) + return EvaluateDependentExpr(E, Info); // Don't bother evaluating beyond an expression-statement which couldn't // be evaluated. // FIXME: Do we need the FullExpressionRAII object here? @@ -4919,6 +4937,10 @@ case Stmt::ReturnStmtClass: { const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue(); FullExpressionRAII Scope(Info); + if (RetExpr && RetExpr->isValueDependent()) + return EvaluateDependentExpr(RetExpr, Info) == ESR_Succeeded + ? ESR_Returned + : ESR_Failed; if (RetExpr && !(Result.Slot ? EvaluateInPlace(Result.Value, Info, *Result.Slot, RetExpr) @@ -5006,6 +5028,8 @@ return ESR; Case = nullptr; + if (DS->getCond()->isValueDependent()) + return EvaluateDependentExpr(DS->getCond(), Info); FullExpressionRAII CondScope(Info); if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info) || !CondScope.destroy()) @@ -5041,9 +5065,11 @@ return ESR; } - if (FS->getInc()) { + if (const auto *Inc = FS->getInc()) { + if (Inc->isValueDependent()) + return EvaluateDependentExpr(Inc, Info); FullExpressionRAII IncScope(Info); - if (!EvaluateIgnoredValue(Info, FS->getInc()) || !IncScope.destroy()) + if (!EvaluateIgnoredValue(Info, Inc) || !IncScope.destroy()) return ESR_Failed; } @@ -5092,6 +5118,8 @@ while (true) { // Condition: __begin != __end. { + if (FS->getCond()->isValueDependent()) + return EvaluateDependentExpr(FS->getCond(), Info); bool Continue = true; FullExpressionRAII CondExpr(Info); if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info)) @@ -5116,7 +5144,8 @@ return ESR_Failed; return ESR; } - + if (FS->getInc()->isValueDependent()) + return EvaluateDependentExpr(FS->getInc(), Info); // Increment: ++__begin if (!EvaluateIgnoredValue(Info, FS->getInc())) return ESR_Failed; @@ -5214,13 +5243,6 @@ return false; } - if (const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(Definition)) { - for (const auto *InitExpr : CtorDecl->inits()) { - if (InitExpr->getInit() && InitExpr->getInit()->containsErrors()) - return false; - } - } - // Can we evaluate this function call? if (Definition && Definition->isConstexpr() && Body) return true; @@ -5877,6 +5899,8 @@ // If it's a delegating constructor, delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); + if ((*I)->getInit()->isValueDependent()) + return EvaluateDependentExpr((*I)->getInit(), Info); { FullExpressionRAII InitScope(Info); if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()) || @@ -6021,6 +6045,8 @@ // This refers to innermost anonymous struct/union containing initializer, // not to currently constructed class. const Expr *Init = I->getInit(); + if (Init->isValueDependent()) + return EvaluateDependentExpr(Init, Info); ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent, isa<CXXDefaultInitExpr>(Init)); FullExpressionRAII InitScope(Info); @@ -7805,6 +7831,7 @@ /// * @selector() expressions in Objective-C static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info, bool InvalidBaseOK) { + assert(!E->isValueDependent()); assert(E->isGLValue() || E->getType()->isFunctionType() || E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E)); return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E); @@ -8335,6 +8362,7 @@ static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info, bool InvalidBaseOK) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->hasPointerRepresentation()); return PointerExprEvaluator(Info, Result, InvalidBaseOK).Visit(E); } @@ -9222,6 +9250,7 @@ static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isMemberPointerType()); return MemberPointerExprEvaluator(Info, Result).Visit(E); } @@ -9696,6 +9725,7 @@ static bool EvaluateRecord(const Expr *E, const LValue &This, APValue &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isRecordType() && "can't evaluate expression as a record rvalue"); return RecordExprEvaluator(Info, This, Result).Visit(E); @@ -9751,6 +9781,7 @@ /// Evaluate an expression of record type as a temporary. static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isRecordType()); return TemporaryExprEvaluator(Info, Result).Visit(E); } @@ -10037,6 +10068,7 @@ static bool EvaluateArray(const Expr *E, const LValue &This, APValue &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isArrayType() && "not an array rvalue"); return ArrayExprEvaluator(Info, This, Result).Visit(E); } @@ -10044,6 +10076,7 @@ static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This, APValue &Result, const InitListExpr *ILE, QualType AllocType) { + assert(!ILE->isValueDependent()); assert(ILE->isRValue() && ILE->getType()->isArrayType() && "not an array rvalue"); return ArrayExprEvaluator(Info, This, Result) @@ -10054,6 +10087,7 @@ APValue &Result, const CXXConstructExpr *CCE, QualType AllocType) { + assert(!CCE->isValueDependent()); assert(CCE->isRValue() && CCE->getType()->isArrayType() && "not an array rvalue"); return ArrayExprEvaluator(Info, This, Result) @@ -10431,11 +10465,13 @@ /// like char*). static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType()); return IntExprEvaluator(Info, Result).Visit(E); } static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); APValue Val; if (!EvaluateIntegerOrLValue(E, Val, Info)) return false; @@ -10457,6 +10493,7 @@ static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); if (E->getType()->isFixedPointType()) { APValue Val; if (!FixedPointExprEvaluator(Info, Val).Visit(E)) @@ -10472,6 +10509,7 @@ static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); if (E->getType()->isIntegerType()) { auto FXSema = Info.Ctx.getFixedPointSemantics(E->getType()); APSInt Val; @@ -12136,6 +12174,7 @@ static bool EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, SuccessCB &&Success, AfterCB &&DoAfter) { + assert(!E->isValueDependent()); assert(E->isComparisonOp() && "expected comparison operator"); assert((E->getOpcode() == BO_Cmp || E->getType()->isIntegralOrEnumerationType()) && @@ -13187,6 +13226,7 @@ } // end anonymous namespace static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isRealFloatingType()); return FloatExprEvaluator(Info, Result).Visit(E); } @@ -13420,6 +13460,7 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isAnyComplexType()); return ComplexExprEvaluator(Info, Result).Visit(E); } @@ -13942,6 +13983,7 @@ static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isAtomicType()); return AtomicExprEvaluator(Info, This, Result).Visit(E); } @@ -14066,6 +14108,7 @@ } static bool EvaluateVoid(const Expr *E, EvalInfo &Info) { + assert(!E->isValueDependent()); assert(E->isRValue() && E->getType()->isVoidType()); return VoidExprEvaluator(Info).Visit(E); } @@ -14075,6 +14118,7 @@ //===----------------------------------------------------------------------===// static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { + assert(!E->isValueDependent()); // In C, function designators are not lvalues, but we evaluate them as if they // are. QualType T = E->getType(); @@ -14185,6 +14229,7 @@ /// EvaluateAsRValue - Try to evaluate this expression, performing an implicit /// lvalue-to-rvalue cast if it is an lvalue. static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { + assert(!E->isValueDependent()); if (Info.EnableNewConstInterp) { if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result)) return false; @@ -14248,6 +14293,7 @@ static bool EvaluateAsRValue(const Expr *E, Expr::EvalResult &Result, const ASTContext &Ctx, EvalInfo &Info) { + assert(!E->isValueDependent()); bool IsConst; if (FastEvaluateAsRValue(E, Result, Ctx, IsConst)) return IsConst; @@ -14259,6 +14305,7 @@ const ASTContext &Ctx, Expr::SideEffectsKind AllowSideEffects, EvalInfo &Info) { + assert(!E->isValueDependent()); if (!E->getType()->isIntegralOrEnumerationType()) return false; @@ -14274,6 +14321,7 @@ const ASTContext &Ctx, Expr::SideEffectsKind AllowSideEffects, EvalInfo &Info) { + assert(!E->isValueDependent()); if (!E->getType()->isFixedPointType()) return false; @@ -15181,15 +15229,6 @@ if (FD->isDependentContext()) return true; - // Bail out if a constexpr constructor has an initializer that contains an - // error. We deliberately don't produce a diagnostic, as we have produced a - // relevant diagnostic when parsing the error initializer. - if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FD)) { - for (const auto *InitExpr : Ctor->inits()) { - if (InitExpr->getInit() && InitExpr->getInit()->containsErrors()) - return false; - } - } Expr::EvalStatus Status; Status.Diag = &Diags;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits