diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -4975,6 +4975,13 @@ return false; } + if (const auto *CtorDecl = dyn_cast_or_null(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; @@ -14736,6 +14743,15 @@ 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(FD)) { + for (const auto *InitExpr : Ctor->inits()) { + if (InitExpr->getInit() && InitExpr->getInit()->containsErrors()) + return false; + } + } Expr::EvalStatus Status; Status.Diag = &Diags; diff --git a/clang/test/SemaCXX/invalid-constructor-init.cpp b/clang/test/SemaCXX/invalid-constructor-init.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/invalid-constructor-init.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -frecovery-ast -verify %s + +struct X { + int Y; + constexpr X() // expected-error {{constexpr constructor never produces}} + : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}} +}; +// no crash on evaluating the constexpr ctor. +constexpr int Z = X().Y; // expected-error {{constexpr variable 'Z' must be initialized by a constant expression}} + +struct X2 { + int Y = foo(); // expected-error {{use of undeclared identifier 'foo'}} \ + // expected-note {{subexpression not valid in a constant expression}} + constexpr X2() {} // expected-error {{constexpr constructor never produces a constant expression}} +}; + +struct CycleDelegate { + int Y; + CycleDelegate(int) + : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}} + // no bogus "delegation cycle" diagnostic + CycleDelegate(float) : CycleDelegate(1) {} +};