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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits