From: Richard Smith Date: Wed, 1 May 2013 19:00:39 +0000 (+0000) Subject: PR15884: In the 'taking the address of a temporary' extension, materialize the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a07a6c3e756d0a6a5baa2cad9d165f79f0fb1b42;p=clang PR15884: In the 'taking the address of a temporary' extension, materialize the temporary to an lvalue before taking its address. This removes a weird special case from the AST representation, and allows the constant expression evaluator to deal with it without (broken) hacks. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180866 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 17e174e061..d1500d490c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -3215,14 +3215,12 @@ public: } // end anonymous namespace /// Evaluate an expression as an lvalue. This can be legitimately called on -/// expressions which are not glvalues, in a few cases: -/// * function designators in C, -/// * "extern void" objects, -/// * temporaries, if building with -Wno-address-of-temporary. -static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { - assert((E->isGLValue() || E->getType()->isFunctionType() || - E->getType()->isVoidType() || isa(E)) && - "can't evaluate expression as an lvalue"); +/// expressions which are not glvalues, in two cases: +/// * function designators in C, and +/// * "extern void" objects +static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info) { + assert(E->isGLValue() || E->getType()->isFunctionType() || + E->getType()->isVoidType()); return LValueExprEvaluator(Info, Result).Visit(E); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 173ee1e7f8..9f4f6d051c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8306,6 +8306,9 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp, << op->getType() << op->getSourceRange(); if (sfinae) return QualType(); + // Materialize the temporary as an lvalue so that we can take its address. + OrigOp = op = new (S.Context) + MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true); } else if (isa(op)) { return S.Context.getPointerType(op->getType()); } else if (lval == Expr::LV_MemberFunction) { diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index b44bb8c907..1d377eb81d 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1480,3 +1480,13 @@ namespace ArrayEltInit { static_assert(b[0].p != &b[9].p, ""); static_assert(b[9].p != &b[0].p, ""); } + +namespace PR15884 { + struct S {}; + constexpr S f() { return {}; } + constexpr S *p = &f(); + // expected-error@-1 {{taking the address of a temporary}} + // expected-error@-2 {{constexpr variable 'p' must be initialized by a constant expression}} + // expected-note@-3 {{pointer to temporary is not a constant expression}} + // expected-note@-4 {{temporary created here}} +}