beanz created this revision.
beanz added reviewers: aaron.ballman, bogner, rnk, MaskRay, void.
Herald added a subscriber: StephenFan.
Herald added a reviewer: NoQ.
Herald added a project: All.
beanz requested review of this revision.
Herald added a project: clang.

Sometimes a default-initialized value isn't really properly
initialized. In most cases these are handled with assertions, but...
what if we could annotate our code to allow the compiler to detect
cases where "uninitialized" user-defined types get used.

Enter yolo, woot and kaboom!
(proper names pending)

The `yolo` attribute denotes a constructor as creating an
"uninitialized" variable.

The `woot` attribute appliest to member functions noting that they
initialize the base object.

The `kaboom` attribute applies to member functions noting that they
must have an initialized base object.

These additional annotations ensure that at least one `woot` function
must be called on an object initialized with a `yolo` constructor
before any `kaboom` functions can be called otherwise a diagnostic will
be issued via the standard -Wuninitialized diagnostics.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130055

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/lib/Analysis/UninitializedValues.cpp
  clang/test/Sema/uninit-attribute.cpp

Index: clang/test/Sema/uninit-attribute.cpp
===================================================================
--- /dev/null
+++ 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;
+}
Index: clang/lib/Analysis/UninitializedValues.cpp
===================================================================
--- clang/lib/Analysis/UninitializedValues.cpp
+++ 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<KABOOMAttr>())
+      classify(CE->getImplicitObjectArgument(), Use);
+    if (CE->getMethodDecl()->hasAttr<WOOTAttr>())
+      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<CXXConstructExpr>(VD->getInit())) 
+        if (CE->getConstructor()->hasAttr<YOLOAttr>())
+          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<CXXConstructExpr>(VD->getInit())) 
+          if (CE->getConstructor()->hasAttr<YOLOAttr>())
+           vals[VD] = Uninitialized;
       } else {
         // No initializer: the variable is now uninitialized. This matters
         // for cases like:
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ 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.
+  }];
+}
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ 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;
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to