Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -167,6 +167,7 @@ COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro") COMPATIBLE_LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math") +COMPATIBLE_LANGOPT(StrictAliasing , 1, 0, "Using strict aliasing rules") BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars") Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -6826,21 +6826,19 @@ // struct Foo *F = (struct Foo *)malloc(sizeof(struct Foo) + strlen(Bar)); // strcpy(&F->c[0], Bar); // - // So, if we see that we're examining an array at the end of a struct with an - // unknown base, we give up instead of breaking code that behaves this way. - // Note that we only do this when Type=1, because Type=3 is a lower bound, so - // answering conservatively is fine. + // So, if we see that we're examining a 1-length (or 0-length) array at the + // end of a struct with an unknown base, we give up instead of breaking code + // that behaves this way. Note that we only do this when Type=1, because + // Type=3 is a lower bound, so answering conservatively is fine. // - // We used to be a bit more aggressive here; we'd only be conservative if the - // array at the end was flexible, or if it had 0 or 1 elements. This broke - // some common standard library extensions (PR30346), but was otherwise - // seemingly fine. It may be useful to reintroduce this behavior with some - // sort of whitelist. OTOH, it seems that GCC is always conservative with the - // last element in structs (if it's an array), so our current behavior is more - // compatible than a whitelisting approach would be. + // This check is relaxed a bit if strict aliasing is off, since there's a + // nontrivial amount of code that treats the array size at the end of a struct + // as a suggestion, rather than a constraint (PR30346). + bool RelaxedEndOfObjectChecks = !Info.Ctx.getLangOpts().StrictAliasing; if (End.InvalidBase && SubobjectOnly && Type == 1 && End.Designator.Entries.size() == End.Designator.MostDerivedPathLength && End.Designator.MostDerivedIsArrayElement && + (RelaxedEndOfObjectChecks || End.Designator.MostDerivedArraySize < 2) && isDesignatorAtObjectEnd(Info.Ctx, End)) return false; Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -2170,6 +2170,8 @@ Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); + Opts.StrictAliasing = !Args.hasArg(OPT_relaxed_aliasing); + Opts.RetainCommentsFromSystemHeaders = Args.hasArg(OPT_fretain_comments_from_system_headers); Index: test/CodeGen/object-size.c =================================================================== --- test/CodeGen/object-size.c +++ test/CodeGen/object-size.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefixes=STRICT,CHECK +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - 2>&1 -relaxed-aliasing | FileCheck %s --check-prefixes=NOSTRICT,CHECK #define strcpy(dest, src) \ ((__builtin_object_size(dest, 0) != -1ULL) \ @@ -276,7 +277,8 @@ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(&p->t[5], 0); - // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + // NOSTRICT: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + // STRICT: store i32 20 gi = __builtin_object_size(&p->t[5], 1); // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true) gi = __builtin_object_size(&p->t[5], 2); @@ -444,7 +446,8 @@ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(ss->snd, 0); - // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + // NOSTRICT: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + // STRICT: store i32 2 gi = __builtin_object_size(ss->snd, 1); // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true) gi = __builtin_object_size(ss->snd, 2); @@ -505,7 +508,8 @@ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(ds1[9].snd, 1); - // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + // NOSTRICT: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + // STRICT: store i32 2 gi = __builtin_object_size(&ss[9].snd[0], 1); // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) @@ -529,7 +533,8 @@ struct sockaddr *sa; // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) gi = __builtin_object_size(sa->sa_data, 0); - // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + // NOSTRICT: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false) + // STRICT: store i32 14 gi = __builtin_object_size(sa->sa_data, 1); // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true) gi = __builtin_object_size(sa->sa_data, 2); Index: test/CodeGen/pass-object-size.c =================================================================== --- test/CodeGen/pass-object-size.c +++ test/CodeGen/pass-object-size.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 | FileCheck %s --check-prefixes STRICT,CHECK +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - -relaxed-aliasing 2>&1 | FileCheck %s --check-prefixes NOSTRICT,CHECK typedef unsigned long size_t; @@ -59,8 +60,10 @@ // CHECK-LABEL: define void @test2 void test2(struct Foo *t) { - // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize - // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 [[VAR]]) + // NOSTRICT: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize + // NOSTRICT: call i32 @ObjectSize1(i8* %{{.*}}, i64 [[VAR]]) + // + // STRICT: call i32 @ObjectSize1(i8* %{{.*}}, i64 36) gi = ObjectSize1(&t->t[1]); // CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36) gi = ObjectSize3(&t->t[1]); @@ -169,8 +172,10 @@ // CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize0(&t[1].t[1]); - // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize - // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 [[VAR]]) + // NOSTRICT: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize + // NOSTRICT: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 [[VAR]]) + // + // STRICT: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36) gi = NoViableOverloadObjectSize1(&t[1].t[1]); // CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}}) gi = NoViableOverloadObjectSize2(&t[1].t[1]); @@ -276,8 +281,10 @@ // CHECK-LABEL: define void @test8 void test8(struct Foo *t) { - // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize - // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 [[VAR]]) + // NOSTRICT: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize + // NOSTRICT: call i32 @"\01Identity"(i8* %{{.*}}, i64 [[VAR]]) + // + // STRICT: call i32 @"\01Identity"(i8* %{{.*}}, i64 36) gi = AsmObjectSize1(&t[1].t[1]); // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36) gi = AsmObjectSize3(&t[1].t[1]);