forked from OSchip/llvm-project
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 <rdar://problem/10465114>. llvm-svn: 183791
This commit is contained in:
parent
bd9e549e21
commit
1f16b743d9
|
@ -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 &&
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue