"%select{pointer|reference}0 to %select{|subobject of }1"
"%select{temporary|%3}2 is not a constant expression">;
def note_constexpr_uninitialized : Note<
- "subobject of type %0 is not initialized">;
+ "%select{|sub}0object of type %1 is not initialized">;
def note_constexpr_array_index : Note<"cannot refer to element %0 of "
"%select{array of %2 elements|non-array object}1 in a constant expression">;
def note_constexpr_float_arithmetic : Note<
def note_constexpr_modify_global : Note<
"a constant expression cannot modify an object that is visible outside "
"that expression">;
+def note_constexpr_stmt_expr_unsupported : Note<
+ "this use of statement expressions is not supported in a "
+ "constant expression">;
def note_constexpr_calls_suppressed : Note<
"(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to "
"see all)">;
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value) {
if (Value.isUninit()) {
- Info.Diag(DiagLoc, diag::note_constexpr_uninitialized) << Type;
+ Info.Diag(DiagLoc, diag::note_constexpr_uninitialized)
+ << true << Type;
return false;
}
Result.set(VD, Info.CurrentCall->Index);
APValue &Val = Info.CurrentCall->Temporaries[VD];
+ if (!VD->getInit()) {
+ Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized)
+ << false << VD->getType();
+ Val = APValue();
+ return false;
+ }
+
if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) {
// Wipe out any partially-computed value, to allow tracking that this
// evaluation failed.
case ESR_Returned:
return ESR;
case ESR_CaseNotFound:
- llvm_unreachable("couldn't find switch case");
+ // This can only happen if the switch case is nested within a statement
+ // expression. We have no intention of supporting that.
+ Info.Diag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported);
+ return ESR_Failed;
}
llvm_unreachable("Invalid EvalStmtResult!");
}
return DerivedSuccess(RVal, UO);
}
+ RetTy VisitStmtExpr(const StmtExpr *E) {
+ // We will have checked the full-expressions inside the statement expression
+ // when they were completed, and don't need to check them again now.
+ if (Info.getIntOverflowCheckMode())
+ return Error(E);
+
+ const CompoundStmt *CS = E->getSubStmt();
+ for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
+ BE = CS->body_end();
+ /**/; ++BI) {
+ if (BI + 1 == BE) {
+ const Expr *FinalExpr = dyn_cast<Expr>(*BI);
+ if (!FinalExpr) {
+ Info.Diag((*BI)->getLocStart(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return false;
+ }
+ return this->Visit(FinalExpr);
+ }
+
+ APValue ReturnValue;
+ EvalStmtResult ESR = EvaluateStmt(ReturnValue, Info, *BI);
+ if (ESR != ESR_Succeeded) {
+ // FIXME: If the statement-expression terminated due to 'return',
+ // 'break', or 'continue', it would be nice to propagate that to
+ // the outer statement evaluation rather than bailing out.
+ if (ESR != ESR_Failed)
+ Info.Diag((*BI)->getLocStart(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return false;
+ }
+ }
+ }
+
/// Visit a value which is evaluated, but whose value is ignored.
void VisitIgnoredValue(const Expr *E) {
EvaluateIgnoredValue(Info, E);
}
static_assert(sum({1, 2, 3, 4, 5}) == 15, "");
}
+
+namespace StmtExpr {
+ struct A { int k; };
+ void f() {
+ static_assert(({ const int x = 5; x * 3; }) == 15, ""); // expected-warning {{extension}}
+ constexpr auto a = ({ A(); }); // expected-warning {{extension}}
+ }
+ constexpr int g(int k) {
+ return ({ // expected-warning {{extension}}
+ const int x = k;
+ x * x;
+ });
+ }
+ static_assert(g(123) == 15129, "");
+ constexpr int h() { // expected-error {{never produces a constant}}
+ return ({ // expected-warning {{extension}}
+ return 0; // expected-note {{not supported}}
+ 1;
+ });
+ }
+}
}
static_assert(sum({1, 2, 3, 4, 5}) == 15, "");
}
+
+namespace StmtExpr {
+ constexpr int f(int k) {
+ switch (k) {
+ case 0:
+ return 0;
+
+ ({
+ case 1: // expected-note {{not supported}}
+ return 1;
+ });
+ }
+ }
+ static_assert(f(1) == 1, ""); // expected-error {{constant expression}} expected-note {{in call}}
+
+ constexpr int g() { // expected-error {{never produces a constant}}
+ return ({ int n; n; }); // expected-note {{object of type 'int' is not initialized}}
+ }
+
+ // FIXME: We should handle the void statement expression case.
+ constexpr int h() { // expected-error {{never produces a constant}}
+ ({ if (true) {} }); // expected-note {{not supported}}
+ return 0;
+ }
+}