Fix crash or wrong code bug if a lifetime-extended temporary contains a
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 8 Oct 2019 21:26:03 +0000 (21:26 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 8 Oct 2019 21:26:03 +0000 (21:26 +0000)
"non-constant" value.

If the constant evaluator evaluates part of a variable initializer,
including the initializer for some lifetime-extended temporary, but
fails to fully evaluate the initializer, it can leave behind wrong
values for temporaries encountered in that initialization. Don't try to
emit those from CodeGen! Instead, look at the values that constant
evaluation produced if (and only if) it actually succeeds and we're
emitting the lifetime-extending declaration's initializer as a constant.

llvm-svn: 374119

clang/lib/AST/ExprConstant.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/test/CodeGenCXX/no-const-init-cxx2a.cpp [new file with mode: 0644]

index c32f516..55ed550 100644 (file)
@@ -13569,8 +13569,10 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage,
   if (!Info.discardCleanups())
     llvm_unreachable("Unhandled cleanup; missing full expression marker?");
 
-  return CheckConstantExpression(Info, getExprLoc(), getType(), Result.Val,
-                                 Usage) &&
+  QualType T = getType();
+  if (!isRValue())
+    T = Ctx.getLValueReferenceType(T);
+  return CheckConstantExpression(Info, getExprLoc(), T, Result.Val, Usage) &&
          CheckMemoryLeaks(Info);
 }
 
index 140f8c3..080914a 100644 (file)
@@ -4978,14 +4978,13 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
       VD, E->getManglingNumber(), Out);
 
   APValue *Value = nullptr;
-  if (E->getStorageDuration() == SD_Static) {
-    // We might have a cached constant initializer for this temporary. Note
-    // that this might have a different value from the value computed by
-    // evaluating the initializer if the surrounding constant expression
-    // modifies the temporary.
+  if (E->getStorageDuration() == SD_Static && VD && VD->evaluateValue()) {
+    // If the initializer of the extending declaration is a constant
+    // initializer, we should have a cached constant initializer for this
+    // temporary. Note that this might have a different value from the value
+    // computed by evaluating the initializer if the surrounding constant
+    // expression modifies the temporary.
     Value = getContext().getMaterializedTemporaryValue(E, false);
-    if (Value && Value->isAbsent())
-      Value = nullptr;
   }
 
   // Try evaluating it now, it might have a constant initializer.
diff --git a/clang/test/CodeGenCXX/no-const-init-cxx2a.cpp b/clang/test/CodeGenCXX/no-const-init-cxx2a.cpp
new file mode 100644 (file)
index 0000000..a945c06
--- /dev/null
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -std=c++2a | FileCheck %s
+
+// CHECK-DAG: @p = {{.*}} null
+// CHECK-DAG: @_ZGR1p_ = {{.*}} null
+int *const &p = new int;
+
+struct d {
+  constexpr d(int &&f) : e(f) {}
+  int &e;
+};
+
+// CHECK-DAG: @g = {{.*}} null
+// CHECK-DAG: @_ZGR1g_ = {{.*}} zeroinitializer
+d &&g{{0}};
+
+// CHECK: define {{.*}} @__cxx_global_var_init
+// CHECK: define {{.*}} @__cxx_global_var_init
+// CHECK-NOT: define {{.*}} @__cxx_global_var_init