]> granicus.if.org Git - clang/commitdiff
PR15884: In the 'taking the address of a temporary' extension, materialize the
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 1 May 2013 19:00:39 +0000 (19:00 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 1 May 2013 19:00:39 +0000 (19:00 +0000)
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

lib/AST/ExprConstant.cpp
lib/Sema/SemaExpr.cpp
test/SemaCXX/constant-expression-cxx11.cpp

index 17e174e061a1ed12ad59eb49783d54877197d3e7..d1500d490c902915d723b9254527154d1e0e06bd 100644 (file)
@@ -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<CXXTemporaryObjectExpr>(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);
 }
 
index 173ee1e7f81375a647165ef89f3eda97c62914c9..9f4f6d051c856ab3daf3b8772247322e4c8243a9 100644 (file)
@@ -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<ObjCSelectorExpr>(op)) {
     return S.Context.getPointerType(op->getType());
   } else if (lval == Expr::LV_MemberFunction) {
index b44bb8c9074de87bdffb82016ce7cc9443fab548..1d377eb81d3affd82b30da33374e25e8c8de48ed 100644 (file)
@@ -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}}
+}