diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3473,7 +3473,7 @@ def Uninitialized : InheritableAttr { let Spellings = [Clang<"uninitialized", 0>]; - let Subjects = SubjectList<[LocalVar]>; + let Subjects = SubjectList<[Var]>; let Documentation = [UninitializedDocs]; } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -249,7 +249,8 @@ // variables cannot have an initializer. llvm::Constant *Init = nullptr; if (Ty.getAddressSpace() == LangAS::opencl_local || - D.hasAttr()) + D.hasAttr() || + D.hasAttr()) Init = llvm::UndefValue::get(LTy); else Init = EmitNullConstant(Ty); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3943,9 +3943,12 @@ // left undefined. bool IsHIPPinnedShadowVar = getLangOpts().CUDAIsDevice && D->hasAttr(); + bool IsUninitializedVar = D->hasAttr(); if (getLangOpts().CUDA && (IsCUDASharedVar || IsCUDAShadowVar || IsHIPPinnedShadowVar)) Init = llvm::UndefValue::get(getTypes().ConvertType(ASTTy)); + else if (IsUninitializedVar) + Init = llvm::UndefValue::get(getTypes().ConvertType(ASTTy)); else if (!InitExpr) { // This is a tentative definition; tentative definitions are // implicitly initialized with { 0 }. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6501,8 +6501,6 @@ } static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - assert(cast(D)->getStorageDuration() == SD_Automatic && - "uninitialized is only valid on automatic duration variables"); D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL)); } diff --git a/clang/test/CodeGenCXX/attribute_uninitialized.cpp b/clang/test/CodeGenCXX/attribute_uninitialized.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/attribute_uninitialized.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++11 -emit-llvm -o - %s | FileCheck %s + +// CHECK: @_ZZ4funcvE4data = internal global i32 undef +int* func(void) +{ + static int data [[clang::uninitialized]]; + return &data; +} + +// No code emitted +extern int extern_unhelpful_but_harmless [[clang::uninitialized]]; + +// CHECK: @tentative = global i32 undef +int tentative [[clang::uninitialized]]; + +// CHECK: @_ZL16tentative_static = internal global i32 undef +static int tentative_static [[clang::uninitialized]] __attribute__((used)); + +// CHECK: @nominally_zero_init = global i32 undef +int nominally_zero_init [[clang::uninitialized]] = 0; + +// CHECK: @nominally_value_init = global i32 undef +int nominally_value_init [[clang::uninitialized]] = 4; + +class trivial +{ + float x; +}; + +// CHECK: @ut = global %class.trivial undef +trivial ut [[clang::uninitialized]]; // claims zero init + +struct nontrivial +{ + nontrivial() : x(3.14) {} + double x; +}; + +// CHECK: @unt = global %struct.nontrivial undef +nontrivial unt [[clang::uninitialized]]; diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -148,6 +148,7 @@ // CHECK-NEXT: Target (SubjectMatchRule_function) // CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member) // CHECK-NEXT: TrivialABI (SubjectMatchRule_record) +// CHECK-NEXT: Uninitialized (SubjectMatchRule_variable) // CHECK-NEXT: UseHandle (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: VecReturn (SubjectMatchRule_record) // CHECK-NEXT: VecTypeHint (SubjectMatchRule_function) diff --git a/clang/test/Sema/attr-uninitialized.c b/clang/test/Sema/attr-uninitialized.c --- a/clang/test/Sema/attr-uninitialized.c +++ b/clang/test/Sema/attr-uninitialized.c @@ -6,16 +6,11 @@ void bad() { int im_bad __attribute((uninitialized("zero"))); // expected-error {{'uninitialized' attribute takes no arguments}} - static int im_baaad __attribute((uninitialized)); // expected-warning {{'uninitialized' attribute only applies to local variables}} } -extern int come_on __attribute((uninitialized)); // expected-warning {{'uninitialized' attribute only applies to local variables}} -int you_know __attribute((uninitialized)); // expected-warning {{'uninitialized' attribute only applies to local variables}} -static int and_the_whole_world_has_to __attribute((uninitialized)); // expected-warning {{'uninitialized' attribute only applies to local variables}} - -void answer_right_now() __attribute((uninitialized)) {} // expected-warning {{'uninitialized' attribute only applies to local variables}} -void just_to_tell_you_once_again(__attribute((uninitialized)) int whos_bad) {} // expected-warning {{'uninitialized' attribute only applies to local variables}} +void answer_right_now() __attribute((uninitialized)) {} // expected-warning {{'uninitialized' attribute only applies to variables}} +void just_to_tell_you_once_again(__attribute((uninitialized)) int whos_bad) {} struct TheWordIsOut { - __attribute((uninitialized)) int youre_doin_wrong; // expected-warning {{'uninitialized' attribute only applies to local variables}} -} __attribute((uninitialized)); // expected-warning {{'uninitialized' attribute only applies to local variables}} + __attribute((uninitialized)) int youre_doin_wrong; // expected-warning {{'uninitialized' attribute only applies to variables}} +} __attribute((uninitialized)); // expected-warning {{'uninitialized' attribute only applies to variables}}