forked from OSchip/llvm-project
Fix PR28366: Handle variables from enclosing local scopes more gracefully during constant expression evaluation.
Only look for a variable's value in the constant expression evaluation activation frame, if the variable was indeed declared in that frame, otherwise it might be a constant expression and be usable within a nested local scope or emit an error. void f(char c) { struct X { static constexpr char f() { return c; // error gracefully here as opposed to crashing. } }; int I = X::f(); } llvm-svn: 286748
This commit is contained in:
parent
e706c1d9d9
commit
0528a31ddf
|
@ -4803,10 +4803,21 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
|
|||
return Error(E);
|
||||
}
|
||||
|
||||
|
||||
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
|
||||
CallStackFrame *Frame = nullptr;
|
||||
if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1)
|
||||
Frame = Info.CurrentCall;
|
||||
if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) {
|
||||
// Only if a local variable was declared in the function currently being
|
||||
// evaluated, do we expect to be able to find its value in the current
|
||||
// frame. (Otherwise it was likely declared in an enclosing context and
|
||||
// could either have a valid evaluatable value (for e.g. a constexpr
|
||||
// variable) or be ill-formed (and trigger an appropriate evaluation
|
||||
// diagnostic)).
|
||||
if (Info.CurrentCall->Callee &&
|
||||
Info.CurrentCall->Callee->Equals(VD->getDeclContext())) {
|
||||
Frame = Info.CurrentCall;
|
||||
}
|
||||
}
|
||||
|
||||
if (!VD->getType()->isReferenceType()) {
|
||||
if (Frame) {
|
||||
|
|
|
@ -188,7 +188,7 @@ static void instantiateDependentEnableIfAttr(
|
|||
|
||||
SmallVector<PartialDiagnosticAt, 8> Diags;
|
||||
if (A->getCond()->isValueDependent() && !Cond->isValueDependent() &&
|
||||
!Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(Tmpl),
|
||||
!Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(New),
|
||||
Diags)) {
|
||||
S.Diag(A->getLocation(), diag::err_enable_if_never_constant_expr);
|
||||
for (int I = 0, N = Diags.size(); I != N; ++I)
|
||||
|
|
|
@ -2066,3 +2066,33 @@ namespace InheritedCtor {
|
|||
constexpr Z z(1);
|
||||
static_assert(z.w == 1 && z.x == 2 && z.y == 3 && z.z == 4, "");
|
||||
}
|
||||
|
||||
|
||||
namespace PR28366 {
|
||||
namespace ns1 {
|
||||
|
||||
void f(char c) { //expected-note2{{declared here}}
|
||||
struct X {
|
||||
static constexpr char f() { //expected-error{{never produces a constant expression}}
|
||||
return c; //expected-error{{reference to local}} expected-note{{non-const variable}}
|
||||
}
|
||||
};
|
||||
int I = X::f();
|
||||
}
|
||||
|
||||
void g() {
|
||||
const int c = 'c';
|
||||
static const int d = 'd';
|
||||
struct X {
|
||||
static constexpr int f() {
|
||||
return c + d;
|
||||
}
|
||||
};
|
||||
static_assert(X::f() == 'c' + 'd',"");
|
||||
}
|
||||
|
||||
|
||||
} // end ns1
|
||||
|
||||
} //end ns PR28366
|
||||
|
||||
|
|
|
@ -46,5 +46,17 @@ namespace ns3 {
|
|||
|
||||
} // end ns test_constexpr_call
|
||||
|
||||
#endif // ndef CPP14_AND_EARLIER
|
||||
namespace test_captureless_lambda {
|
||||
void f() {
|
||||
const char c = 'c';
|
||||
auto L = [] { return c; };
|
||||
constexpr char C = L();
|
||||
}
|
||||
|
||||
void f(char c) { //expected-note{{declared here}}
|
||||
auto L = [] { return c; }; //expected-error{{cannot be implicitly captured}} expected-note{{lambda expression begins here}}
|
||||
int I = L();
|
||||
}
|
||||
|
||||
}
|
||||
#endif // ndef CPP14_AND_EARLIER
|
||||
|
|
Loading…
Reference in New Issue