From: Eli Friedman Date: Tue, 11 Jun 2013 21:48:11 +0000 (+0000) Subject: Correctly handle designated initializers which modify an array initialized X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=188ddb14a82792f2d9405706ae38fccb79a066fd;p=clang Correctly handle designated initializers which modify an array initialized 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 . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183791 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 7d73e0890e..4d6eaa45c4 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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(SubExpr)) { + // Get the length of the string. + uint64_t StrLen = SL->getLength(); + if (cast(AT)->getSize().ult(StrLen)) + StrLen = cast(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(SubExpr); + std::string Str; + Context.getObjCEncodingForType(E->getEncodedType(), Str); + + // Get the length of the string. + uint64_t StrLen = Str.size(); + if (cast(AT)->getSize().ult(StrLen)) + StrLen = cast(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 && diff --git a/test/CodeGen/designated-initializers.c b/test/CodeGen/designated-initializers.c index 6561ce56d8..b41898600b 100644 --- a/test/CodeGen/designated-initializers.c +++ b/test/CodeGen/designated-initializers.c @@ -52,6 +52,36 @@ struct ds ds7 = { .b = 3 }; + +// +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 index 0000000000..80dfdf3602 --- /dev/null +++ b/test/CodeGenObjC/designated-initializers.m @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s + +// +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