]> granicus.if.org Git - clang/commitdiff
Fix wrong-code bug when a const automatic variable of struct type has both a
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 2 Dec 2011 00:30:33 +0000 (00:30 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 2 Dec 2011 00:30:33 +0000 (00:30 +0000)
mutable member and a constant initializer. We'd previously promoted such
variables to global constants, resulting in nasal demons if the mutable member
was modified.

This is only a temporary fix. The subtle interplay between isConstantInitializer
and CGExprConstant is very bug-prone; there are some other issues in this area
which I will be addressing in subsequent, more major reworking of this code.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145654 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGDecl.cpp
test/CodeGenCXX/const-init.cpp

index 562cc5bb909a6370f0c5000fea41acd691438756..59efea0dae1351a43b7fa8708051e9d0d5bab2d3 100644 (file)
@@ -739,11 +739,13 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
                   D.isNRVOVariable();
 
       // If this value is a POD array or struct with a statically
-      // determinable constant initializer, there are optimizations we
-      // can do.
-      // TODO: we can potentially constant-evaluate non-POD structs and
-      // arrays as long as the initialization is trivial (e.g. if they
-      // have a non-trivial destructor, but not a non-trivial constructor).
+      // determinable constant initializer, there are optimizations we can do.
+      //
+      // TODO: we should constant-evaluate any variable of literal type
+      // as long as it is initialized by a constant expression. Currently,
+      // isConstantInitializer produces wrong answers for structs with
+      // reference or bitfield members, and a few other cases, and checking
+      // for POD-ness protects us from some of these.
       if (D.getInit() &&
           (Ty->isArrayType() || Ty->isRecordType()) &&
           (Ty.isPODType(getContext()) ||
@@ -751,9 +753,10 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
           D.getInit()->isConstantInitializer(getContext(), false)) {
 
         // If the variable's a const type, and it's neither an NRVO
-        // candidate nor a __block variable, emit it as a global instead.
+        // candidate nor a __block variable and has no mutable members,
+        // emit it as a global instead.
         if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstQualified() &&
-            !NRVO && !isByRef) {
+            !NRVO && !isByRef && Ty->isLiteralType()) {
           EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
 
           emission.Address = 0; // signal this condition to later callbacks
index 1fc3deba41b3fc30f34faece2fed66b28f38c9b1..aa77d5c6c031366bf30a1e5ce0249afdbc2213fc 100644 (file)
@@ -45,3 +45,14 @@ namespace test2 {
 // We don't expect to fold this in the frontend, but make sure it doesn't crash.
 // CHECK: @PR9558 = global float 0.000000e+0
 float PR9558 = reinterpret_cast<const float&>("asd");
+
+// An initialized const automatic variable cannot be promoted to a constant
+// global if it has a mutable member.
+struct MutableMember {
+  mutable int n;
+};
+int writeToMutable() {
+  // CHECK-NOT: {{.*}}MM{{.*}} = {{.*}}constant
+  const MutableMember MM = { 0 };
+  return ++MM.n;
+}