Skip to content

Commit

Permalink
[AST] Fix a crash on invalid constexpr Ctorinitializer when building …
Browse files Browse the repository at this point in the history
…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.
 rust-lang#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
 rust-lang#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
rust-lang#10  HandleConstructorCall(clang::Expr const*, (anonymous namespace)::LValue const&, llvm::ArrayRef<clang::Expr const*>, clang::CXXConstructorDecl const*, (anonymous namespace)::EvalInfo&, clang::APValue&)  workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:5819:10
rust-lang#11  clang::Expr::isPotentialConstantExpr(clang::FunctionDecl const*, llvm::SmallVectorImpl<std::pair<clang::SourceLocation, clang::PartialDiagnostic> >&) workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:14746:5
rust-lang#12  CheckConstexprFunctionBody(clang::Sema&, clang::FunctionDecl const*, clang::Stmt*, clang::Sema::CheckConstexprKind)  workspace/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:2306:7
rust-lang#13  clang::Sema::CheckConstexprFunctionDefinition(clang::FunctionDecl const*, clang::Sema::CheckConstexprKind)  workspace/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:1766:0
rust-lang#14  clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool)  workspace/llvm-project/clang/lib/Sema/SemaDecl.cpp:14357:9
rust-lang#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
  • Loading branch information
hokein committed Apr 7, 2020
1 parent 448b777 commit 041080c
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
16 changes: 16 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4976,6 +4976,13 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
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;
Expand Down Expand Up @@ -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<CXXConstructorDecl>(FD)) {
for (const auto *InitExpr : Ctor->inits()) {
if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
return false;
}
}
Expr::EvalStatus Status;
Status.Diag = &Diags;

Expand Down
23 changes: 23 additions & 0 deletions clang/test/SemaCXX/invalid-constructor-init.cpp
Original file line number Diff line number Diff line change
@@ -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) {}
};

0 comments on commit 041080c

Please sign in to comment.