Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3960,7 +3960,7 @@ def Uninitialized : InheritableAttr { let Spellings = [Clang<"uninitialized", 0>]; - let Subjects = SubjectList<[LocalVar]>; + let Subjects = SubjectList<[LocalVar, Record]>; let PragmaAttributeSupport = 1; let Documentation = [UninitializedDocs]; } Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -5785,8 +5785,10 @@ The command-line parameter ``-ftrivial-auto-var-init=*`` can be used to initialize trivial automatic stack variables. By default, trivial automatic stack variables are uninitialized. This attribute is used to override the -command-line parameter, forcing variables to remain uninitialized. It has no -semantic meaning in that using uninitialized values is undefined behavior, +command-line parameter, forcing variables to remain uninitialized. +When set on a struct or class, all stack variables of this type are affected. + +It has no semantic meaning in that using uninitialized values is undefined behavior, it rather documents the programmer's intent. }]; } Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -1905,13 +1905,17 @@ const Address Loc = locIsByrefHeader ? emission.getObjectAddress(*this) : emission.Addr; - // Note: constexpr already initializes everything correctly. - LangOptions::TrivialAutoVarInitKind trivialAutoVarInit = - (D.isConstexpr() - ? LangOptions::TrivialAutoVarInitKind::Uninitialized - : (D.getAttr() - ? LangOptions::TrivialAutoVarInitKind::Uninitialized - : getContext().getLangOpts().getTrivialAutoVarInit())); + LangOptions::TrivialAutoVarInitKind trivialAutoVarInit; + if (D.isConstexpr()) { + // Note: constexpr already initializes everything correctly. + trivialAutoVarInit = LangOptions::TrivialAutoVarInitKind::Uninitialized; + } else if (D.hasAttr()) + trivialAutoVarInit = LangOptions::TrivialAutoVarInitKind::Uninitialized; + else if (const auto *RecordTy = D.getType()->getAsRecordDecl(); + RecordTy && RecordTy->hasAttr()) + trivialAutoVarInit = LangOptions::TrivialAutoVarInitKind::Uninitialized; + else + trivialAutoVarInit = getContext().getLangOpts().getTrivialAutoVarInit(); auto initializeWhatIsTechnicallyUninitialized = [&](Address Loc) { if (trivialAutoVarInit == Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -8457,8 +8457,10 @@ } static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - assert(cast(D)->getStorageDuration() == SD_Automatic && - "uninitialized is only valid on automatic duration variables"); + assert((isa(D) || + (cast(D)->getStorageDuration() == SD_Automatic)) && + "uninitialized is only valid on automatic duration variables and " + "record type"); D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL)); } Index: clang/test/CodeGenCXX/trivial-auto-var-init-attribute.cpp =================================================================== --- clang/test/CodeGenCXX/trivial-auto-var-init-attribute.cpp +++ clang/test/CodeGenCXX/trivial-auto-var-init-attribute.cpp @@ -38,4 +38,24 @@ } #pragma clang attribute pop +struct [[clang::uninitialized]] uninitialized_record { + int i; +}; + +// UNINIT-LABEL: test_record_attribute_uninitialized( +// UNINIT: alloca +// UNINIT-NEXT: call void +// ZERO-LABEL: test_record_attribute_uninitialized( +// ZERO: alloca +// ZERO-NOT: !annotation +// ZERO-NEXT: call void +// PATTERN-LABEL: test_record_attribute_uninitialized( +// PATTERN: alloca +// PATTERN-NOT: !annotation +// PATTERN-NEXT: call void +void test_record_attribute_uninitialized() { + uninitialized_record some; + used(some); +} + } // extern "C" Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -188,7 +188,7 @@ // CHECK-NEXT: TargetVersion (SubjectMatchRule_function) // CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member) // CHECK-NEXT: TrivialABI (SubjectMatchRule_record) -// CHECK-NEXT: Uninitialized (SubjectMatchRule_variable_is_local) +// CHECK-NEXT: Uninitialized (SubjectMatchRule_variable_is_local, SubjectMatchRule_record) // CHECK-NEXT: UnsafeBufferUsage (SubjectMatchRule_function) // CHECK-NEXT: UseHandle (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: VecReturn (SubjectMatchRule_record) Index: clang/test/Sema/attr-uninitialized.c =================================================================== --- clang/test/Sema/attr-uninitialized.c +++ clang/test/Sema/attr-uninitialized.c @@ -18,4 +18,4 @@ 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)); Index: clang/test/SemaCXX/constant-expression-cxx14.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx14.cpp +++ clang/test/SemaCXX/constant-expression-cxx14.cpp @@ -850,6 +850,13 @@ ({ if (true) {} }); // expected-note {{not supported}} return 0; } + + // Make sure the uninitialized attribute does not silent constant expression + // warnings. + constexpr int i() { + return ({ __attribute__((uninitialized)) int n; n; }); // expected-note {{read of uninitialized object}} + } + static_assert(i() == 0, ""); // expected-error {{constant expression}} expected-note {{in call}} } namespace VirtualFromBase { Index: clang/test/SemaCXX/constant-expression-cxx2a.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -1362,6 +1362,9 @@ static_assert(&zti == &typeid(Y)); } +struct __attribute__((uninitialized)) j { int v; constexpr j() {}}; +static_assert(j().v == 0, ""); // expected-error {{constant expression}} expected-note {{read of uninitialized object is not allowed in a constant expression}} + namespace PR45133 { struct A { long x; };