[pkg-d-commits] [ldc] 13/149: Back off on what we consider as "constant literals": (some) dynamic array literals are not-const because they are expected to be newly allocated. (#1927)

Matthias Klumpp mak at moszumanska.debian.org
Sun Apr 23 22:36:53 UTC 2017


This is an automated email from the git hooks/post-receive script.

mak pushed a commit to annotated tag v1.2.0
in repository ldc.

commit 0f2d594ae56a87b95053a052e1bbdfb825733177
Author: Johan Engelen <jbc.engelen at gmail.com>
Date:   Tue Dec 20 11:26:25 2016 +0100

    Back off on what we consider as "constant literals": (some) dynamic array literals are not-const because they are expected to be newly allocated. (#1927)
    
    Resolves #1924
---
 gen/arrays.cpp                       | 15 +++++--
 gen/arrays.h                         |  5 ++-
 gen/toir.cpp                         |  2 +-
 tests/codegen/array_literal_gh1924.d | 83 ++++++++++++++++++++++++++++++++++++
 4 files changed, 100 insertions(+), 5 deletions(-)

diff --git a/gen/arrays.cpp b/gen/arrays.cpp
index da87788..4e9a12c 100644
--- a/gen/arrays.cpp
+++ b/gen/arrays.cpp
@@ -496,7 +496,7 @@ Expression *indexArrayLiteral(ArrayLiteralExp *ale, unsigned idx) {
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool isConstLiteral(Expression *e) {
+bool isConstLiteral(Expression *e, bool immutableType) {
   // We have to check the return value of isConst specifically for '1',
   // as SymOffExp is classified as '2' and the address of a local variable is
   // not an LLVM constant.
@@ -506,8 +506,17 @@ bool isConstLiteral(Expression *e) {
   switch (e->op) {
   case TOKarrayliteral: {
     auto ale = static_cast<ArrayLiteralExp *>(e);
+
+    if (!immutableType) {
+      // If dynamic array: assume not constant because the array is expected to
+      // be newly allocated. See GH 1924.
+      Type *arrayType = ale->type->toBasetype();
+      if (arrayType->ty == Tarray)
+        return false;
+    }
+
     for (auto el : *ale->elements) {
-      if (!isConstLiteral(el ? el : ale->basis))
+      if (!isConstLiteral(el ? el : ale->basis, immutableType))
         return false;
     }
   } break;
@@ -517,7 +526,7 @@ bool isConstLiteral(Expression *e) {
     if (sle->sd->isNested())
       return false;
     for (auto el : *sle->elements) {
-      if (el && !isConstLiteral(el))
+      if (el && !isConstLiteral(el, immutableType))
         return false;
     }
   } break;
diff --git a/gen/arrays.h b/gen/arrays.h
index 3aa939b..f8cddf3 100644
--- a/gen/arrays.h
+++ b/gen/arrays.h
@@ -42,7 +42,10 @@ LLConstant *DtoConstSlice(LLConstant *dim, LLConstant *ptr,
 Expression *indexArrayLiteral(ArrayLiteralExp *ale, unsigned idx);
 
 /// Returns whether the array literal can be evaluated to a (LLVM) constant.
-bool isConstLiteral(Expression *e);
+/// immutableType indicates whether the literal is used to initialize an
+/// immutable type, in which case allocated dynamic arrays are considered
+/// constant too.
+bool isConstLiteral(Expression *e, bool immutableType = false);
 
 /// Returns the constant for the given array literal expression.
 llvm::Constant *arrayLiteralToConst(IRState *p, ArrayLiteralExp *ale);
diff --git a/gen/toir.cpp b/gen/toir.cpp
index c6ecd29..e2fe773 100644
--- a/gen/toir.cpp
+++ b/gen/toir.cpp
@@ -2253,7 +2253,7 @@ public:
       result = new DSliceValue(e->type, DtoConstSize_t(0),
                                getNullPtr(getPtrToType(llElemType)));
     } else if (dyn) {
-      if (arrayType->isImmutable() && isConstLiteral(e)) {
+      if (arrayType->isImmutable() && isConstLiteral(e, true)) {
         llvm::Constant *init = arrayLiteralToConst(p, e);
         auto global = new llvm::GlobalVariable(
             gIR->module, init->getType(), true,
diff --git a/tests/codegen/array_literal_gh1924.d b/tests/codegen/array_literal_gh1924.d
new file mode 100644
index 0000000..88b8b85
--- /dev/null
+++ b/tests/codegen/array_literal_gh1924.d
@@ -0,0 +1,83 @@
+// RUN: %ldc -c -O3 -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
+// RUN: %ldc -d-version=RUN -run %s
+
+// CHECK-LABEL: define{{.*}} @{{.*}}simple2d
+auto simple2d()
+{
+    // CHECK: _d_newarrayU
+    // CHECK: _d_newarrayU
+    // CHECK-NOT: _d_newarrayU
+    // CHECK: ret {
+    return [[1.0]];
+}
+
+// CHECK-LABEL: define{{.*}} @{{.*}}make3d
+auto make3d()
+{
+    // CHECK: _d_newarrayU
+    // CHECK: _d_newarrayU
+    // CHECK-NOT: _d_newarrayU
+    int[][1][] a = [[[1]]];
+    // CHECK: ret {
+    return a;
+}
+
+struct S
+{
+    auto arr = [[321]];
+}
+
+// CHECK-LABEL: define{{.*}} @{{.*}}makeS
+auto makeS()
+{
+    // CHECK: _d_newarrayU
+    // CHECK: _d_newarrayU
+    // CHECK-NOT: _d_newarrayU
+    // CHECK: ret
+    return S();
+}
+
+mixin template A()
+{
+    auto a = [1, 2, 3];
+    auto b = [[1, 2, 3]];
+}
+
+version (RUN)
+{
+    void main()
+    {
+        {
+            auto a = simple2d();
+            auto b = simple2d();
+            assert(a.ptr !is b.ptr);
+            assert(a[0].ptr !is b[0].ptr);
+        }
+        {
+            auto a = make3d();
+            auto b = make3d();
+            assert(a.ptr !is b.ptr);
+            assert(a[0].ptr !is b[0].ptr);
+        }
+        {
+            enum e = [[1.0]];
+            auto a = e;
+            auto b = e;
+            assert(a.ptr !is b.ptr);
+            assert(a[0].ptr !is b[0].ptr);
+        }
+        {
+            auto a = makeS();
+            auto b = makeS();
+            assert(a.arr.ptr !is b.arr.ptr);
+            assert(a.arr[0].ptr !is b.arr[0].ptr);
+        }
+        {
+            mixin A!() a0;
+            mixin A!() a1;
+            assert(a0.a.ptr !is a1.a.ptr);
+            assert(a0.b.ptr !is a1.b.ptr);
+            assert(a0.b[0].ptr !is a1.b[0].ptr);
+        }
+    }
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-d/ldc.git



More information about the pkg-d-commits mailing list