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 @@ -4047,3 +4047,24 @@ let Subjects = SubjectList<[Function]>; let Documentation = [FunctionReturnThunksDocs]; } + +def YOLO : InheritableAttr { + let Spellings = [CXX11<"clang", "yolo">]; + let Subjects = SubjectList<[NonStaticCXXMethod]>; + let Documentation = [YOLODocs]; + let SimpleHandler = 1; +} + +def WOOT : InheritableAttr { + let Spellings = [CXX11<"clang", "woot">]; + let Subjects = SubjectList<[NonStaticCXXMethod]>; + let Documentation = [WOOTDocs]; + let SimpleHandler = 1; +} + +def KABOOM : InheritableAttr { + let Spellings = [CXX11<"clang", "kaboom">]; + let Subjects = SubjectList<[NonStaticCXXMethod]>; + let Documentation = [KABOOMDocs]; + let SimpleHandler = 1; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -6631,3 +6631,34 @@ As such, this function attribute is currently only supported on X86 targets. }]; } + + +def YOLODocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The clang attribute ``clang::yolo`` allows designating a constructor as +non-initializing for -Wuninitialized analysis purposes. It works in conjuction +with the ``clang::woot`` and ``clang::kaboom`` attributes to describe which +methods of an object are initialization and usage methods. + }]; +} + +def WOOTDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The clang attribute ``clang::woot`` allows designating a method as initializing +for -Wuninitialized analysis purposes. It works in conjuction with the +``clang::woot`` and ``clang::kaboom`` attributes to describe which methods of +an object are initialization and usage methods. + }]; +} + +def KABOOMDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The clang attribute ``clang::kaboom`` allows designating a method as using for +-Wuninitialized analysis purposes. It works in conjuction with the +``clang::woot`` and ``clang::kaboom`` attributes to describe which methods of an +object are initialization and usage methods. + }]; +} diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp --- a/clang/lib/Analysis/UninitializedValues.cpp +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -291,6 +291,12 @@ void VisitCallExpr(CallExpr *CE); void VisitCastExpr(CastExpr *CE); void VisitOMPExecutableDirective(OMPExecutableDirective *ED); + void VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) { + if (CE->getMethodDecl()->hasAttr()) + classify(CE->getImplicitObjectArgument(), Use); + if (CE->getMethodDecl()->hasAttr()) + classify(CE->getImplicitObjectArgument(), Init); + } void operator()(Stmt *S) { Visit(S); } @@ -304,6 +310,11 @@ if (!VD || !isTrackedVar(VD)) return Ignore; + if (VD->getInit()) + if (auto *CE = dyn_cast(VD->getInit())) + if (CE->getConstructor()->hasAttr()) + return Ignore; + return Init; } }; @@ -788,6 +799,9 @@ } else if (VD->getInit()) { // Treat the new variable as initialized. vals[VD] = Initialized; + if (auto *CE = dyn_cast(VD->getInit())) + if (CE->getConstructor()->hasAttr()) + vals[VD] = Uninitialized; } else { // No initializer: the variable is now uninitialized. This matters // for cases like: diff --git a/clang/test/Sema/uninit-attribute.cpp b/clang/test/Sema/uninit-attribute.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/uninit-attribute.cpp @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -Wuninitialized -fsyntax-only %s -verify + +class TaggedValue { + enum Kind { + Uninitialized = 0, + Integer, + Float + }; + Kind VK = Uninitialized; + + union { + int I; + float F; + }; +public: + + [[clang::yolo]] + TaggedValue() = default; + + TaggedValue(TaggedValue&) = default; + + void doesNothing() {} + + [[clang::woot]] + void set(float V) { + VK= Float; + F = V; + } + + [[clang::woot]] + void set(int V) { + VK= Integer; + I = V; + } + + [[clang::kaboom]] + operator float() { + return F; + } + + [[clang::kaboom]] + operator int() { + return I; + } +}; + +int fn1(bool B) { + TaggedValue TV; // expected-note{{variable 'TV' is declared here}} + TV.doesNothing(); + if (B) // expected-warning{{variable 'TV' is used uninitialized whenever 'if' condition is false}} \ + // expected-note{{remove the 'if' if its condition is always true}} + TV.set(1.0f); + + return (int)TV; // expected-note{{uninitialized use occurs here}} +} + +int fn2() { + TaggedValue TV ;// expected-note{{variable 'TV' is declared here}} + + return (int)TV; // expected-warning{{variable 'TV' is uninitialized when used here}} +} + +// No warnings expected in this example +int fn3(bool B) { + TaggedValue TV; + if (B) + TV.set(1.0f); + else + TV.set(1); + + return (int)TV; +}