]> granicus.if.org Git - clang/commitdiff
Correctly handle designated initializers which modify an array initialized
authorEli Friedman <eli.friedman@gmail.com>
Tue, 11 Jun 2013 21:48:11 +0000 (21:48 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Tue, 11 Jun 2013 21:48:11 +0000 (21:48 +0000)
with a string.  This case is sort of tricky because we can't modify the
StringLiteral used to represent such initializers.
We are forced to decompose the string into individual characters.

Fixes <rdar://problem/10465114>.

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

lib/Sema/SemaInit.cpp
test/CodeGen/designated-initializers.c
test/CodeGenObjC/designated-initializers.m [new file with mode: 0644]

index 7d73e0890ec9bdd668c3f7982148f405d3bf23e7..4d6eaa45c4125eaa2e1944f855744c47d5067285 100644 (file)
@@ -2075,6 +2075,64 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
     DesignatedEndIndex.setIsUnsigned(true);
   }
 
+  if (!VerifyOnly && StructuredList->isStringLiteralInit()) {
+    // We're modifying a string literal init; we have to decompose the string
+    // so we can modify the individual characters.
+    ASTContext &Context = SemaRef.Context;
+    Expr *SubExpr = StructuredList->getInit(0)->IgnoreParens();
+
+    // Compute the character type
+    QualType CharTy = AT->getElementType();
+
+    // Compute the type of the integer literals.
+    QualType PromotedCharTy = CharTy;
+    if (CharTy->isPromotableIntegerType())
+      PromotedCharTy = Context.getPromotedIntegerType(CharTy);
+    unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy);
+
+    if (StringLiteral *SL = dyn_cast<StringLiteral>(SubExpr)) {
+      // Get the length of the string.
+      uint64_t StrLen = SL->getLength();
+      if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen))
+        StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue();
+      StructuredList->resizeInits(Context, StrLen);
+
+      // Build a literal for each character in the string, and put them into
+      // the init list.
+      for (unsigned i = 0, e = StrLen; i != e; ++i) {
+        llvm::APInt CodeUnit(PromotedCharTyWidth, SL->getCodeUnit(i));
+        Expr *Init = new (Context) IntegerLiteral(
+            Context, CodeUnit, PromotedCharTy, SourceLocation());
+        if (CharTy != PromotedCharTy)
+          Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast,
+                                          Init, 0, VK_RValue);
+        StructuredList->updateInit(Context, i, Init);
+      }
+    } else {
+      ObjCEncodeExpr *E = cast<ObjCEncodeExpr>(SubExpr);
+      std::string Str;
+      Context.getObjCEncodingForType(E->getEncodedType(), Str);
+
+      // Get the length of the string.
+      uint64_t StrLen = Str.size();
+      if (cast<ConstantArrayType>(AT)->getSize().ult(StrLen))
+        StrLen = cast<ConstantArrayType>(AT)->getSize().getZExtValue();
+      StructuredList->resizeInits(Context, StrLen);
+
+      // Build a literal for each character in the string, and put them into
+      // the init list.
+      for (unsigned i = 0, e = StrLen; i != e; ++i) {
+        llvm::APInt CodeUnit(PromotedCharTyWidth, Str[i]);
+        Expr *Init = new (Context) IntegerLiteral(
+            Context, CodeUnit, PromotedCharTy, SourceLocation());
+        if (CharTy != PromotedCharTy)
+          Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast,
+                                          Init, 0, VK_RValue);
+        StructuredList->updateInit(Context, i, Init);
+      }
+    }
+  }
+
   // Make sure that our non-designated initializer list has space
   // for a subobject corresponding to this array element.
   if (!VerifyOnly &&
index 6561ce56d823976e480421bcc376480d301a7d64..b41898600b208f824ac7948ae5a707427009480f 100644 (file)
@@ -52,6 +52,36 @@ struct ds ds7 = {
   .b = 3
 };
 
+
+// <rdar://problem/10465114>
+struct overwrite_string_struct1 {
+  __typeof(L"foo"[0]) L[6];
+  int M;
+} overwrite_string1[] = { { { L"foo" }, 1 }, [0].L[2] = L'x'};
+// CHECK: [6 x i32] [i32 102, i32 111, i32 120, i32 0, i32 0, i32 0], i32 1
+struct overwrite_string_struct2 {
+  char L[6];
+  int M;
+} overwrite_string2[] = { { { "foo" }, 1 }, [0].L[2] = 'x'};
+// CHECK: [6 x i8] c"fox\00\00\00", i32 1
+struct overwrite_string_struct3 {
+  char L[3];
+  int M;
+} overwrite_string3[] = { { { "foo" }, 1 }, [0].L[2] = 'x'};
+// CHECK: [3 x i8] c"fox", i32 1
+struct overwrite_string_struct4 {
+  char L[3];
+  int M;
+} overwrite_string4[] = { { { "foobar" }, 1 }, [0].L[2] = 'x'};
+// CHECK: [3 x i8] c"fox", i32 1
+struct overwrite_string_struct5 {
+  char L[6];
+  int M;
+} overwrite_string5[] = { { { "foo" }, 1 }, [0].L[4] = 'y'};
+// CHECK: [6 x i8] c"foo\00y\00", i32 1
+
+
+
 void test1(int argc, char **argv)
 {
   // CHECK: internal global %struct.foo { i8* null, i32 1024 }
diff --git a/test/CodeGenObjC/designated-initializers.m b/test/CodeGenObjC/designated-initializers.m
new file mode 100644 (file)
index 0000000..80dfdf3
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+// <rdar://problem/10465114>
+struct overwrite_string_struct {
+  char L[3];
+  int M;
+} overwrite_string[] = { { { @encode(void**) }, 1 }, [0].L[1] = 'x'};
+// CHECK: [3 x i8] c"^xv", i32 1