From 041080c247351da15b6bb21a7196c8dc9bc6babc Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 7 Apr 2020 13:48:18 +0200 Subject: [PATCH] [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr. Summary: crash stack: ``` lang: workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:13704: bool EvaluateInPlace(clang::APValue &, (anonymous namespace)::EvalInfo &, const (anonymous namespace)::LValue &, const clang::Expr *, bool): Assertion `!E->isValueDependent()' failed. #8 EvaluateInPlace(clang::APValue&, (anonymous namespace)::EvalInfo&, (anonymous namespace)::LValue const&, clang::Expr const*, bool) workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:0:0 #9 HandleConstructorCall(clang::Expr const*, (anonymous namespace)::LValue const&, clang::APValue*, clang::CXXConstructorDecl const*, (anonymous namespace)::EvalInfo&, clang::APValue&) workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:5779:57 #10 HandleConstructorCall(clang::Expr const*, (anonymous namespace)::LValue const&, llvm::ArrayRef, clang::CXXConstructorDecl const*, (anonymous namespace)::EvalInfo&, clang::APValue&) workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:5819:10 #11 clang::Expr::isPotentialConstantExpr(clang::FunctionDecl const*, llvm::SmallVectorImpl >&) workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:14746:5 #12 CheckConstexprFunctionBody(clang::Sema&, clang::FunctionDecl const*, clang::Stmt*, clang::Sema::CheckConstexprKind) workspace/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:2306:7 #13 clang::Sema::CheckConstexprFunctionDefinition(clang::FunctionDecl const*, clang::Sema::CheckConstexprKind) workspace/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:1766:0 #14 clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool) workspace/llvm-project/clang/lib/Sema/SemaDecl.cpp:14357:9 #15 clang::Parser::ParseFunctionStatementBody(clang::Decl*, clang::Parser::ParseScope&) workspace/llvm-project/clang/lib/Parse/ParseStmt.cpp:2213:18 ``` Reviewers: sammccall Reviewed By: sammccall Subscribers: rsmith, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D77041 --- clang/lib/AST/ExprConstant.cpp | 16 +++++++++++++ .../test/SemaCXX/invalid-constructor-init.cpp | 23 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 clang/test/SemaCXX/invalid-constructor-init.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9ebde22f7a587f..628f22ae205330 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -4976,6 +4976,13 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, 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; @@ -14709,6 +14716,15 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, 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 index 00000000000000..8fda9cc525babe --- /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) {} +};