[PATCH] D49910: [clang-tidy] Recognize [[clang::reinitializes]] attribute in bugprone-use-after-move

2018-08-13 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 160347.
mboehme added a comment.

Rebase to head.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49910

Files:
  clang-tidy/bugprone/UseAfterMoveCheck.cpp
  docs/clang-tidy/checks/bugprone-use-after-move.rst
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -107,6 +107,15 @@
   int i;
 };
 
+template 
+class AnnotatedContainer {
+public:
+  AnnotatedContainer();
+
+  void foo() const;
+  [[clang::reinitializes]] void clear();
+};
+
 

 // General tests.
 
@@ -898,6 +907,32 @@
   }
 }
 
+void reinitAnnotation() {
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj' used after it was
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.clear();
+obj.foo();
+  }
+  {
+// Calling clear() on a different object to the one that was moved is not
+// considered a reinitialization.
+AnnotatedContainer obj1, obj2;
+std::move(obj1);
+obj2.clear();
+obj1.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj1' used after it was
+// CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+  }
+}
+
 

 // Tests related to order of evaluation within expressions
 
Index: docs/clang-tidy/checks/bugprone-use-after-move.rst
===
--- docs/clang-tidy/checks/bugprone-use-after-move.rst
+++ docs/clang-tidy/checks/bugprone-use-after-move.rst
@@ -178,6 +178,9 @@
   - ``reset()`` is called on the variable and the variable is of type
 ``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``.
 
+  - A member function marked with the ``[[clang::reinitializes]]`` attribute is
+called on the variable.
+
 If the variable in question is a struct and an individual member variable of
 that struct is written to, the check does not consider this to be a
 reinitialization -- even if, eventually, all member variables of the struct are
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -308,6 +308,10 @@
cxxMemberCallExpr(
on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)),
callee(cxxMethodDecl(hasName("reset",
+   // Methods that have the [[clang::reinitializes]] attribute.
+   cxxMemberCallExpr(
+   on(DeclRefMatcher),
+   callee(cxxMethodDecl(hasAttr(clang::attr::Reinitializes,
// Passing variable to a function as a non-const pointer.
callExpr(forEachArgumentWithParam(
unaryOperator(hasOperatorName("&"),


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -107,6 +107,15 @@
   int i;
 };
 
+template 
+class AnnotatedContainer {
+public:
+  AnnotatedContainer();
+
+  void foo() const;
+  [[clang::reinitializes]] void clear();
+};
+
 
 // General tests.
 
@@ -898,6 +907,32 @@
   }
 }
 
+void reinitAnnotation() {
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj' used after it was
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.clear();
+obj.foo();
+  }
+  {
+// Calling clear() on a different object to the one that was moved is not
+// considered a reinitialization.
+AnnotatedContainer obj1, obj2;
+std::move(obj1);
+obj2.clear();
+obj1.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj1' used after it was
+// CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+  }
+}
+
 
 // Tests related to order of evaluation within expressions
 
Index: docs/clang-tidy/checks/bugprone-use-after-move.rst
===
--- docs/clang-tidy/checks/bugprone-use-after-move.rst
+++ docs/clang-tidy/checks/bugprone-use-after-move.rst
@@ -178,6 +178,9 @@
   - ``reset()`` is called on the variable and the variable is of type
 ``std::unique_ptr``, ``std::shared_ptr`` or ``std:

[PATCH] D49911: Summary:Add clang::reinitializes attribute

2018-08-13 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 160348.
mboehme marked 2 inline comments as done.
mboehme added a comment.

Rebase to head.


Repository:
  rC Clang

https://reviews.llvm.org/D49911

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  lib/Sema/SemaDeclAttr.cpp
  test/SemaCXX/attr-reinitializes.cpp


Index: test/SemaCXX/attr-reinitializes.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{'reinitializes' attribute 
only applies to non-static non-const member functions}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  __attribute__((reinitializes)) void gnu_foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+  [[clang::reinitializes("arg")]] void qux(); // expected-error 
{{'reinitializes' attribute takes no arguments}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6582,6 +6582,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  // Move semantics attribute.
+  case ParsedAttr::AT_Reinitializes:
+handleSimpleAttribute(S, D, AL);
+break;
   }
 }
 
Index: include/clang/Basic/AttrDocs.td
===
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -3458,3 +3458,31 @@
 corresponding line within the inlined callee.
   }];
 }
+
+def ReinitializesDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``reinitializes`` attribute can be applied to a non-static, non-const C++
+member function to indicate that this member function reinitializes the entire
+object to a known state, independent of the previous state of the object.
+
+This attribute can be interpreted by static analyzers that warn about uses of 
an
+object that has been left in an indeterminate state by a move operation. If a
+member function marked with the ``reinitializes`` attribute is called on a
+moved-from object, the analyzer can conclude that the object is no longer in an
+indeterminate state.
+
+A typical example where this attribute would be used is on functions that clear
+a container class:
+
+.. code-block:: c++
+
+  template 
+  class Container {
+  public:
+...
+[[clang::reinitializes]] void Clear();
+...
+  };
+  }];
+}
Index: include/clang/Basic/Attr.td
===
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -90,6 +90,11 @@
 [{!S->isBitField()}],
 "non-bit-field non-static data members">;
 
+def NonStaticNonConstCXXMethod
+: SubsetSubjectisStatic() && !S->isConst()}],
+"non-static non-const member functions">;
+
 def ObjCInstanceMethod : SubsetSubjectisInstanceMethod()}],
"Objective-C instance methods">;
@@ -2974,3 +2979,9 @@
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;
   let Documentation = [InternalLinkageDocs];
 }
+
+def Reinitializes : InheritableAttr {
+  let Spellings = [Clang<"reinitializes", 0>];
+  let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;
+  let Documentation = [ReinitializesDocs];
+}


Index: test/SemaCXX/attr-reinitializes.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{'reinitializes' attribute only applies to non-static non-const member functions}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  __attribute__((reinitializes)) void gnu_foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies to}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+  [[clang::reinitializes("arg")]] void qux(); // expected-error {{'reinitializes' attribute takes no arguments}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6582,6 +6582,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  // Move semantics attribute.
+  

[PATCH] D49910: [clang-tidy] Recognize [[clang::reinitializes]] attribute in bugprone-use-after-move

2018-08-13 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Thank you for the review!


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49910



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49911: Summary:Add clang::reinitializes attribute

2018-08-13 Thread Martin Böhme via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339569: Summary:Add clang::reinitializes attribute (authored 
by mboehme, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D49911?vs=160348&id=160351#toc

Repository:
  rC Clang

https://reviews.llvm.org/D49911

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  lib/Sema/SemaDeclAttr.cpp
  test/SemaCXX/attr-reinitializes.cpp


Index: include/clang/Basic/Attr.td
===
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -90,6 +90,11 @@
 [{!S->isBitField()}],
 "non-bit-field non-static data members">;
 
+def NonStaticNonConstCXXMethod
+: SubsetSubjectisStatic() && !S->isConst()}],
+"non-static non-const member functions">;
+
 def ObjCInstanceMethod : SubsetSubjectisInstanceMethod()}],
"Objective-C instance methods">;
@@ -2974,3 +2979,9 @@
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;
   let Documentation = [InternalLinkageDocs];
 }
+
+def Reinitializes : InheritableAttr {
+  let Spellings = [Clang<"reinitializes", 0>];
+  let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;
+  let Documentation = [ReinitializesDocs];
+}
Index: include/clang/Basic/AttrDocs.td
===
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -3458,3 +3458,31 @@
 corresponding line within the inlined callee.
   }];
 }
+
+def ReinitializesDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``reinitializes`` attribute can be applied to a non-static, non-const C++
+member function to indicate that this member function reinitializes the entire
+object to a known state, independent of the previous state of the object.
+
+This attribute can be interpreted by static analyzers that warn about uses of 
an
+object that has been left in an indeterminate state by a move operation. If a
+member function marked with the ``reinitializes`` attribute is called on a
+moved-from object, the analyzer can conclude that the object is no longer in an
+indeterminate state.
+
+A typical example where this attribute would be used is on functions that clear
+a container class:
+
+.. code-block:: c++
+
+  template 
+  class Container {
+  public:
+...
+[[clang::reinitializes]] void Clear();
+...
+  };
+  }];
+}
Index: test/SemaCXX/attr-reinitializes.cpp
===
--- test/SemaCXX/attr-reinitializes.cpp
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{'reinitializes' attribute 
only applies to non-static non-const member functions}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  __attribute__((reinitializes)) void gnu_foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+  [[clang::reinitializes("arg")]] void qux(); // expected-error 
{{'reinitializes' attribute takes no arguments}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6582,6 +6582,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  // Move semantics attribute.
+  case ParsedAttr::AT_Reinitializes:
+handleSimpleAttribute(S, D, AL);
+break;
   }
 }
 


Index: include/clang/Basic/Attr.td
===
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -90,6 +90,11 @@
 [{!S->isBitField()}],
 "non-bit-field non-static data members">;
 
+def NonStaticNonConstCXXMethod
+: SubsetSubjectisStatic() && !S->isConst()}],
+"non-static non-const member functions">;
+
 def ObjCInstanceMethod : SubsetSubjectisInstanceMethod()}],
"Objective-C instance methods">;
@@ -2974,3 +2979,9 @@
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;
   let Documentation = [InternalLinkageDocs];
 }
+
+def Reinitializes : InheritableAttr {
+  let Spellings = [Clang<"reinitializes", 0>];
+  let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;
+  let Documentation = [ReinitializesDocs];
+}
Index: include/clang/Basic/AttrDocs.td
===
--- include/clang

[PATCH] D49910: [clang-tidy] Recognize [[clang::reinitializes]] attribute in bugprone-use-after-move

2018-08-13 Thread Martin Böhme via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL339571: [clang-tidy] Recognize [[clang::reinitializes]] 
attribute in bugprone-use-after… (authored by mboehme, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D49910

Files:
  clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
  clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-use-after-move.rst
  clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp


Index: clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -308,6 +308,10 @@
cxxMemberCallExpr(
on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)),
callee(cxxMethodDecl(hasName("reset",
+   // Methods that have the [[clang::reinitializes]] attribute.
+   cxxMemberCallExpr(
+   on(DeclRefMatcher),
+   callee(cxxMethodDecl(hasAttr(clang::attr::Reinitializes,
// Passing variable to a function as a non-const pointer.
callExpr(forEachArgumentWithParam(
unaryOperator(hasOperatorName("&"),
Index: 
clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-use-after-move.rst
===
--- clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-use-after-move.rst
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-use-after-move.rst
@@ -178,6 +178,9 @@
   - ``reset()`` is called on the variable and the variable is of type
 ``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``.
 
+  - A member function marked with the ``[[clang::reinitializes]]`` attribute is
+called on the variable.
+
 If the variable in question is a struct and an individual member variable of
 that struct is written to, the check does not consider this to be a
 reinitialization -- even if, eventually, all member variables of the struct are
Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
@@ -107,6 +107,15 @@
   int i;
 };
 
+template 
+class AnnotatedContainer {
+public:
+  AnnotatedContainer();
+
+  void foo() const;
+  [[clang::reinitializes]] void clear();
+};
+
 

 // General tests.
 
@@ -898,6 +907,32 @@
   }
 }
 
+void reinitAnnotation() {
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj' used after it was
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.clear();
+obj.foo();
+  }
+  {
+// Calling clear() on a different object to the one that was moved is not
+// considered a reinitialization.
+AnnotatedContainer obj1, obj2;
+std::move(obj1);
+obj2.clear();
+obj1.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj1' used after it was
+// CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+  }
+}
+
 

 // Tests related to order of evaluation within expressions
 


Index: clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -308,6 +308,10 @@
cxxMemberCallExpr(
on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)),
callee(cxxMethodDecl(hasName("reset",
+   // Methods that have the [[clang::reinitializes]] attribute.
+   cxxMemberCallExpr(
+   on(DeclRefMatcher),
+   callee(cxxMethodDecl(hasAttr(clang::attr::Reinitializes,
// Passing variable to a function as a non-const pointer.
callExpr(forEachArgumentWithParam(
unaryOperator(hasOperatorName("&"),
Index: clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-use-after-move.rst
===
--- clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-use-after-move.rst
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-use-after-move.rst
@@ -178,6 +178,9 @@
   - ``reset()`` is called on the variable and the variable is of type
 ``std::un

[PATCH] D49910: Reviewers:

2018-07-27 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a subscriber: cfe-commits.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49910

Files:
  clang-tidy/bugprone/UseAfterMoveCheck.cpp
  docs/clang-tidy/checks/bugprone-use-after-move.rst
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -107,6 +107,15 @@
   int i;
 };
 
+template 
+class AnnotatedContainer {
+public:
+  AnnotatedContainer();
+
+  void foo() const;
+  [[clang::reinitializes]] void clear();
+};
+
 

 // General tests.
 
@@ -898,6 +907,32 @@
   }
 }
 
+void reinitAnnotation() {
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj' used after it was
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.clear();
+obj.foo();
+  }
+  {
+// Calling clear() on a different object to the one that was moved is not
+// considered a reinitialization.
+AnnotatedContainer obj1, obj2;
+std::move(obj1);
+obj2.clear();
+obj1.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj1' used after it was
+// CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+  }
+}
+
 

 // Tests related to order of evaluation within expressions
 
Index: docs/clang-tidy/checks/bugprone-use-after-move.rst
===
--- docs/clang-tidy/checks/bugprone-use-after-move.rst
+++ docs/clang-tidy/checks/bugprone-use-after-move.rst
@@ -178,6 +178,9 @@
   - ``reset()`` is called on the variable and the variable is of type
 ``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``.
 
+  - A member function marked with the ``[[clang::reinitializes]]`` attribute is
+called on the variable.
+
 If the variable in question is a struct and an individual member variable of
 that struct is written to, the check does not consider this to be a
 reinitialization -- even if, eventually, all member variables of the struct are
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -308,6 +308,10 @@
cxxMemberCallExpr(
on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)),
callee(cxxMethodDecl(hasName("reset",
+   // Methods that have the [[clang::reinitializes]] attribute.
+   cxxMemberCallExpr(
+   on(DeclRefMatcher),
+   callee(cxxMethodDecl(hasAttr(clang::attr::Reinitializes,
// Passing variable to a function as a non-const pointer.
callExpr(forEachArgumentWithParam(
unaryOperator(hasOperatorName("&"),


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -107,6 +107,15 @@
   int i;
 };
 
+template 
+class AnnotatedContainer {
+public:
+  AnnotatedContainer();
+
+  void foo() const;
+  [[clang::reinitializes]] void clear();
+};
+
 
 // General tests.
 
@@ -898,6 +907,32 @@
   }
 }
 
+void reinitAnnotation() {
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj' used after it was
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.clear();
+obj.foo();
+  }
+  {
+// Calling clear() on a different object to the one that was moved is not
+// considered a reinitialization.
+AnnotatedContainer obj1, obj2;
+std::move(obj1);
+obj2.clear();
+obj1.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj1' used after it was
+// CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+  }
+}
+
 
 // Tests related to order of evaluation within expressions
 
Index: docs/clang-tidy/checks/bugprone-use-after-move.rst
===
--- docs/clang-tidy/checks/bugprone-use-after-move.rst
+++ docs/clang-tidy/checks/bugprone-use-after-move.rst
@@ -178,6 +178,9 @@
   - ``reset()`` is called on the variable and the variable is of type
 ``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``.
 
+  

[PATCH] D49910: Reviewers:

2018-07-27 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 157669.
mboehme added a comment.

[clang-tidy] Recognize [[clang::reinitializes]] attribute in 
bugprone-use-after-move.

This allows member functions to be marked as reinitializing the object. After a 
moved-from object has been reinitialized, the check will no longer consider it  
to be in an indeterminate state.

I'll submit a patch for Clang in a moment that adds the attribute itself.

Reviewers:
aaron.ballman, ilya-biryukov

Subscribers:
cfe-commits


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49910

Files:
  clang-tidy/bugprone/UseAfterMoveCheck.cpp
  docs/clang-tidy/checks/bugprone-use-after-move.rst
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -107,6 +107,15 @@
   int i;
 };
 
+template 
+class AnnotatedContainer {
+public:
+  AnnotatedContainer();
+
+  void foo() const;
+  [[clang::reinitializes]] void clear();
+};
+
 

 // General tests.
 
@@ -898,6 +907,32 @@
   }
 }
 
+void reinitAnnotation() {
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj' used after it was
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.clear();
+obj.foo();
+  }
+  {
+// Calling clear() on a different object to the one that was moved is not
+// considered a reinitialization.
+AnnotatedContainer obj1, obj2;
+std::move(obj1);
+obj2.clear();
+obj1.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj1' used after it was
+// CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+  }
+}
+
 

 // Tests related to order of evaluation within expressions
 
Index: docs/clang-tidy/checks/bugprone-use-after-move.rst
===
--- docs/clang-tidy/checks/bugprone-use-after-move.rst
+++ docs/clang-tidy/checks/bugprone-use-after-move.rst
@@ -178,6 +178,9 @@
   - ``reset()`` is called on the variable and the variable is of type
 ``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``.
 
+  - A member function marked with the ``[[clang::reinitializes]]`` attribute is
+called on the variable.
+
 If the variable in question is a struct and an individual member variable of
 that struct is written to, the check does not consider this to be a
 reinitialization -- even if, eventually, all member variables of the struct are
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -308,6 +308,10 @@
cxxMemberCallExpr(
on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)),
callee(cxxMethodDecl(hasName("reset",
+   // Methods that have the [[clang::reinitializes]] attribute.
+   cxxMemberCallExpr(
+   on(DeclRefMatcher),
+   callee(cxxMethodDecl(hasAttr(clang::attr::Reinitializes,
// Passing variable to a function as a non-const pointer.
callExpr(forEachArgumentWithParam(
unaryOperator(hasOperatorName("&"),


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -107,6 +107,15 @@
   int i;
 };
 
+template 
+class AnnotatedContainer {
+public:
+  AnnotatedContainer();
+
+  void foo() const;
+  [[clang::reinitializes]] void clear();
+};
+
 
 // General tests.
 
@@ -898,6 +907,32 @@
   }
 }
 
+void reinitAnnotation() {
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj' used after it was
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+AnnotatedContainer obj;
+std::move(obj);
+obj.clear();
+obj.foo();
+  }
+  {
+// Calling clear() on a different object to the one that was moved is not
+// considered a reinitialization.
+AnnotatedContainer obj1, obj2;
+std::move(obj1);
+obj2.clear();
+obj1.foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'obj1' used after it was
+// CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+  }
+}
+
 
 // Tests related to order of evalu

[PATCH] D49911: Summary:Add clang::reinitializes attribute

2018-07-27 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a subscriber: cfe-commits.

This is for use by clang-tidy's bugprone-use-after-move check -- see
corresponding clang-tidy patch at https://reviews.llvm.org/D49910.


Repository:
  rC Clang

https://reviews.llvm.org/D49911

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  lib/Sema/SemaDeclAttr.cpp
  test/SemaCXX/attr-reinitializes.cpp


Index: test/SemaCXX/attr-reinitializes.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies 
to non-static non-const}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6539,6 +6539,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  // Move semantics attribute.
+  case ParsedAttr::AT_Reinitializes:
+handleSimpleAttribute(S, D, AL);
+break;
   }
 }
 
Index: include/clang/Basic/AttrDocs.td
===
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -3419,3 +3419,31 @@
 corresponding line within the inlined callee.
   }];
 }
+
+def ReinitializesDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``reinitializes`` attribute can be applied to a non-static, non-const C++
+member function to indicate that this member function reinitializes the entire
+object to a known state, independent of the previous state of the object.
+
+This attribute can be interpreted by static analyzers that warn about uses of 
an
+object that has been left in an indeterminate state by a move operation. If a
+member function marked with the ``reinitializes`` attribute is called on a
+moved-from object, the analyzer can conclude that the object is no longer in an
+indeterminate state.
+
+A typical example where this attribute would be used is on functions that clear
+a container class:
+
+.. code-block:: c++
+
+  template 
+  class Container {
+  public:
+...
+[[clang::reinitializes]] void Clear();
+...
+  };
+  }];
+}
Index: include/clang/Basic/Attr.td
===
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -90,6 +90,11 @@
 [{!S->isBitField()}],
 "non-bit-field non-static data members">;
 
+def NonStaticNonConstCXXMethod
+: SubsetSubjectisStatic() && !S->isConst()}],
+"non-static non-const member functions">;
+
 def ObjCInstanceMethod : SubsetSubjectisInstanceMethod()}],
"Objective-C instance methods">;
@@ -2935,3 +2940,9 @@
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;
   let Documentation = [InternalLinkageDocs];
 }
+
+def Reinitializes : InheritableAttr {
+  let Spellings = [CXX11<"clang", "reinitializes">];
+  let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;
+  let Documentation = [ReinitializesDocs];
+}


Index: test/SemaCXX/attr-reinitializes.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies to non-static non-const}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6539,6 +6539,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  // Move semantics attribute.
+  case ParsedAttr::AT_Reinitializes:
+handleSimpleAttribute(S, D, AL);
+break;
   }
 }
 
Index: include/clang/Basic/AttrDocs.td
===
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -3419,3 +3419,31 @@
 corresponding line within the inlined 

[PATCH] D49918: [clang-tidy] Sequence declaration in while statement before the condition

2018-07-27 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
mboehme added a reviewer: ilya-biryukov.
Herald added subscribers: cfe-commits, xazax.hun.

Fixes https://bugs.llvm.org/show_bug.cgi?id=36516.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49918

Files:
  clang-tidy/utils/ExprSequence.cpp
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1132,15 +1132,18 @@
   }
 }
 
-// If a variable is declared in an if statement, the declaration of the 
variable
-// (which is treated like a reinitialization by the check) is sequenced before
-// the evaluation of the condition (which constitutes a use).
-void ifStmtSequencesDeclAndCondition() {
+// If a variable is declared in an if or while statement, the declaration of 
the
+// variable (which is treated like a reinitialization by the check) is 
sequenced
+// before the evaluation of the condition (which constitutes a use).
+void ifAndWhileStmtSequencesDeclAndCondition() {
   for (int i = 0; i < 10; ++i) {
 if (A a = A()) {
   std::move(a);
 }
   }
+  while (A a = A()) {
+std::move(a);
+  }
 }
 
 namespace PR33020 {
Index: clang-tidy/utils/ExprSequence.cpp
===
--- clang-tidy/utils/ExprSequence.cpp
+++ clang-tidy/utils/ExprSequence.cpp
@@ -144,6 +144,12 @@
   // evaluation of the condition.
   if (S == TheIfStmt->getConditionVariableDeclStmt())
 return TheIfStmt->getCond();
+} else if (const auto *TheWhileStmt = dyn_cast(Parent)) {
+  // While statement: If a variable is declared inside the condition, the
+  // expression used to initialize the variable is sequenced before the
+  // evaluation of the condition.
+  if (S == TheWhileStmt->getConditionVariableDeclStmt())
+return TheWhileStmt->getCond();
 }
   }
 


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1132,15 +1132,18 @@
   }
 }
 
-// If a variable is declared in an if statement, the declaration of the variable
-// (which is treated like a reinitialization by the check) is sequenced before
-// the evaluation of the condition (which constitutes a use).
-void ifStmtSequencesDeclAndCondition() {
+// If a variable is declared in an if or while statement, the declaration of the
+// variable (which is treated like a reinitialization by the check) is sequenced
+// before the evaluation of the condition (which constitutes a use).
+void ifAndWhileStmtSequencesDeclAndCondition() {
   for (int i = 0; i < 10; ++i) {
 if (A a = A()) {
   std::move(a);
 }
   }
+  while (A a = A()) {
+std::move(a);
+  }
 }
 
 namespace PR33020 {
Index: clang-tidy/utils/ExprSequence.cpp
===
--- clang-tidy/utils/ExprSequence.cpp
+++ clang-tidy/utils/ExprSequence.cpp
@@ -144,6 +144,12 @@
   // evaluation of the condition.
   if (S == TheIfStmt->getConditionVariableDeclStmt())
 return TheIfStmt->getCond();
+} else if (const auto *TheWhileStmt = dyn_cast(Parent)) {
+  // While statement: If a variable is declared inside the condition, the
+  // expression used to initialize the variable is sequenced before the
+  // evaluation of the condition.
+  if (S == TheWhileStmt->getConditionVariableDeclStmt())
+return TheWhileStmt->getCond();
 }
   }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49911: Summary:Add clang::reinitializes attribute

2018-07-30 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 158051.
mboehme added a comment.

Various changes in response to reviewer comments.


Repository:
  rC Clang

https://reviews.llvm.org/D49911

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  lib/Sema/SemaDeclAttr.cpp
  test/SemaCXX/attr-reinitializes.cpp


Index: test/SemaCXX/attr-reinitializes.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{'reinitializes' attribute 
only applies to non-static and non-const member functions}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+  [[clang::reinitializes("arg")]] void qux(); // expected-error 
{{'reinitializes' attribute takes no arguments}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6539,6 +6539,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  // Move semantics attribute.
+  case ParsedAttr::AT_Reinitializes:
+handleSimpleAttribute(S, D, AL);
+break;
   }
 }
 
Index: include/clang/Basic/AttrDocs.td
===
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -3419,3 +3419,31 @@
 corresponding line within the inlined callee.
   }];
 }
+
+def ReinitializesDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``reinitializes`` attribute can be applied to a non-static, non-const C++
+member function to indicate that this member function reinitializes the entire
+object to a known state, independent of the previous state of the object.
+
+This attribute can be interpreted by static analyzers that warn about uses of 
an
+object that has been left in an indeterminate state by a move operation. If a
+member function marked with the ``reinitializes`` attribute is called on a
+moved-from object, the analyzer can conclude that the object is no longer in an
+indeterminate state.
+
+A typical example where this attribute would be used is on functions that clear
+a container class:
+
+.. code-block:: c++
+
+  template 
+  class Container {
+  public:
+...
+[[clang::reinitializes]] void Clear();
+...
+  };
+  }];
+}
Index: include/clang/Basic/Attr.td
===
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -90,6 +90,11 @@
 [{!S->isBitField()}],
 "non-bit-field non-static data members">;
 
+def NonStaticNonConstCXXMethod
+: SubsetSubjectisStatic() && !S->isConst()}],
+"non-static, non-const member functions">;
+
 def ObjCInstanceMethod : SubsetSubjectisInstanceMethod()}],
"Objective-C instance methods">;
@@ -2935,3 +2940,9 @@
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;
   let Documentation = [InternalLinkageDocs];
 }
+
+def Reinitializes : InheritableAttr {
+  let Spellings = [CXX11<"clang", "reinitializes">];
+  let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;
+  let Documentation = [ReinitializesDocs];
+}


Index: test/SemaCXX/attr-reinitializes.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{'reinitializes' attribute only applies to non-static and non-const member functions}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies to}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+  [[clang::reinitializes("arg")]] void qux(); // expected-error {{'reinitializes' attribute takes no arguments}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6539,6 +6539,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  // Move semantics attribute.
+  case ParsedAttr::AT_Reinitializes:
+handleSimpleAttribute(S, D, AL);
+break;
   }
 }

[PATCH] D49911: Summary:Add clang::reinitializes attribute

2018-07-30 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 3 inline comments as done.
mboehme added a comment.

> Should this attribute have some semantic checking that ensures the non-static 
> data members are accessed in the function that claims it reinitializes the 
> object?

I think this would be hard to do in a way that provides meaningful value.

We can't demand that the function should modify all member variables because 
not all functions that perform a logical "clear" or other reinitialization need 
to do this. For example, a typical implementation of `std::string::clear()` 
only modifies the string length but leaves the capacity and buffer unchanged.

The strongest requirement I think we can impose is that the function needs to 
modify at least one of the member variables -- possibly indirectly (i.e. 
through a call to another function). I don't think checking this would provide 
a real benefit though. We already disallow the `reinitializes` attribute for 
const member functions -- so if someone misuses the attribute, it'll be on a 
non-const member function that most likely modifies member variables, just not 
in a way that's guaranteed to reinitialize the object.

What we'd really want to check is whether the function is actually doing a 
logical reinitialization of the object. Instead of putting the 'reinitializes' 
attribute on the function, we'd want some way of expressing "this function has 
the precondition `true` and the postcondition `empty()`", and then we'd like to 
prove this at compile time or at least check it at runtime. That's obviously 
beyond the scope of what is possible in C++ today though.




Comment at: include/clang/Basic/Attr.td:96
+[{!S->isStatic() && !S->isConst()}],
+"non-static non-const member functions">;
+

aaron.ballman wrote:
> `non-static, non-const member functions` (with the comma)
IIUC, Clang then translates the comma into an "and" -- so the actual diagnostic 
becomes "non-static and non-const member functions" (see the expected-error in 
the tests). Is this as intended?



Comment at: include/clang/Basic/Attr.td:2945
+def Reinitializes : InheritableAttr {
+  let Spellings = [CXX11<"clang", "reinitializes">];
+  let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;

aaron.ballman wrote:
> I think it makes sense to use `CXX11` instead of `Clang` as this attribute 
> doesn't make sense in C2x mode, but should there be a `GNU` spelling as well?
I have to admit I'm not sure. What are the usual considerations here? Does this 
need to be coordinated in any way with GNU, or can Clang simply introduce 
additional "GNU-style" spellings (i.e. with `__attribute__`) that are 
Clang-only?

I understand there's a difference between `GCC` spellings and `GNU` spellings 
-- but I'm not sure what the rules around the latter are. Let me know if you 
think this should have a `GNU` spelling, and I'll add it!



Comment at: include/clang/Basic/AttrDocs.td:3426
+  let Content = [{
+The ``reinitializes`` attribute can be applied to a non-static, non-const C++
+member function to indicate that this member function reinitializes the entire

aaron.ballman wrote:
> While I kind of understand the restriction on a `const` member function, what 
> about code that has mutable members being reset within a const method?
I find it hard to envision a method that reinitializes an object by modifying 
only mutable member variables. Mutable members are, after all, intended to be 
used for purposes (such as caching and locking) that do not change the "logical 
state" of the object, whereas reinitialization is an operation that does change 
the logical state of the object.

If it really does turn out that there are legitimate use cases for applying the 
'reinitializes' attribute to a const member function, we can always relax this 
requirement later on.


Repository:
  rC Clang

https://reviews.llvm.org/D49911



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49918: [clang-tidy] Sequence declaration in while statement before the condition

2018-07-31 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 158314.
mboehme added a comment.

Add support for switch statement.

While I'm here, also add support for the init statement in an if statement.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49918

Files:
  clang-tidy/utils/ExprSequence.cpp
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++11 
-fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++17 
-fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 
@@ -1132,13 +1132,30 @@
   }
 }
 
-// If a variable is declared in an if statement, the declaration of the 
variable
-// (which is treated like a reinitialization by the check) is sequenced before
-// the evaluation of the condition (which constitutes a use).
-void ifStmtSequencesDeclAndCondition() {
+// If a variable is declared in an if, while or switch statement, the init
+// statement (for if and switch) is sequenced before the variable declaration,
+// which in turn is sequenced before the evaluation of the condition.
+void ifWhileAndSwitchSequenceInitDeclAndCondition() {
   for (int i = 0; i < 10; ++i) {
-if (A a = A()) {
-  std::move(a);
+A a1;
+if (A a2= std::move(a1)) {
+  std::move(a2);
+}
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+if (A a2 = std::move(a1); A a3 = std::move(a2)) {
+  std::move(a3);
+}
+  }
+  while (A a = A()) {
+std::move(a);
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+switch (A a2 = a1; A a3 = std::move(a2)) {
+  case true:
+std::move(a3);
 }
   }
 }
Index: clang-tidy/utils/ExprSequence.cpp
===
--- clang-tidy/utils/ExprSequence.cpp
+++ clang-tidy/utils/ExprSequence.cpp
@@ -139,11 +139,26 @@
   if (S == ForRange->getLoopVarStmt())
 return ForRange->getBody();
 } else if (const auto *TheIfStmt = dyn_cast(Parent)) {
-  // If statement: If a variable is declared inside the condition, the
-  // expression used to initialize the variable is sequenced before the
-  // evaluation of the condition.
+  // If statement:
+  // - Sequence init statement before variable declaration.
+  // - Sequence variable declaration (along with the expression used to
+  //   initialize it) before the evaluation of the condition.
+  if (S == TheIfStmt->getInit())
+return TheIfStmt->getConditionVariableDeclStmt();
   if (S == TheIfStmt->getConditionVariableDeclStmt())
 return TheIfStmt->getCond();
+} else if (const auto *TheSwitchStmt = dyn_cast(Parent)) {
+  // Ditto for switch statements.
+  if (S == TheSwitchStmt->getInit())
+return TheSwitchStmt->getConditionVariableDeclStmt();
+  if (S == TheSwitchStmt->getConditionVariableDeclStmt())
+return TheSwitchStmt->getCond();
+} else if (const auto *TheWhileStmt = dyn_cast(Parent)) {
+  // While statement: Sequence variable declaration (along with the
+  // expression used to initialize it) before the evaluation of the
+  // condition.
+  if (S == TheWhileStmt->getConditionVariableDeclStmt())
+return TheWhileStmt->getCond();
 }
   }
 


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++11 -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++17 -fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 
@@ -1132,13 +1132,30 @@
   }
 }
 
-// If a variable is declared in an if statement, the declaration of the variable
-// (which is treated like a reinitialization by the check) is sequenced before
-// the evaluation of the condition (which constitutes a use).
-void ifStmtSequencesDeclAndCondition() {
+// If a variable is declared in an if, while or switch statement, the init
+// statement (for if and switch) is sequenced before the variable declaration,
+// which in turn is sequenced before the evaluation of the condition.
+void ifWhileAndSwitchSequenceInitDeclAndCondition() {
   for (int i = 0; i < 10; ++i) {
-if (A a = A()) {
-  std::move(a);
+A a1;
+if (A a2= std::move(a1)) {
+  std::move(a2);
+}
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+if (A a2 = std::move(a1); A a3 = std::move(a2)) {
+  std::move(a3);
+}
+  }
+  while (A a = A()) {
+std::move(a);
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+switch (A a2 = a1; A a

[PATCH] D49918: [clang-tidy] Sequence declaration in while statement before the condition

2018-07-31 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked an inline comment as done.
mboehme added inline comments.



Comment at: clang-tidy/utils/ExprSequence.cpp:147
 return TheIfStmt->getCond();
+} else if (const auto *TheWhileStmt = dyn_cast(Parent)) {
+  // While statement: If a variable is declared inside the condition, the

aaron.ballman wrote:
> Should we also handle switch statements at the same time?
Good point.

While I was doing this, I noticed that we were also not sequencing init 
statements in if statements correctly, so I've added code for that as well.

The description of the change is now too narrow, so I'll change that in a 
moment.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49918



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49910: [clang-tidy] Recognize [[clang::reinitializes]] attribute in bugprone-use-after-move

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Any comments?

https://reviews.llvm.org/D49911, on which this relies, is now ready to land.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49910



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49918: [clang-tidy] Sequence init statements, declarations, and conditions correctly in if, switch, and while

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked an inline comment as done.
mboehme added a comment.

Any further comments? This is marked ready to land, but I've made some 
non-trivial changes since then, so I didn't just want to land this.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49918



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49911: Summary:Add clang::reinitializes attribute

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 159007.
mboehme marked an inline comment as done.
mboehme added a comment.

Various changes in response to review comments.


Repository:
  rC Clang

https://reviews.llvm.org/D49911

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  lib/Sema/SemaDeclAttr.cpp
  test/SemaCXX/attr-reinitializes.cpp


Index: test/SemaCXX/attr-reinitializes.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{'reinitializes' attribute 
only applies to non-static non-const member functions}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  __attribute__((reinitializes)) void gnu_foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies 
to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+  [[clang::reinitializes("arg")]] void qux(); // expected-error 
{{'reinitializes' attribute takes no arguments}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6539,6 +6539,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  // Move semantics attribute.
+  case ParsedAttr::AT_Reinitializes:
+handleSimpleAttribute(S, D, AL);
+break;
   }
 }
 
Index: include/clang/Basic/AttrDocs.td
===
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -3419,3 +3419,31 @@
 corresponding line within the inlined callee.
   }];
 }
+
+def ReinitializesDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``reinitializes`` attribute can be applied to a non-static, non-const C++
+member function to indicate that this member function reinitializes the entire
+object to a known state, independent of the previous state of the object.
+
+This attribute can be interpreted by static analyzers that warn about uses of 
an
+object that has been left in an indeterminate state by a move operation. If a
+member function marked with the ``reinitializes`` attribute is called on a
+moved-from object, the analyzer can conclude that the object is no longer in an
+indeterminate state.
+
+A typical example where this attribute would be used is on functions that clear
+a container class:
+
+.. code-block:: c++
+
+  template 
+  class Container {
+  public:
+...
+[[clang::reinitializes]] void Clear();
+...
+  };
+  }];
+}
Index: include/clang/Basic/Attr.td
===
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -90,6 +90,11 @@
 [{!S->isBitField()}],
 "non-bit-field non-static data members">;
 
+def NonStaticNonConstCXXMethod
+: SubsetSubjectisStatic() && !S->isConst()}],
+"non-static non-const member functions">;
+
 def ObjCInstanceMethod : SubsetSubjectisInstanceMethod()}],
"Objective-C instance methods">;
@@ -2935,3 +2940,9 @@
   let Subjects = SubjectList<[Var, Function, CXXRecord]>;
   let Documentation = [InternalLinkageDocs];
 }
+
+def Reinitializes : InheritableAttr {
+  let Spellings = [Clang<"reinitializes", 0>];
+  let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;
+  let Documentation = [ReinitializesDocs];
+}


Index: test/SemaCXX/attr-reinitializes.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-reinitializes.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+[[clang::reinitializes]] int a; // expected-error {{'reinitializes' attribute only applies to non-static non-const member functions}}
+
+[[clang::reinitializes]] void f(); // expected-error {{only applies to}}
+
+struct A {
+  [[clang::reinitializes]] void foo();
+  __attribute__((reinitializes)) void gnu_foo();
+  [[clang::reinitializes]] void bar() const; // expected-error {{only applies to}}
+  [[clang::reinitializes]] static void baz(); // expected-error {{only applies to}}
+  [[clang::reinitializes]] int a; // expected-error {{only applies to}}
+
+  [[clang::reinitializes("arg")]] void qux(); // expected-error {{'reinitializes' attribute takes no arguments}}
+};
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6539,6 +6539,11 @@
   case ParsedAttr::AT_XRayLogArgs:
 handleXRayLogArgsAttr(S, D, AL);
 break;
+
+  

[PATCH] D49911: Summary:Add clang::reinitializes attribute

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 2 inline comments as done.
mboehme added a comment.

Thanks for the review!

In https://reviews.llvm.org/D49911#1186185, @aaron.ballman wrote:

> The attribute itself is looking reasonable aside from some minor nits, but 
> this should not be committed until the clang-tidy functionality is approved 
> (since it has no utility beyond clang-tidy).


Will do.




Comment at: include/clang/Basic/Attr.td:96
+[{!S->isStatic() && !S->isConst()}],
+"non-static non-const member functions">;
+

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > `non-static, non-const member functions` (with the comma)
> > IIUC, Clang then translates the comma into an "and" -- so the actual 
> > diagnostic becomes "non-static and non-const member functions" (see the 
> > expected-error in the tests). Is this as intended?
> Ugh, that's a deficiency in ClangAttrEmitter.cpp. Good thing diagnostics 
> aren't grammatically correct anyway, you can roll back to the previous form. 
> Sorry about the churn!
No worries!



Comment at: include/clang/Basic/Attr.td:2945
+def Reinitializes : InheritableAttr {
+  let Spellings = [CXX11<"clang", "reinitializes">];
+  let Subjects = SubjectList<[NonStaticNonConstCXXMethod], ErrorDiag>;

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > I think it makes sense to use `CXX11` instead of `Clang` as this 
> > > attribute doesn't make sense in C2x mode, but should there be a `GNU` 
> > > spelling as well?
> > I have to admit I'm not sure. What are the usual considerations here? Does 
> > this need to be coordinated in any way with GNU, or can Clang simply 
> > introduce additional "GNU-style" spellings (i.e. with `__attribute__`) that 
> > are Clang-only?
> > 
> > I understand there's a difference between `GCC` spellings and `GNU` 
> > spellings -- but I'm not sure what the rules around the latter are. Let me 
> > know if you think this should have a `GNU` spelling, and I'll add it!
> We generally want things with both spellings unless there's rationale 
> justifying why only one spelling is better. I don't see any reason why this 
> shouldn't have a GNU spelling as well.
> 
> I'd spell this as `Clang<"reinitializes", 0>` so it gets both the CXX11 and 
> GNU spellings but not the C2x spelling.
Thanks for the explanation -- done!

I've also added a test that the GNU spelling is recognized.


Repository:
  rC Clang

https://reviews.llvm.org/D49911



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49910: [clang-tidy] Recognize [[clang::reinitializes]] attribute in bugprone-use-after-move

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In https://reviews.llvm.org/D49910#1187455, @aaron.ballman wrote:

> Are you going to propose adding this attribute to libc++, or is this expected 
> to only work with UDTs?


I don't have any experience contributing to libc++, but I think this would make 
sense.

The check currently hard-codes various member functions of classes in the "std" 
namespace that do reinitializations; I'm not sure though if those can be 
removed after the attribute has been added to libc++. We'd would also 
presumably have to add the attribute to libstdc++ -- does it accept Clang-only 
attributes? And what is the story for people using clang-tidy with MSVC 
projects? (I have to admit I'm very hazy on how that works...)


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49910



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49910: [clang-tidy] Recognize [[clang::reinitializes]] attribute in bugprone-use-after-move

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In https://reviews.llvm.org/D49910#1187809, @aaron.ballman wrote:

> In https://reviews.llvm.org/D49910#1187492, @mboehme wrote:
>
> > In https://reviews.llvm.org/D49910#1187455, @aaron.ballman wrote:
> >
> > > Are you going to propose adding this attribute to libc++, or is this 
> > > expected to only work with UDTs?
> >
> >
> > I don't have any experience contributing to libc++, but I think this would 
> > make sense.
> >
> > The check currently hard-codes various member functions of classes in the 
> > "std" namespace that do reinitializations; I'm not sure though if those can 
> > be removed after the attribute has been added to libc++. We'd would also 
> > presumably have to add the attribute to libstdc++ -- does it accept 
> > Clang-only attributes? And what is the story for people using clang-tidy 
> > with MSVC projects? (I have to admit I'm very hazy on how that works...)
>
>
> I ask the question because it's novel to add an attribute to Clang that's 
> used only by clang-tidy, and I'm wondering who is expected to use that 
> attribute to help with this check. Is it expected to be an attribute users 
> use with their own custom datatypes and it's not needed for standards-based 
> APIs (because we handle those some other way), or something else? As it 
> stands, I sort of feel like this is a very heavy approach to solve an edge 
> case -- is there a lot of evidence for re-using a moved-from object after 
> reinitializing it?


Ah, now I understand what you're getting at.

Yes, I see this attribute mainly as something that people would add to their 
own user-defined types -- typically, containers and smart pointers.

I've regularly been getting internal feature requests for this. One typical 
pattern in which this comes up is the following:

MyContainer container;
T t;
while (GetNextT(&t)) {

  container.Add(t);
  if (SomeCondition()) {
PassToConsumer(std::move(container));
container.Clear();
  }

}

I.e. you're incrementally adding items to some data structure, and at some 
point you decide the data structure is now complete, so you hand it off to a 
consumer and clear it, ready to be filled with the next batch of items.

As clang-tidy doesn't understand that the "container.Clear()" reinitializes the 
container, it complains that the Clear() is a use-after-move.

Yes, it's unusual to add an attribute to Clang that is only (at least 
initially) intended for use by clang-tidy -- but I don't really see how to 
implement this other than with an attribute.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49910



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49910: [clang-tidy] Recognize [[clang::reinitializes]] attribute in bugprone-use-after-move

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Sorry, that code got formatted strangely. Here's the same code block in more 
legible form:

  MyContainer container;
  T t;
  while (GetNextT(&t)) {
container.Add(t);
if (SomeCondition()) {
  PassToConsumer(std::move(container));
  container.Clear();
}
  }


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49910



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49918: [clang-tidy] Sequence init statements, declarations, and conditions correctly in if, switch, and while

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 159093.
mboehme added a comment.

Apply clang-format.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49918

Files:
  clang-tidy/utils/ExprSequence.cpp
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++11 
-fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++17 
-fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 
@@ -1132,13 +1132,30 @@
   }
 }
 
-// If a variable is declared in an if statement, the declaration of the 
variable
-// (which is treated like a reinitialization by the check) is sequenced before
-// the evaluation of the condition (which constitutes a use).
-void ifStmtSequencesDeclAndCondition() {
+// If a variable is declared in an if, while or switch statement, the init
+// statement (for if and switch) is sequenced before the variable declaration,
+// which in turn is sequenced before the evaluation of the condition.
+void ifWhileAndSwitchSequenceInitDeclAndCondition() {
   for (int i = 0; i < 10; ++i) {
-if (A a = A()) {
-  std::move(a);
+A a1;
+if (A a2 = std::move(a1)) {
+  std::move(a2);
+}
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+if (A a2 = std::move(a1); A a3 = std::move(a2)) {
+  std::move(a3);
+}
+  }
+  while (A a = A()) {
+std::move(a);
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+switch (A a2 = a1; A a3 = std::move(a2)) {
+  case true:
+std::move(a3);
 }
   }
 }
Index: clang-tidy/utils/ExprSequence.cpp
===
--- clang-tidy/utils/ExprSequence.cpp
+++ clang-tidy/utils/ExprSequence.cpp
@@ -139,11 +139,26 @@
   if (S == ForRange->getLoopVarStmt())
 return ForRange->getBody();
 } else if (const auto *TheIfStmt = dyn_cast(Parent)) {
-  // If statement: If a variable is declared inside the condition, the
-  // expression used to initialize the variable is sequenced before the
-  // evaluation of the condition.
+  // If statement:
+  // - Sequence init statement before variable declaration.
+  // - Sequence variable declaration (along with the expression used to
+  //   initialize it) before the evaluation of the condition.
+  if (S == TheIfStmt->getInit())
+return TheIfStmt->getConditionVariableDeclStmt();
   if (S == TheIfStmt->getConditionVariableDeclStmt())
 return TheIfStmt->getCond();
+} else if (const auto *TheSwitchStmt = dyn_cast(Parent)) {
+  // Ditto for switch statements.
+  if (S == TheSwitchStmt->getInit())
+return TheSwitchStmt->getConditionVariableDeclStmt();
+  if (S == TheSwitchStmt->getConditionVariableDeclStmt())
+return TheSwitchStmt->getCond();
+} else if (const auto *TheWhileStmt = dyn_cast(Parent)) {
+  // While statement: Sequence variable declaration (along with the
+  // expression used to initialize it) before the evaluation of the
+  // condition.
+  if (S == TheWhileStmt->getConditionVariableDeclStmt())
+return TheWhileStmt->getCond();
 }
   }
 


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++11 -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++17 -fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 
@@ -1132,13 +1132,30 @@
   }
 }
 
-// If a variable is declared in an if statement, the declaration of the variable
-// (which is treated like a reinitialization by the check) is sequenced before
-// the evaluation of the condition (which constitutes a use).
-void ifStmtSequencesDeclAndCondition() {
+// If a variable is declared in an if, while or switch statement, the init
+// statement (for if and switch) is sequenced before the variable declaration,
+// which in turn is sequenced before the evaluation of the condition.
+void ifWhileAndSwitchSequenceInitDeclAndCondition() {
   for (int i = 0; i < 10; ++i) {
-if (A a = A()) {
-  std::move(a);
+A a1;
+if (A a2 = std::move(a1)) {
+  std::move(a2);
+}
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+if (A a2 = std::move(a1); A a3 = std::move(a2)) {
+  std::move(a3);
+}
+  }
+  while (A a = A()) {
+std::move(a);
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+switch (A a2 = a1; A a3 = std::move(a2)) {
+  case true:
+std::move(a3);
 }
   }
 }
Index: clan

[PATCH] D49918: [clang-tidy] Sequence init statements, declarations, and conditions correctly in if, switch, and while

2018-08-03 Thread Martin Böhme via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCTE338932: [clang-tidy] Sequence init statements, 
declarations, and conditions correctly… (authored by mboehme, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D49918?vs=159093&id=159105#toc

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D49918

Files:
  clang-tidy/utils/ExprSequence.cpp
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++11 
-fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++17 
-fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 
@@ -1132,13 +1132,30 @@
   }
 }
 
-// If a variable is declared in an if statement, the declaration of the 
variable
-// (which is treated like a reinitialization by the check) is sequenced before
-// the evaluation of the condition (which constitutes a use).
-void ifStmtSequencesDeclAndCondition() {
+// If a variable is declared in an if, while or switch statement, the init
+// statement (for if and switch) is sequenced before the variable declaration,
+// which in turn is sequenced before the evaluation of the condition.
+void ifWhileAndSwitchSequenceInitDeclAndCondition() {
   for (int i = 0; i < 10; ++i) {
-if (A a = A()) {
-  std::move(a);
+A a1;
+if (A a2 = std::move(a1)) {
+  std::move(a2);
+}
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+if (A a2 = std::move(a1); A a3 = std::move(a2)) {
+  std::move(a3);
+}
+  }
+  while (A a = A()) {
+std::move(a);
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+switch (A a2 = a1; A a3 = std::move(a2)) {
+  case true:
+std::move(a3);
 }
   }
 }
Index: clang-tidy/utils/ExprSequence.cpp
===
--- clang-tidy/utils/ExprSequence.cpp
+++ clang-tidy/utils/ExprSequence.cpp
@@ -139,11 +139,26 @@
   if (S == ForRange->getLoopVarStmt())
 return ForRange->getBody();
 } else if (const auto *TheIfStmt = dyn_cast(Parent)) {
-  // If statement: If a variable is declared inside the condition, the
-  // expression used to initialize the variable is sequenced before the
-  // evaluation of the condition.
+  // If statement:
+  // - Sequence init statement before variable declaration.
+  // - Sequence variable declaration (along with the expression used to
+  //   initialize it) before the evaluation of the condition.
+  if (S == TheIfStmt->getInit())
+return TheIfStmt->getConditionVariableDeclStmt();
   if (S == TheIfStmt->getConditionVariableDeclStmt())
 return TheIfStmt->getCond();
+} else if (const auto *TheSwitchStmt = dyn_cast(Parent)) {
+  // Ditto for switch statements.
+  if (S == TheSwitchStmt->getInit())
+return TheSwitchStmt->getConditionVariableDeclStmt();
+  if (S == TheSwitchStmt->getConditionVariableDeclStmt())
+return TheSwitchStmt->getCond();
+} else if (const auto *TheWhileStmt = dyn_cast(Parent)) {
+  // While statement: Sequence variable declaration (along with the
+  // expression used to initialize it) before the evaluation of the
+  // condition.
+  if (S == TheWhileStmt->getConditionVariableDeclStmt())
+return TheWhileStmt->getCond();
 }
   }
 


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++11 -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++17 -fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 
@@ -1132,13 +1132,30 @@
   }
 }
 
-// If a variable is declared in an if statement, the declaration of the variable
-// (which is treated like a reinitialization by the check) is sequenced before
-// the evaluation of the condition (which constitutes a use).
-void ifStmtSequencesDeclAndCondition() {
+// If a variable is declared in an if, while or switch statement, the init
+// statement (for if and switch) is sequenced before the variable declaration,
+// which in turn is sequenced before the evaluation of the condition.
+void ifWhileAndSwitchSequenceInitDeclAndCondition() {
   for (int i = 0; i < 10; ++i) {
-if (A a = A()) {
-  std::move(a);
+A a1;
+if (A a2 = std::move(a1)) {
+  std::move(a2);
+}
+  }
+  for (int i = 0; i < 10; ++i) {
+A a1;
+if (A a2 = std::move(a1); A a3 = std::move(a2)) {
+  std::move(a3);
+}
+

[PATCH] D56585: [clang-tidy] Treat references to smart pointers correctly in use-after-move.

2019-01-11 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added subscribers: cfe-commits, xazax.hun.

Previously, we weren't recognizing these as smart pointers and thus
weren't allowing non-dereference accesses as we should -- see new test
cases which fail without the fix.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D56585

Files:
  clang-tidy/bugprone/UseAfterMoveCheck.cpp
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -244,6 +244,19 @@
 std::move(ptr);
 ptr.get();
   }
+  // Make sure we treat references to smart pointers correctly.
+  {
+std::unique_ptr ptr;
+std::unique_ptr& ref_to_ptr = ptr;
+std::move(ref_to_ptr);
+ref_to_ptr.get();
+  }
+  {
+std::unique_ptr ptr;
+std::unique_ptr&& rvalue_ref_to_ptr = std::move(ptr);
+std::move(rvalue_ref_to_ptr);
+rvalue_ref_to_ptr.get();
+  }
   // We don't give any special treatment to types that are called "unique_ptr"
   // or "shared_ptr" but are not in the "::std" namespace.
   {
@@ -257,6 +270,11 @@
   }
 }
 
+void foo(std::unique_ptr&& a) {
+  std::move(a);
+  std::move(a);
+}
+
 // The check also works in member functions.
 class Container {
   void useAfterMoveInMemberFunction() {
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -207,7 +207,7 @@
 }
 
 bool isStandardSmartPointer(const ValueDecl *VD) {
-  const Type *TheType = VD->getType().getTypePtrOrNull();
+  const Type *TheType = VD->getType().getNonReferenceType().getTypePtrOrNull();
   if (!TheType)
 return false;
 


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -244,6 +244,19 @@
 std::move(ptr);
 ptr.get();
   }
+  // Make sure we treat references to smart pointers correctly.
+  {
+std::unique_ptr ptr;
+std::unique_ptr& ref_to_ptr = ptr;
+std::move(ref_to_ptr);
+ref_to_ptr.get();
+  }
+  {
+std::unique_ptr ptr;
+std::unique_ptr&& rvalue_ref_to_ptr = std::move(ptr);
+std::move(rvalue_ref_to_ptr);
+rvalue_ref_to_ptr.get();
+  }
   // We don't give any special treatment to types that are called "unique_ptr"
   // or "shared_ptr" but are not in the "::std" namespace.
   {
@@ -257,6 +270,11 @@
   }
 }
 
+void foo(std::unique_ptr&& a) {
+  std::move(a);
+  std::move(a);
+}
+
 // The check also works in member functions.
 class Container {
   void useAfterMoveInMemberFunction() {
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -207,7 +207,7 @@
 }
 
 bool isStandardSmartPointer(const ValueDecl *VD) {
-  const Type *TheType = VD->getType().getTypePtrOrNull();
+  const Type *TheType = VD->getType().getNonReferenceType().getTypePtrOrNull();
   if (!TheType)
 return false;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D56585: [clang-tidy] Treat references to smart pointers correctly in use-after-move.

2019-01-11 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 181228.
mboehme added a comment.

Removing experimental code that shouldn't have been added.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56585/new/

https://reviews.llvm.org/D56585

Files:
  clang-tidy/bugprone/UseAfterMoveCheck.cpp
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -244,6 +244,19 @@
 std::move(ptr);
 ptr.get();
   }
+  // Make sure we treat references to smart pointers correctly.
+  {
+std::unique_ptr ptr;
+std::unique_ptr& ref_to_ptr = ptr;
+std::move(ref_to_ptr);
+ref_to_ptr.get();
+  }
+  {
+std::unique_ptr ptr;
+std::unique_ptr&& rvalue_ref_to_ptr = std::move(ptr);
+std::move(rvalue_ref_to_ptr);
+rvalue_ref_to_ptr.get();
+  }
   // We don't give any special treatment to types that are called "unique_ptr"
   // or "shared_ptr" but are not in the "::std" namespace.
   {
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -207,7 +207,7 @@
 }
 
 bool isStandardSmartPointer(const ValueDecl *VD) {
-  const Type *TheType = VD->getType().getTypePtrOrNull();
+  const Type *TheType = VD->getType().getNonReferenceType().getTypePtrOrNull();
   if (!TheType)
 return false;
 


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -244,6 +244,19 @@
 std::move(ptr);
 ptr.get();
   }
+  // Make sure we treat references to smart pointers correctly.
+  {
+std::unique_ptr ptr;
+std::unique_ptr& ref_to_ptr = ptr;
+std::move(ref_to_ptr);
+ref_to_ptr.get();
+  }
+  {
+std::unique_ptr ptr;
+std::unique_ptr&& rvalue_ref_to_ptr = std::move(ptr);
+std::move(rvalue_ref_to_ptr);
+rvalue_ref_to_ptr.get();
+  }
   // We don't give any special treatment to types that are called "unique_ptr"
   // or "shared_ptr" but are not in the "::std" namespace.
   {
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -207,7 +207,7 @@
 }
 
 bool isStandardSmartPointer(const ValueDecl *VD) {
-  const Type *TheType = VD->getType().getTypePtrOrNull();
+  const Type *TheType = VD->getType().getNonReferenceType().getTypePtrOrNull();
   if (!TheType)
 return false;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D56585: [clang-tidy] Treat references to smart pointers correctly in use-after-move.

2019-01-15 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In D56585#1358477 , @JonasToth wrote:

> LGTM, is there a bug report for this issue? If yes please close that too :)


Thanks for the reminder!

This was a bug that was reported internally, so there is no LLVM bug for this.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56585/new/

https://reviews.llvm.org/D56585



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D56585: [clang-tidy] Treat references to smart pointers correctly in use-after-move.

2019-01-15 Thread Martin Böhme via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL351303: [clang-tidy] Treat references to smart pointers 
correctly in use-after-move. (authored by mboehme, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56585/new/

https://reviews.llvm.org/D56585

Files:
  clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp


Index: clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -207,7 +207,7 @@
 }
 
 bool isStandardSmartPointer(const ValueDecl *VD) {
-  const Type *TheType = VD->getType().getTypePtrOrNull();
+  const Type *TheType = VD->getType().getNonReferenceType().getTypePtrOrNull();
   if (!TheType)
 return false;
 
Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
@@ -244,6 +244,19 @@
 std::move(ptr);
 ptr.get();
   }
+  // Make sure we treat references to smart pointers correctly.
+  {
+std::unique_ptr ptr;
+std::unique_ptr& ref_to_ptr = ptr;
+std::move(ref_to_ptr);
+ref_to_ptr.get();
+  }
+  {
+std::unique_ptr ptr;
+std::unique_ptr&& rvalue_ref_to_ptr = std::move(ptr);
+std::move(rvalue_ref_to_ptr);
+rvalue_ref_to_ptr.get();
+  }
   // We don't give any special treatment to types that are called "unique_ptr"
   // or "shared_ptr" but are not in the "::std" namespace.
   {


Index: clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -207,7 +207,7 @@
 }
 
 bool isStandardSmartPointer(const ValueDecl *VD) {
-  const Type *TheType = VD->getType().getTypePtrOrNull();
+  const Type *TheType = VD->getType().getNonReferenceType().getTypePtrOrNull();
   if (!TheType)
 return false;
 
Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
@@ -244,6 +244,19 @@
 std::move(ptr);
 ptr.get();
   }
+  // Make sure we treat references to smart pointers correctly.
+  {
+std::unique_ptr ptr;
+std::unique_ptr& ref_to_ptr = ptr;
+std::move(ref_to_ptr);
+ref_to_ptr.get();
+  }
+  {
+std::unique_ptr ptr;
+std::unique_ptr&& rvalue_ref_to_ptr = std::move(ptr);
+std::move(rvalue_ref_to_ptr);
+rvalue_ref_to_ptr.get();
+  }
   // We don't give any special treatment to types that are called "unique_ptr"
   // or "shared_ptr" but are not in the "::std" namespace.
   {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52782: [clang-tidy] Sequence statements with multiple parents correctly (PR39149)

2018-10-02 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added subscribers: cfe-commits, xazax.hun.

Before this fix, the bugprone-use-after-move check could incorrectly
conclude that a use and move in a function template were not sequenced.
For details, see

https://bugs.llvm.org/show_bug.cgi?id=39149


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52782

Files:
  clang-tidy/bugprone/UseAfterMoveCheck.cpp
  clang-tidy/utils/ExprSequence.cpp
  clang-tidy/utils/ExprSequence.h
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1195,6 +1195,18 @@
   }
 }
 
+// Null statements (and some other statements) in templates may be shared
+// between the uninstantiated and instantiated versions of the template and
+// therefore have multiple parents. Make sure the sequencing code handles this
+// correctly.
+template  void nullStatementSequencesInTemplate() {
+  int c = 0;
+  (void)c;
+  ;
+  std::move(c);
+}
+template void nullStatementSequencesInTemplate();
+
 namespace PR33020 {
 class D {
   ~D();
Index: clang-tidy/utils/ExprSequence.h
===
--- clang-tidy/utils/ExprSequence.h
+++ clang-tidy/utils/ExprSequence.h
@@ -69,8 +69,8 @@
 class ExprSequence {
 public:
   /// Initializes this `ExprSequence` with sequence information for the given
-  /// `CFG`.
-  ExprSequence(const CFG *TheCFG, ASTContext *TheContext);
+  /// `CFG`. `Root` is the root statement the CFG was built from.
+  ExprSequence(const CFG *TheCFG, const Stmt *Root, ASTContext *TheContext);
 
   /// Returns whether \p Before is sequenced before \p After.
   bool inSequence(const Stmt *Before, const Stmt *After) const;
@@ -94,6 +94,7 @@
   const Stmt *resolveSyntheticStmt(const Stmt *S) const;
 
   ASTContext *Context;
+  const Stmt *Root;
 
   llvm::DenseMap SyntheticStmtSourceMap;
 };
Index: clang-tidy/utils/ExprSequence.cpp
===
--- clang-tidy/utils/ExprSequence.cpp
+++ clang-tidy/utils/ExprSequence.cpp
@@ -63,8 +63,9 @@
 }
 }
 
-ExprSequence::ExprSequence(const CFG *TheCFG, ASTContext *TheContext)
-: Context(TheContext) {
+ExprSequence::ExprSequence(const CFG *TheCFG, const Stmt *Root,
+   ASTContext *TheContext)
+: Context(TheContext), Root(Root) {
   for (const auto &SyntheticStmt : TheCFG->synthetic_stmts()) {
 SyntheticStmtSourceMap[SyntheticStmt.first] = SyntheticStmt.second;
   }
@@ -99,6 +100,11 @@
 
 const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const {
   for (const Stmt *Parent : getParentStmts(S, Context)) {
+// For statements that have multiple parents, make sure we're using the
+// parent that lies within the sub-tree under Root.
+if (!isDescendantOrEqual(Parent, Root, Context))
+  continue;
+
 if (const auto *BO = dyn_cast(Parent)) {
   // Comma operator: Right-hand side is sequenced after the left-hand side.
   if (BO->getLHS() == S && BO->getOpcode() == BO_Comma)
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -102,8 +102,9 @@
   if (!TheCFG)
 return false;
 
-  Sequence.reset(new ExprSequence(TheCFG.get(), Context));
-  BlockMap.reset(new StmtToBlockMap(TheCFG.get(), Context));
+  Sequence =
+  llvm::make_unique(TheCFG.get(), FunctionBody, Context);
+  BlockMap = llvm::make_unique(TheCFG.get(), Context);
   Visited.clear();
 
   const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1195,6 +1195,18 @@
   }
 }
 
+// Null statements (and some other statements) in templates may be shared
+// between the uninstantiated and instantiated versions of the template and
+// therefore have multiple parents. Make sure the sequencing code handles this
+// correctly.
+template  void nullStatementSequencesInTemplate() {
+  int c = 0;
+  (void)c;
+  ;
+  std::move(c);
+}
+template void nullStatementSequencesInTemplate();
+
 namespace PR33020 {
 class D {
   ~D();
Index: clang-tidy/utils/ExprSequence.h
===
--- clang-tidy/utils/ExprSequence.h
+++ clang-tidy/utils/ExprSequence.h
@@ -69,8 +69,8 @@
 class ExprSequence {
 public:
   /// Initializes this `ExprSequence` with sequence information for the given
-  /// `CFG`.
-  ExprSequence(const CFG *TheCFG, ASTContext *TheContext);
+  /// `CFG`. `Root` is the root statement the CFG was built from.
+  ExprSequence(const CFG *TheCFG, co

[PATCH] D52782: [clang-tidy] Sequence statements with multiple parents correctly (PR39149)

2018-10-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 168239.
mboehme added a comment.

- Responses to reviewer comments.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52782

Files:
  clang-tidy/bugprone/UseAfterMoveCheck.cpp
  clang-tidy/utils/ExprSequence.cpp
  clang-tidy/utils/ExprSequence.h
  test/clang-tidy/bugprone-use-after-move.cpp


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1195,6 +1195,18 @@
   }
 }
 
+// Some statements in templates (e.g. null, break and continue statements) may
+// be shared between the uninstantiated and instantiated versions of the
+// template and therefore have multiple parents. Make sure the sequencing code
+// handles this correctly.
+template  void nullStatementSequencesInTemplate() {
+  int c = 0;
+  (void)c;
+  ;
+  std::move(c);
+}
+template void nullStatementSequencesInTemplate();
+
 namespace PR33020 {
 class D {
   ~D();
Index: clang-tidy/utils/ExprSequence.h
===
--- clang-tidy/utils/ExprSequence.h
+++ clang-tidy/utils/ExprSequence.h
@@ -69,8 +69,8 @@
 class ExprSequence {
 public:
   /// Initializes this `ExprSequence` with sequence information for the given
-  /// `CFG`.
-  ExprSequence(const CFG *TheCFG, ASTContext *TheContext);
+  /// `CFG`. `Root` is the root statement the CFG was built from.
+  ExprSequence(const CFG *TheCFG, const Stmt *Root, ASTContext *TheContext);
 
   /// Returns whether \p Before is sequenced before \p After.
   bool inSequence(const Stmt *Before, const Stmt *After) const;
@@ -94,6 +94,7 @@
   const Stmt *resolveSyntheticStmt(const Stmt *S) const;
 
   ASTContext *Context;
+  const Stmt *Root;
 
   llvm::DenseMap SyntheticStmtSourceMap;
 };
Index: clang-tidy/utils/ExprSequence.cpp
===
--- clang-tidy/utils/ExprSequence.cpp
+++ clang-tidy/utils/ExprSequence.cpp
@@ -63,8 +63,9 @@
 }
 }
 
-ExprSequence::ExprSequence(const CFG *TheCFG, ASTContext *TheContext)
-: Context(TheContext) {
+ExprSequence::ExprSequence(const CFG *TheCFG, const Stmt *Root,
+   ASTContext *TheContext)
+: Context(TheContext), Root(Root) {
   for (const auto &SyntheticStmt : TheCFG->synthetic_stmts()) {
 SyntheticStmtSourceMap[SyntheticStmt.first] = SyntheticStmt.second;
   }
@@ -99,6 +100,11 @@
 
 const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const {
   for (const Stmt *Parent : getParentStmts(S, Context)) {
+// If a statement has multiple parents, make sure we're using the parent
+// that lies within the sub-tree under Root.
+if (!isDescendantOrEqual(Parent, Root, Context))
+  continue;
+
 if (const auto *BO = dyn_cast(Parent)) {
   // Comma operator: Right-hand side is sequenced after the left-hand side.
   if (BO->getLHS() == S && BO->getOpcode() == BO_Comma)
Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -102,8 +102,9 @@
   if (!TheCFG)
 return false;
 
-  Sequence.reset(new ExprSequence(TheCFG.get(), Context));
-  BlockMap.reset(new StmtToBlockMap(TheCFG.get(), Context));
+  Sequence =
+  llvm::make_unique(TheCFG.get(), FunctionBody, Context);
+  BlockMap = llvm::make_unique(TheCFG.get(), Context);
   Visited.clear();
 
   const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);


Index: test/clang-tidy/bugprone-use-after-move.cpp
===
--- test/clang-tidy/bugprone-use-after-move.cpp
+++ test/clang-tidy/bugprone-use-after-move.cpp
@@ -1195,6 +1195,18 @@
   }
 }
 
+// Some statements in templates (e.g. null, break and continue statements) may
+// be shared between the uninstantiated and instantiated versions of the
+// template and therefore have multiple parents. Make sure the sequencing code
+// handles this correctly.
+template  void nullStatementSequencesInTemplate() {
+  int c = 0;
+  (void)c;
+  ;
+  std::move(c);
+}
+template void nullStatementSequencesInTemplate();
+
 namespace PR33020 {
 class D {
   ~D();
Index: clang-tidy/utils/ExprSequence.h
===
--- clang-tidy/utils/ExprSequence.h
+++ clang-tidy/utils/ExprSequence.h
@@ -69,8 +69,8 @@
 class ExprSequence {
 public:
   /// Initializes this `ExprSequence` with sequence information for the given
-  /// `CFG`.
-  ExprSequence(const CFG *TheCFG, ASTContext *TheContext);
+  /// `CFG`. `Root` is the root statement the CFG was built from.
+  ExprSequence(const CFG *TheCFG, const Stmt *Root, ASTContext *TheContext);
 
   /// Returns whether \p Before is sequenced before \p After.
   bool inSequence(const Stmt *Before, const Stmt

[PATCH] D52782: [clang-tidy] Sequence statements with multiple parents correctly (PR39149)

2018-10-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 3 inline comments as done.
mboehme added inline comments.



Comment at: clang-tidy/utils/ExprSequence.cpp:103
   for (const Stmt *Parent : getParentStmts(S, Context)) {
+// For statements that have multiple parents, make sure we're using the
+// parent that lies within the sub-tree under Root.

aaron.ballman wrote:
> JonasToth wrote:
> > I find the first part of the comment unclear. Does this loop handle `for` 
> > only?
> I think this means English "for" and not C `for`. Could rewrite to `If a 
> statement has multiple parents, ` instead.
Yes, this is what I meant. Rephrased as Aaron suggested to remove the ambiguity.



Comment at: test/clang-tidy/bugprone-use-after-move.cpp:1198
 
+// Null statements (and some other statements) in templates may be shared
+// between the uninstantiated and instantiated versions of the template and

JonasToth wrote:
> Which other stmts? do they produce the same false positive?
I've added the two other examples I'm aware of (continue and break statements) 
to the description. However, I haven't been able to use these to construct an 
example that triggers the false positive.

In general, any statement that TemplateInstantiator leaves unchanged will have 
multiple parents; I'm not sure which other statements this applies to. In my 
experience, any statement that contains an expression will be rebuilt, but I 
may be missing something here.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52782



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52782: [clang-tidy] Sequence statements with multiple parents correctly (PR39149)

2018-10-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 2 inline comments as done.
mboehme added a comment.

In https://reviews.llvm.org/D52782#1254933, @JonasToth wrote:

> Thanks for clarification :)


Thanks! Do you agree this is ready to land now?


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D52782



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52782: [clang-tidy] Sequence statements with multiple parents correctly (PR39149)

2018-10-04 Thread Martin Böhme via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL343768: [clang-tidy] Sequence statements with multiple 
parents correctly (PR39149) (authored by mboehme, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D52782

Files:
  clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
  clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp
  clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h
  clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp


Index: clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -102,8 +102,9 @@
   if (!TheCFG)
 return false;
 
-  Sequence.reset(new ExprSequence(TheCFG.get(), Context));
-  BlockMap.reset(new StmtToBlockMap(TheCFG.get(), Context));
+  Sequence =
+  llvm::make_unique(TheCFG.get(), FunctionBody, Context);
+  BlockMap = llvm::make_unique(TheCFG.get(), Context);
   Visited.clear();
 
   const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);
Index: clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h
===
--- clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h
+++ clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h
@@ -69,8 +69,8 @@
 class ExprSequence {
 public:
   /// Initializes this `ExprSequence` with sequence information for the given
-  /// `CFG`.
-  ExprSequence(const CFG *TheCFG, ASTContext *TheContext);
+  /// `CFG`. `Root` is the root statement the CFG was built from.
+  ExprSequence(const CFG *TheCFG, const Stmt *Root, ASTContext *TheContext);
 
   /// Returns whether \p Before is sequenced before \p After.
   bool inSequence(const Stmt *Before, const Stmt *After) const;
@@ -94,6 +94,7 @@
   const Stmt *resolveSyntheticStmt(const Stmt *S) const;
 
   ASTContext *Context;
+  const Stmt *Root;
 
   llvm::DenseMap SyntheticStmtSourceMap;
 };
Index: clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp
===
--- clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp
+++ clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp
@@ -63,8 +63,9 @@
 }
 }
 
-ExprSequence::ExprSequence(const CFG *TheCFG, ASTContext *TheContext)
-: Context(TheContext) {
+ExprSequence::ExprSequence(const CFG *TheCFG, const Stmt *Root,
+   ASTContext *TheContext)
+: Context(TheContext), Root(Root) {
   for (const auto &SyntheticStmt : TheCFG->synthetic_stmts()) {
 SyntheticStmtSourceMap[SyntheticStmt.first] = SyntheticStmt.second;
   }
@@ -99,6 +100,11 @@
 
 const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const {
   for (const Stmt *Parent : getParentStmts(S, Context)) {
+// If a statement has multiple parents, make sure we're using the parent
+// that lies within the sub-tree under Root.
+if (!isDescendantOrEqual(Parent, Root, Context))
+  continue;
+
 if (const auto *BO = dyn_cast(Parent)) {
   // Comma operator: Right-hand side is sequenced after the left-hand side.
   if (BO->getLHS() == S && BO->getOpcode() == BO_Comma)
Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-use-after-move.cpp
@@ -1195,6 +1195,18 @@
   }
 }
 
+// Some statements in templates (e.g. null, break and continue statements) may
+// be shared between the uninstantiated and instantiated versions of the
+// template and therefore have multiple parents. Make sure the sequencing code
+// handles this correctly.
+template  void nullStatementSequencesInTemplate() {
+  int c = 0;
+  (void)c;
+  ;
+  std::move(c);
+}
+template void nullStatementSequencesInTemplate();
+
 namespace PR33020 {
 class D {
   ~D();


Index: clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -102,8 +102,9 @@
   if (!TheCFG)
 return false;
 
-  Sequence.reset(new ExprSequence(TheCFG.get(), Context));
-  BlockMap.reset(new StmtToBlockMap(TheCFG.get(), Context));
+  Sequence =
+  llvm::make_unique(TheCFG.get(), FunctionBody, Context);
+  BlockMap = llvm::make_unique(TheCFG.get(), Context);
   Visited.clear();
 
   const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);
Index: clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h
===
--- clang-tool

[PATCH] D67627: Clang-format: Add Whitesmiths indentation style

2019-09-17 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In D67627#1671638 , @echristo wrote:

> Martin should know who should look at this... maybe Krasimir?


Yes, I think he'd be a good person to look at this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67627/new/

https://reviews.llvm.org/D67627



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D80781: [clang] Always allow including builtin headers in [no_undeclared_headers] modules.

2020-05-29 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
mboehme added a project: clang.
Herald added a subscriber: cfe-commits.
mboehme added a reviewer: rsmith.

Previously, this would fail if the builtin headers had been "claimed" by a 
different module that wraps these builtin headers. libc++ does this, for 
example.

This change adds a test demonstrating this situation; the test fails without 
the fix.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D80781

Files:
  clang/include/clang/Lex/ModuleMap.h
  clang/lib/Lex/HeaderSearch.cpp
  clang/lib/Lex/ModuleMap.cpp
  
clang/test/Modules/Inputs/no-undeclared-includes-builtins/system_module/module.modulemap
  
clang/test/Modules/Inputs/no-undeclared-includes-builtins/system_module/stddef.h
  
clang/test/Modules/Inputs/no-undeclared-includes-builtins/user_module/module.modulemap
  
clang/test/Modules/Inputs/no-undeclared-includes-builtins/user_module/user_module.h
  clang/test/Modules/no-undeclared-includes-builtins.cpp

Index: clang/test/Modules/no-undeclared-includes-builtins.cpp
===
--- /dev/null
+++ clang/test/Modules/no-undeclared-includes-builtins.cpp
@@ -0,0 +1,9 @@
+// Test that a [no_undeclared_headers] module can include builtin headers, even
+// if these have been "claimed" by a different module that wraps these builtin
+// headers. libc++ does this, for example.
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/no-undeclared-includes-builtins/user_module -I %S/Inputs/no-undeclared-includes-builtins/system_module %s
+// expected-no-diagnostics
+
+#include 
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/user_module/user_module.h
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/user_module/user_module.h
@@ -0,0 +1 @@
+#include 
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/user_module/module.modulemap
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/user_module/module.modulemap
@@ -0,0 +1,4 @@
+module UserModule [no_undeclared_includes] {
+  header "user_module.h"
+  export *
+}
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/system_module/stddef.h
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/system_module/stddef.h
@@ -0,0 +1 @@
+#include_next 
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/system_module/module.modulemap
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/system_module/module.modulemap
@@ -0,0 +1,4 @@
+module stddef [system] {
+  header "stddef.h"
+  export *
+}
Index: clang/lib/Lex/ModuleMap.cpp
===
--- clang/lib/Lex/ModuleMap.cpp
+++ clang/lib/Lex/ModuleMap.cpp
@@ -387,13 +387,17 @@
.Default(false);
 }
 
+bool ModuleMap::isBuiltinHeader(const FileEntry *File) {
+  return File->getDir() == BuiltinIncludeDir &&
+ ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()));
+}
+
 ModuleMap::HeadersMap::iterator
 ModuleMap::findKnownHeader(const FileEntry *File) {
   resolveHeaderDirectives(File);
   HeadersMap::iterator Known = Headers.find(File);
   if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
-  Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
-  ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName( {
+  Known == Headers.end() && ModuleMap::isBuiltinHeader(File)) {
 HeaderInfo.loadTopLevelSystemModules();
 return Headers.find(File);
   }
Index: clang/lib/Lex/HeaderSearch.cpp
===
--- clang/lib/Lex/HeaderSearch.cpp
+++ clang/lib/Lex/HeaderSearch.cpp
@@ -1276,14 +1276,12 @@
 //
 // It's common that libc++ and system modules will both define such
 // submodules. Make sure cached results for a builtin header won't
-// prevent other builtin modules to potentially enter the builtin header.
-// Note that builtins are header guarded and the decision to actually
-// enter them is postponed to the controlling macros logic below.
+// prevent other builtin modules from potentially entering the builtin
+// header. Note that builtins are header guarded and the decision to
+// actually enter them is postponed to the controlling macros logic below.
 bool TryEnterHdr = false;
 if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader)
-  TryEnterHdr = File->getDir() == ModMap.getBuiltinDir() &&
-ModuleMap::isBuiltinHeader(
-llvm::sys::path::filename(File->getName()));
+

[PATCH] D80781: [clang] Always allow including builtin headers in [no_undeclared_headers] modules.

2020-05-29 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Temporarily retracting from review as I've realized there's another case I need 
to take care of.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80781/new/

https://reviews.llvm.org/D80781



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D80781: [clang] Always allow including builtin headers in [no_undeclared_headers] modules.

2020-05-29 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 267210.
mboehme added a comment.

When testing with the real libc++ and glibc, I realized that I was still 
getting a cyclic dependency between the two modules because the builtin 
stddef.h that glibc was including was still being ascribed to libc++.

This modified version fixes this and also updates the test to more closely 
reflect the real libc++ and glibc so that my previous version of the fix also 
fails with a cyclic dependency.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80781/new/

https://reviews.llvm.org/D80781

Files:
  clang/include/clang/Lex/ModuleMap.h
  clang/lib/Lex/HeaderSearch.cpp
  clang/lib/Lex/ModuleMap.cpp
  
clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/module.modulemap
  clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/stdio.h
  
clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/module.modulemap
  clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stddef.h
  clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stdio.h
  clang/test/Modules/no-undeclared-includes-builtins.cpp

Index: clang/test/Modules/no-undeclared-includes-builtins.cpp
===
--- /dev/null
+++ clang/test/Modules/no-undeclared-includes-builtins.cpp
@@ -0,0 +1,14 @@
+// Test that a [no_undeclared_headers] module can include builtin headers, even
+// if these have been "claimed" by a different module that wraps these builtin
+// headers. libc++ does this, for example.
+//
+// The test inputs used here replicates the relationship between libc++ and
+// glibc. When modularizing glibc, [no_undeclared_headers] must be used to
+// prevent glibc from including the libc++ versions of the C standard library
+// headers.
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/no-undeclared-includes-builtins/libcxx -I %S/Inputs/no-undeclared-includes-builtins/glibc %s
+// expected-no-diagnostics
+
+#include 
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stdio.h
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stdio.h
@@ -0,0 +1 @@
+#include_next 
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stddef.h
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stddef.h
@@ -0,0 +1 @@
+#include_next 
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/module.modulemap
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/module.modulemap
@@ -0,0 +1,5 @@
+module libcxx [system] {
+  header "stddef.h"
+  header "stdio.h"
+  export *
+}
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/stdio.h
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/stdio.h
@@ -0,0 +1 @@
+#include 
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/module.modulemap
===
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/module.modulemap
@@ -0,0 +1,5 @@
+module glibc [system] [no_undeclared_includes] {
+  // glibc relies on the builtin stddef.h, so it has no stddef.h of its own.
+  header "stdio.h"
+  export *
+}
Index: clang/lib/Lex/ModuleMap.cpp
===
--- clang/lib/Lex/ModuleMap.cpp
+++ clang/lib/Lex/ModuleMap.cpp
@@ -387,13 +387,17 @@
.Default(false);
 }
 
+bool ModuleMap::isBuiltinHeader(const FileEntry *File) {
+  return File->getDir() == BuiltinIncludeDir &&
+ ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()));
+}
+
 ModuleMap::HeadersMap::iterator
 ModuleMap::findKnownHeader(const FileEntry *File) {
   resolveHeaderDirectives(File);
   HeadersMap::iterator Known = Headers.find(File);
   if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
-  Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
-  ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName( {
+  Known == Headers.end() && ModuleMap::isBuiltinHeader(File)) {
 HeaderInfo.loadTopLevelSystemModules();
 return Headers.find(File);
   }
Index: clang/lib/Lex/HeaderSearch.cpp
===
--- clang/lib/Lex/HeaderSearch.cpp
+++ clang/lib/Lex/HeaderSearch.cpp
@@ -1276,14 +1276,12 @@
 //
 // It's common that libc++ and system modules will both define such
 // submodules. Make sure cached results for a builtin header won't
-// prevent other builtin modules to po

[PATCH] D81080: [clang-tidy] Compile fix: Change CPlusPlus2a to CPlusPlus20.

2020-06-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
mboehme added a reviewer: sammccall.
mboehme added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, xazax.hun.
Herald added a project: clang.

The name of the option was changed here:

https://github.com/llvm/llvm-project/commit/6a30894391ca671bab16c505eff30c7819bd8e8e


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81080

Files:
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp


Index: clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
@@ -88,7 +88,7 @@
 }
 
 void UseAnyOfAllOfCheck::check(const MatchFinder::MatchResult &Result) {
-  StringRef Ranges = getLangOpts().CPlusPlus2a ? "::ranges" : "";
+  StringRef Ranges = getLangOpts().CPlusPlus20 ? "::ranges" : "";
 
   if (const auto *S = Result.Nodes.getNodeAs("any_of_loop")) {
 if (!isViableLoop(*S, *Result.Context))


Index: clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
@@ -88,7 +88,7 @@
 }
 
 void UseAnyOfAllOfCheck::check(const MatchFinder::MatchResult &Result) {
-  StringRef Ranges = getLangOpts().CPlusPlus2a ? "::ranges" : "";
+  StringRef Ranges = getLangOpts().CPlusPlus20 ? "::ranges" : "";
 
   if (const auto *S = Result.Nodes.getNodeAs("any_of_loop")) {
 if (!isViableLoop(*S, *Result.Context))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81079: [clangd] Add std::move() to a return statement to please some compilers.

2020-06-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
mboehme added a reviewer: sammccall.
mboehme added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, usaxena95, kadircet, arphaman, jkorous, 
MaskRay, ilya-biryukov.
Herald added a project: clang.

This has been causing build errors in Swift CI.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81079

Files:
  clang-tools-extra/clangd/index/FileIndex.cpp


Index: clang-tools-extra/clangd/index/FileIndex.cpp
===
--- clang-tools-extra/clangd/index/FileIndex.cpp
+++ clang-tools-extra/clangd/index/FileIndex.cpp
@@ -201,7 +201,8 @@
 RelB.insert(*Rel);
   }
   IF.Relations = std::move(RelB).build();
-  return IF;
+  // Explicit move here is needed by some compilers.
+  return std::move(IF);
 }
 
 SlabTuple indexMainDecls(ParsedAST &AST) {


Index: clang-tools-extra/clangd/index/FileIndex.cpp
===
--- clang-tools-extra/clangd/index/FileIndex.cpp
+++ clang-tools-extra/clangd/index/FileIndex.cpp
@@ -201,7 +201,8 @@
 RelB.insert(*Rel);
   }
   IF.Relations = std::move(RelB).build();
-  return IF;
+  // Explicit move here is needed by some compilers.
+  return std::move(IF);
 }
 
 SlabTuple indexMainDecls(ParsedAST &AST) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81080: [clang-tidy] Compile fix: Change CPlusPlus2a to CPlusPlus20.

2020-06-03 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Already fixed in

https://github.com/llvm/llvm-project/commit/fd2740143e626ca32432aac0b51b2880a3b1e0bc

Retracting this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81080/new/

https://reviews.llvm.org/D81080



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81079: [clangd] Add std::move() to a return statement to please some compilers.

2020-06-03 Thread Martin Böhme via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGa3220dffcb1d: [clangd] Add std::move() to a return statement 
to please some compilers. (authored by mboehme).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81079/new/

https://reviews.llvm.org/D81079

Files:
  clang-tools-extra/clangd/index/FileIndex.cpp


Index: clang-tools-extra/clangd/index/FileIndex.cpp
===
--- clang-tools-extra/clangd/index/FileIndex.cpp
+++ clang-tools-extra/clangd/index/FileIndex.cpp
@@ -201,7 +201,8 @@
 RelB.insert(*Rel);
   }
   IF.Relations = std::move(RelB).build();
-  return IF;
+  // Explicit move here is needed by some compilers.
+  return std::move(IF);
 }
 
 SlabTuple indexMainDecls(ParsedAST &AST) {


Index: clang-tools-extra/clangd/index/FileIndex.cpp
===
--- clang-tools-extra/clangd/index/FileIndex.cpp
+++ clang-tools-extra/clangd/index/FileIndex.cpp
@@ -201,7 +201,8 @@
 RelB.insert(*Rel);
   }
   IF.Relations = std::move(RelB).build();
-  return IF;
+  // Explicit move here is needed by some compilers.
+  return std::move(IF);
 }
 
 SlabTuple indexMainDecls(ParsedAST &AST) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D80781: [clang] Always allow including builtin headers in [no_undeclared_headers] modules.

2020-06-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Committed as 
https://github.com/llvm/llvm-project/commit/8d74de9de6d6cca552d7de7d0bfd36b6dd7d58dc.

I thought I had added a "Differential Revision:" to the commit message, but 
something must have gone wrong.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80781/new/

https://reviews.llvm.org/D80781



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81392: [clang] Rename Decl::isHidden() to isUnconditionallyVisible()

2020-06-08 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
mboehme added a reviewer: rsmith.
mboehme added a project: clang.
Herald added a subscriber: cfe-commits.

Also invert the sense of the return value.

As pointed out by the FIXME that this change resolves, isHidden() wasn't a very 
accurate name for this function.

I haven't yet changed any of the strings that are output in ASTDumper.cpp / 
JSONNodeDumper.cpp / TextNodeDumper.cpp in response to whether isHidden() is 
set because

a) I'm not sure whether it's actually desired to change these strings (would 
appreciate feedback on this), and

b) In any case, I'd like to get this pure rename out of the way first, without 
any changes to tests. Changing the strings that are output in the various 
...Dumper.cpp files will require changes to quite a few tests, and I'd like to 
make those in a separate change.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81392

Files:
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/AST/DeclObjC.h
  clang/include/clang/Sema/Lookup.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTDumper.cpp
  clang/lib/AST/DeclObjC.cpp
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/Sema/SemaDeclObjC.cpp
  clang/lib/Sema/SemaLookup.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp

Index: clang/lib/Serialization/ASTWriter.cpp
===
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -6041,7 +6041,7 @@
 void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {
   if (Chain && Chain->isProcessingUpdateRecords()) return;
   assert(!WritingAST && "Already writing the AST!");
-  assert(D->isHidden() && "expected a hidden declaration");
+  assert(!D->isUnconditionallyVisible() && "expected a hidden declaration");
   DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, M));
 }
 
Index: clang/lib/Serialization/ASTReader.cpp
===
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -4030,7 +4030,7 @@
 void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
   assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?");
   for (Decl *D : Names) {
-bool wasHidden = D->isHidden();
+bool wasHidden = !D->isUnconditionallyVisible();
 D->setVisibleDespiteOwningModule();
 
 if (wasHidden && SemaObj) {
@@ -4092,9 +4092,9 @@
 /// visible.
 void ASTReader::mergeDefinitionVisibility(NamedDecl *Def,
   NamedDecl *MergedDef) {
-  if (Def->isHidden()) {
+  if (!Def->isUnconditionallyVisible()) {
 // If MergedDef is visible or becomes visible, make the definition visible.
-if (!MergedDef->isHidden())
+if (MergedDef->isUnconditionallyVisible())
   Def->setVisibleDespiteOwningModule();
 else {
   getContext().mergeDefinitionIntoModule(
Index: clang/lib/Sema/SemaLookup.cpp
===
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -1710,7 +1710,8 @@
 /// path (by instantiating a template, you allow it to see the declarations that
 /// your module can see, including those later on in your module).
 bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
-  assert(D->isHidden() && "should not call this: not in slow case");
+  assert(!D->isUnconditionallyVisible() &&
+ "should not call this: not in slow case");
 
   Module *DeclModule = SemaRef.getOwningModule(D);
   assert(DeclModule && "hidden decl has no owning module");
Index: clang/lib/Sema/SemaDeclObjC.cpp
===
--- clang/lib/Sema/SemaDeclObjC.cpp
+++ clang/lib/Sema/SemaDeclObjC.cpp
@@ -1272,7 +1272,8 @@
 
 static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,
   ObjCProtocolDecl *&UndefinedProtocol) {
-  if (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()) {
+  if (!PDecl->hasDefinition() ||
+  !PDecl->getDefinition()->isUnconditionallyVisible()) {
 UndefinedProtocol = PDecl;
 return true;
   }
@@ -3235,7 +3236,7 @@
 return false;
 
   // If either is hidden, it is not considered to match.
-  if (left->isHidden() || right->isHidden())
+  if (!left->isUnconditionallyVisible() || !right->isUnconditionallyVisible())
 return false;
 
   if (left->isDirectMethod() != right->isDirectMethod())
@@ -3494,7 +3495,7 @@
   ObjCMethodList &MethList = InstanceFirst ? Pos->second.first :
  Pos->second.second;
   for (ObjCMethodList *M = &MethList; M; M = M->getNext())
-if (M->getMethod() && !M->getMethod()->isHidden()) {
+if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) {
   if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))

[PATCH] D81392: [clang] Rename Decl::isHidden() to isUnconditionallyVisible()

2020-06-12 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In D81392#2088131 , @rsmith wrote:

> I think renaming the flag in the AST dump output would be a good idea, though 
> it'll be a lot of churn in the tests. I would prefer that we continue to dump 
> a marker only if the declaration is not unconditionally visible rather than 
> reversing the sense of the flag in the dump output.


Agree -- I had tried that experimentally, but it does cause a lot of noise in 
the output.

> Maybe we should dump the ModuleOwnershipKind in general, not only an 
> indicator of whether it's Visible or something else?

I like this -- though would we then always dump the ModuleOwnershipKind (i.e. 
causing a lot of churn, as discussed above) or only if it's 
`VisibleWhenImported` or `ModulePrivate` (i.e. not unconditionally visible)?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81392/new/

https://reviews.llvm.org/D81392



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81392: [clang] Rename Decl::isHidden() to isUnconditionallyVisible()

2020-06-12 Thread Martin Böhme via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG2e92b397ae4b: [clang] Rename Decl::isHidden() to 
isUnconditionallyVisible(). (authored by mboehme).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81392/new/

https://reviews.llvm.org/D81392

Files:
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/AST/DeclObjC.h
  clang/include/clang/Sema/Lookup.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTDumper.cpp
  clang/lib/AST/DeclObjC.cpp
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/Sema/SemaDeclObjC.cpp
  clang/lib/Sema/SemaLookup.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp

Index: clang/lib/Serialization/ASTWriter.cpp
===
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -6057,7 +6057,7 @@
 void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {
   if (Chain && Chain->isProcessingUpdateRecords()) return;
   assert(!WritingAST && "Already writing the AST!");
-  assert(D->isHidden() && "expected a hidden declaration");
+  assert(!D->isUnconditionallyVisible() && "expected a hidden declaration");
   DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, M));
 }
 
Index: clang/lib/Serialization/ASTReader.cpp
===
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -4038,7 +4038,7 @@
 void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
   assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?");
   for (Decl *D : Names) {
-bool wasHidden = D->isHidden();
+bool wasHidden = !D->isUnconditionallyVisible();
 D->setVisibleDespiteOwningModule();
 
 if (wasHidden && SemaObj) {
@@ -4100,9 +4100,9 @@
 /// visible.
 void ASTReader::mergeDefinitionVisibility(NamedDecl *Def,
   NamedDecl *MergedDef) {
-  if (Def->isHidden()) {
+  if (!Def->isUnconditionallyVisible()) {
 // If MergedDef is visible or becomes visible, make the definition visible.
-if (!MergedDef->isHidden())
+if (MergedDef->isUnconditionallyVisible())
   Def->setVisibleDespiteOwningModule();
 else {
   getContext().mergeDefinitionIntoModule(
Index: clang/lib/Sema/SemaLookup.cpp
===
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -1710,7 +1710,8 @@
 /// path (by instantiating a template, you allow it to see the declarations that
 /// your module can see, including those later on in your module).
 bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
-  assert(D->isHidden() && "should not call this: not in slow case");
+  assert(!D->isUnconditionallyVisible() &&
+ "should not call this: not in slow case");
 
   Module *DeclModule = SemaRef.getOwningModule(D);
   assert(DeclModule && "hidden decl has no owning module");
Index: clang/lib/Sema/SemaDeclObjC.cpp
===
--- clang/lib/Sema/SemaDeclObjC.cpp
+++ clang/lib/Sema/SemaDeclObjC.cpp
@@ -1272,7 +1272,8 @@
 
 static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,
   ObjCProtocolDecl *&UndefinedProtocol) {
-  if (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()) {
+  if (!PDecl->hasDefinition() ||
+  !PDecl->getDefinition()->isUnconditionallyVisible()) {
 UndefinedProtocol = PDecl;
 return true;
   }
@@ -3235,7 +3236,7 @@
 return false;
 
   // If either is hidden, it is not considered to match.
-  if (left->isHidden() || right->isHidden())
+  if (!left->isUnconditionallyVisible() || !right->isUnconditionallyVisible())
 return false;
 
   if (left->isDirectMethod() != right->isDirectMethod())
@@ -3494,7 +3495,7 @@
   ObjCMethodList &MethList = InstanceFirst ? Pos->second.first :
  Pos->second.second;
   for (ObjCMethodList *M = &MethList; M; M = M->getNext())
-if (M->getMethod() && !M->getMethod()->isHidden()) {
+if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) {
   if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
 Methods.push_back(M->getMethod());
 }
@@ -3510,7 +3511,7 @@
   ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second :
   Pos->second.first;
   for (ObjCMethodList *M = &MethList2; M; M = M->getNext())
-if (M->getMethod() && !M->getMethod()->isHidden()) {
+if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) {
   if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
 Methods.push_back(M->getMethod());
 }
@@ -3557,7 +3558,7 @@
   ObjCMethodList &MethList = instance ? Pos->second.first : Pos->

[PATCH] D81732: [clang] Replace Decl::isUnconditionallyVisible() with Sema::isVisible()

2020-06-12 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
mboehme added a reviewer: rsmith.
mboehme added a project: clang.
Herald added a subscriber: cfe-commits.

For context, see
https://bugs.llvm.org/show_bug.cgi?id=46248

This handles only the easy cases in Sema/SemaDeclObjC.cpp. The cases in 
AST/DeclObjC.{h,cpp} will require much more work, but there's no reason not to 
get the easy work out of the way now.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81732

Files:
  clang/lib/Sema/SemaDeclObjC.cpp


Index: clang/lib/Sema/SemaDeclObjC.cpp
===
--- clang/lib/Sema/SemaDeclObjC.cpp
+++ clang/lib/Sema/SemaDeclObjC.cpp
@@ -1270,16 +1270,16 @@
   return ActOnObjCContainerStartDefinition(PDecl);
 }
 
-static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,
-  ObjCProtocolDecl 
*&UndefinedProtocol) {
-  if (!PDecl->hasDefinition() ||
-  !PDecl->getDefinition()->isUnconditionallyVisible()) {
+static bool
+NestedProtocolHasNoDefinition(Sema &SemaRef, ObjCProtocolDecl *PDecl,
+  ObjCProtocolDecl *&UndefinedProtocol) {
+  if (!PDecl->hasDefinition() || !SemaRef.isVisible(PDecl->getDefinition())) {
 UndefinedProtocol = PDecl;
 return true;
   }
 
   for (auto *PI : PDecl->protocols())
-if (NestedProtocolHasNoDefinition(PI, UndefinedProtocol)) {
+if (NestedProtocolHasNoDefinition(SemaRef, PI, UndefinedProtocol)) {
   UndefinedProtocol = PI;
   return true;
 }
@@ -1325,7 +1325,7 @@
 ObjCProtocolDecl *UndefinedProtocol;
 
 if (WarnOnDeclarations &&
-NestedProtocolHasNoDefinition(PDecl, UndefinedProtocol)) {
+NestedProtocolHasNoDefinition(*this, PDecl, UndefinedProtocol)) {
   Diag(Pair.second, diag::warn_undef_protocolref) << Pair.first;
   Diag(UndefinedProtocol->getLocation(), 
diag::note_protocol_decl_undefined)
 << UndefinedProtocol;
@@ -1461,7 +1461,7 @@
   // FIXME: Recover nicely in the hidden case.
   ObjCProtocolDecl *forwardDecl = nullptr;
   if (warnOnIncompleteProtocols &&
-  NestedProtocolHasNoDefinition(proto, forwardDecl)) {
+  NestedProtocolHasNoDefinition(*this, proto, forwardDecl)) {
 Diag(identifierLocs[i], diag::warn_undef_protocolref)
   << proto->getDeclName();
 Diag(forwardDecl->getLocation(), diag::note_protocol_decl_undefined)
@@ -3236,7 +3236,7 @@
 return false;
 
   // If either is hidden, it is not considered to match.
-  if (!left->isUnconditionallyVisible() || !right->isUnconditionallyVisible())
+  if (!isVisible(left) || !isVisible(right))
 return false;
 
   if (left->isDirectMethod() != right->isDirectMethod())
@@ -3495,7 +3495,7 @@
   ObjCMethodList &MethList = InstanceFirst ? Pos->second.first :
  Pos->second.second;
   for (ObjCMethodList *M = &MethList; M; M = M->getNext())
-if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) {
+if (M->getMethod() && isVisible(M->getMethod())) {
   if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
 Methods.push_back(M->getMethod());
 }
@@ -3511,7 +3511,7 @@
   ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second :
   Pos->second.first;
   for (ObjCMethodList *M = &MethList2; M; M = M->getNext())
-if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) {
+if (M->getMethod() && isVisible(M->getMethod())) {
   if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
 Methods.push_back(M->getMethod());
 }
@@ -3558,7 +3558,7 @@
   ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
   SmallVector Methods;
   for (ObjCMethodList *M = &MethList; M; M = M->getNext()) {
-if (M->getMethod() && M->getMethod()->isUnconditionallyVisible())
+if (M->getMethod() && isVisible(M->getMethod()))
   return M->getMethod();
   }
   return nullptr;


Index: clang/lib/Sema/SemaDeclObjC.cpp
===
--- clang/lib/Sema/SemaDeclObjC.cpp
+++ clang/lib/Sema/SemaDeclObjC.cpp
@@ -1270,16 +1270,16 @@
   return ActOnObjCContainerStartDefinition(PDecl);
 }
 
-static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,
-  ObjCProtocolDecl *&UndefinedProtocol) {
-  if (!PDecl->hasDefinition() ||
-  !PDecl->getDefinition()->isUnconditionallyVisible()) {
+static bool
+NestedProtocolHasNoDefinition(Sema &SemaRef, ObjCProtocolDecl *PDecl,
+  ObjCProtocolDecl *&UndefinedProtocol) {
+  if (!PDecl->hasDefinition() || !SemaRef.isVisible(PDecl->getDefinition())) {
 UndefinedProtocol = PDecl;
 return true;
   }
 
   for (auto *PI : PDecl->protocols())
-if (NestedProtocolHasNoDefinition(PI, UndefinedProtocol)) {
+if (NestedProtocolHasNoDefinition(SemaRef, PI, UndefinedProtocol)) {
   UndefinedP

[PATCH] D81732: [clang] Replace Decl::isUnconditionallyVisible() with Sema::isVisible()

2020-06-15 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In D81732#2093260 , @dblaikie wrote:

> Test case(s)?


Is there anything specific you have in mind?

This change should be behavior-preserving in the case where 
-fmodules-local-submodule-visibility isn't set, as evidenced by the existing 
tests, which continue to pass.

This change is a small step towards making -fmodules-local-submodule-visibility 
work for Objective-C, but unfortunately we're still a long way off from being 
able to turn this flag on; activating it for existing tests still causes them 
to fail because parts of AST are still using Decl::isUnconditionallyVisible() 
instead of Sema::isVisible(), and that's unfortunately harder to fix.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81732/new/

https://reviews.llvm.org/D81732



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D79486: [clang] Make arrangeCXX{Constructor,Method}Call() publicly available

2020-05-06 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
mboehme added a project: clang.
Herald added a subscriber: cfe-commits.

These are needed for C++ interop in Swift. See this Swift forum discussion for 
details:

https://forums.swift.org/t/calling-c-constructors-looking-for-feedback-on-my-approach/34787/4?u=mboehme


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79486

Files:
  clang/include/clang/CodeGen/CodeGenABITypes.h
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CodeGenABITypes.cpp
  clang/lib/CodeGen/CodeGenTypes.h

Index: clang/lib/CodeGen/CodeGenTypes.h
===
--- clang/lib/CodeGen/CodeGenTypes.h
+++ clang/lib/CodeGen/CodeGenTypes.h
@@ -244,11 +244,22 @@
   unsigned ExtraPrefixArgs,
   unsigned ExtraSuffixArgs,
   bool PassProtoArgs = true);
+  const CGFunctionInfo &
+  arrangeCXXConstructorCall(ArrayRef ArgTypes,
+const CXXConstructorDecl *D,
+CXXCtorType CtorKind,
+unsigned ExtraPrefixArgs,
+unsigned ExtraSuffixArgs,
+bool PassProtoArgs = true);
 
   const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
  const FunctionProtoType *type,
  RequiredArgs required,
  unsigned numPrefixArgs);
+  const CGFunctionInfo &arrangeCXXMethodCall(ArrayRef argTypes,
+ const FunctionProtoType *type,
+ RequiredArgs required,
+ unsigned numPrefixArgs);
   const CGFunctionInfo &
   arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD);
   const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD,
Index: clang/lib/CodeGen/CodeGenABITypes.cpp
===
--- clang/lib/CodeGen/CodeGenABITypes.cpp
+++ clang/lib/CodeGen/CodeGenABITypes.cpp
@@ -63,6 +63,27 @@
   info, {}, args);
 }
 
+const CGFunctionInfo &
+CodeGen::arrangeCXXConstructorCall(CodeGenModule &CGM,
+   ArrayRef argTypes,
+   const CXXConstructorDecl *CD,
+   CXXCtorType CtorKind,
+   unsigned ExtraPrefixArgs,
+   unsigned ExtraSuffixArgs,
+   bool PassProtoArgs) {
+  return CGM.getTypes().arrangeCXXConstructorCall(
+  argTypes, CD, CtorKind, ExtraPrefixArgs, ExtraSuffixArgs, PassProtoArgs);
+}
+
+const CGFunctionInfo &arrangeCXXMethodCall(CodeGenModule &CGM,
+   ArrayRef argTypes,
+   const FunctionProtoType *type,
+   RequiredArgs required,
+   unsigned numPrefixArgs) {
+  return CGM.getTypes().arrangeCXXMethodCall(argTypes, type, required,
+ numPrefixArgs);
+}
+
 llvm::FunctionType *
 CodeGen::convertFreeFunctionType(CodeGenModule &CGM, const FunctionDecl *FD) {
   assert(FD != nullptr && "Expected a non-null function declaration!");
Index: clang/lib/CodeGen/CGCall.cpp
===
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -399,6 +399,17 @@
   for (const auto &Arg : args)
 ArgTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
 
+  return arrangeCXXConstructorCall(ArgTypes, D, CtorKind, ExtraPrefixArgs,
+   ExtraSuffixArgs, PassProtoArgs);
+}
+
+const CGFunctionInfo &
+CodeGenTypes::arrangeCXXConstructorCall(ArrayRef ArgTypes,
+const CXXConstructorDecl *D,
+CXXCtorType CtorKind,
+unsigned ExtraPrefixArgs,
+unsigned ExtraSuffixArgs,
+bool PassProtoArgs) {
   // +1 for implicit this, which should always be args[0].
   unsigned TotalPrefixArgs = 1 + ExtraPrefixArgs;
 
@@ -677,15 +688,23 @@
const FunctionProtoType *proto,
RequiredArgs required,
unsigned numPrefixArgs) {
-  assert(numPrefixArgs + 1 <= args.size() &&
+  // FIXME: Kill copy.
+  auto argTypes = getArgTypesForCall(Context, args);
+
+  return arrangeCXXMethodCall(argTypes, proto, required, numPrefixArgs);
+}
+
+const CGFunctionInfo &
+CodeGenTypes::arrangeCXXMethodCall(ArrayRef argTypes,
+   

[PATCH] D79486: [clang] Make arrangeCXX{Constructor,Method}Call() publicly available

2020-05-07 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Abandoning this change as I've realized I'm going to need additional features, 
specifically those related to extra args passed for virtual base classes.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79486/new/

https://reviews.llvm.org/D79486



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D79942: [clang] Add an API to retrieve implicit constructor arguments.

2020-05-14 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
mboehme added a project: clang.
Herald added a subscriber: cfe-commits.

This is needed in Swift for C++ interop.

As part of this change, I've had to make some changes to the interface of 
CGCXXABI to return the additional parameters separately rather than adding them 
directly to a `CallArgList`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79942

Files:
  clang/include/clang/CodeGen/CodeGenABITypes.h
  clang/lib/CodeGen/CGCXXABI.cpp
  clang/lib/CodeGen/CGCXXABI.h
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGClass.cpp
  clang/lib/CodeGen/CodeGenABITypes.cpp
  clang/lib/CodeGen/ItaniumCXXABI.cpp
  clang/lib/CodeGen/MicrosoftCXXABI.cpp

Index: clang/lib/CodeGen/MicrosoftCXXABI.cpp
===
--- clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -206,7 +206,7 @@
   // lacks a definition for the destructor, non-base destructors must always
   // delegate to or alias the base destructor.
 
-  AddedStructorArgs
+  AddedStructorArgCounts
   buildStructorSignature(GlobalDecl GD,
  SmallVectorImpl &ArgTys) override;
 
@@ -253,10 +253,11 @@
 
   void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override;
 
-  AddedStructorArgs
-  addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating, CallArgList &Args) override;
+  AddedStructorArgs getImplicitConstructorArgs(CodeGenFunction &CGF,
+   const CXXConstructorDecl *D,
+   CXXCtorType Type,
+   bool ForVirtualBase,
+   bool Delegating) override;
 
   void EmitDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *DD,
   CXXDtorType Type, bool ForVirtualBase,
@@ -1261,10 +1262,10 @@
   }
 }
 
-CGCXXABI::AddedStructorArgs
+CGCXXABI::AddedStructorArgCounts
 MicrosoftCXXABI::buildStructorSignature(GlobalDecl GD,
 SmallVectorImpl &ArgTys) {
-  AddedStructorArgs Added;
+  AddedStructorArgCounts Added;
   // TODO: 'for base' flag
   if (isa(GD.getDecl()) &&
   GD.getDtorType() == Dtor_Deleting) {
@@ -1553,9 +1554,9 @@
   }
 }
 
-CGCXXABI::AddedStructorArgs MicrosoftCXXABI::addImplicitConstructorArgs(
+CGCXXABI::AddedStructorArgs MicrosoftCXXABI::getImplicitConstructorArgs(
 CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type,
-bool ForVirtualBase, bool Delegating, CallArgList &Args) {
+bool ForVirtualBase, bool Delegating) {
   assert(Type == Ctor_Complete || Type == Ctor_Base);
 
   // Check if we need a 'most_derived' parameter.
@@ -1570,13 +1571,10 @@
   } else {
 MostDerivedArg = llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete);
   }
-  RValue RV = RValue::get(MostDerivedArg);
   if (FPT->isVariadic()) {
-Args.insert(Args.begin() + 1, CallArg(RV, getContext().IntTy));
-return AddedStructorArgs::prefix(1);
+return AddedStructorArgs::prefix({{MostDerivedArg, getContext().IntTy}});
   }
-  Args.add(RV, getContext().IntTy);
-  return AddedStructorArgs::suffix(1);
+  return AddedStructorArgs::suffix({{MostDerivedArg, getContext().IntTy}});
 }
 
 void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
@@ -4009,7 +4007,7 @@
   CGF.EmitCallArgs(Args, FPT, llvm::makeArrayRef(ArgVec), CD, IsCopy ? 1 : 0);
 
   // Insert any ABI-specific implicit constructor arguments.
-  AddedStructorArgs ExtraArgs =
+  AddedStructorArgCounts ExtraArgs =
   addImplicitConstructorArgs(CGF, CD, Ctor_Complete,
  /*ForVirtualBase=*/false,
  /*Delegating=*/false, Args);
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -203,7 +203,7 @@
 
   void EmitCXXConstructors(const CXXConstructorDecl *D) override;
 
-  AddedStructorArgs
+  AddedStructorArgCounts
   buildStructorSignature(GlobalDecl GD,
  SmallVectorImpl &ArgTys) override;
 
@@ -222,10 +222,11 @@
 
   void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override;
 
-  AddedStructorArgs
-  addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating, CallArgList &Args) override;
+  AddedStructorArgs getImplicitConstructorArgs(CodeGenFunction &CGF,
+   const CXXConstructorDecl *D,
+   CXXCtorType Type,
+   bool ForVirtualBase,
+  

[PATCH] D79942: [clang] Add an API to retrieve implicit constructor arguments.

2020-05-18 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Can someone commit for me? I've applied to have my SVN commit access 
transferred to github, but haven't gotten a response yet.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79942/new/

https://reviews.llvm.org/D79942



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D128439: [Clang][WIP] Don't call distributeTypeAttrsFromDeclarator() on empty list.

2022-06-26 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

Thanks for the pointer -- I wasn't aware of that document yet!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128439/new/

https://reviews.llvm.org/D128439

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D128499: [Clang] Fix: Restore warning inadvertently removed by D126061.

2022-06-27 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 440134.
mboehme marked an inline comment as done.
mboehme added a comment.

Turn off clang-format for attr-declspec-ignored.cpp.

It has existing formatting (indentation within namespaces) that's incompatible
with clang-format.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128499/new/

https://reviews.llvm.org/D128499

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/SemaCXX/attr-declspec-ignored.cpp

Index: clang/test/SemaCXX/attr-declspec-ignored.cpp
===
--- clang/test/SemaCXX/attr-declspec-ignored.cpp
+++ clang/test/SemaCXX/attr-declspec-ignored.cpp
@@ -1,5 +1,10 @@
 // RUN: %clang_cc1 %s -verify -fsyntax-only
 
+// For this test, we want the contents of the namespaces to be indented, which
+// clang-format doesn't like. Also, clang-format reformats the long lines in a
+// way that's difficult to read.
+// clang-format off
+
 namespace test1 {
   __attribute__((visibility("hidden")))  __attribute__((aligned)) class A; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
   // expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
@@ -9,6 +14,30 @@
   // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} 
   __attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
   // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+  // Test that we get the same warnings for type declarations nested in a record.
+  struct X {
+__attribute__((visibility("hidden")))  __attribute__((aligned)) class A; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} 
+__attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+// Also test [[]] attribute syntax. (On a non-nested declaration, these
+// generate a hard "misplaced attributes" error, which we test for
+// elsewhere.)
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] class E; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] struct F; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] union G; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} 
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] enum H {H}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+  };
 }
 
 namespace test2 {
@@ -16,4 +45,18 @@
   __attribute__((visibility("hidden")))  __attribute__((aligned)) struct B {} b;
   __attribute__((visibility("hidden")))  __attribute__((aligned)) union C {} c;
   __attribute__((visibility("hidden")))  

[PATCH] D128499: [Clang] Fix: Restore warning inadvertently removed by D126061.

2022-06-27 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 440492.
mboehme added a comment.

Remove `clang-format` directives from test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128499/new/

https://reviews.llvm.org/D128499

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/SemaCXX/attr-declspec-ignored.cpp

Index: clang/test/SemaCXX/attr-declspec-ignored.cpp
===
--- clang/test/SemaCXX/attr-declspec-ignored.cpp
+++ clang/test/SemaCXX/attr-declspec-ignored.cpp
@@ -9,6 +9,30 @@
   // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} 
   __attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
   // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+  // Test that we get the same warnings for type declarations nested in a record.
+  struct X {
+__attribute__((visibility("hidden")))  __attribute__((aligned)) class A; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} 
+__attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+// Also test [[]] attribute syntax. (On a non-nested declaration, these
+// generate a hard "misplaced attributes" error, which we test for
+// elsewhere.)
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] class E; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] struct F; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] union G; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} 
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] enum H {H}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+  };
 }
 
 namespace test2 {
@@ -16,4 +40,16 @@
   __attribute__((visibility("hidden")))  __attribute__((aligned)) struct B {} b;
   __attribute__((visibility("hidden")))  __attribute__((aligned)) union C {} c;
   __attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D} d;
+
+  struct X {
+__attribute__((visibility("hidden")))  __attribute__((aligned)) class A {} a;
+__attribute__((visibility("hidden")))  __attribute__((aligned)) struct B {} b;
+__attribute__((visibility("hidden")))  __attribute__((aligned)) union C {} c;
+__attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D} d;
+
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] class E {} e;
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] struct F {} f;
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] union G {} g;
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] enum H {H} h;
+  };
 }
Index: clang/lib/Sema/SemaDecl.cpp
==

[PATCH] D128499: [Clang] Fix: Restore warning inadvertently removed by D126061.

2022-06-27 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 2 inline comments as done.
mboehme added inline comments.



Comment at: clang/test/SemaCXX/attr-declspec-ignored.cpp:3-6
+// For this test, we want the contents of the namespaces to be indented, which
+// clang-format doesn't like. Also, clang-format reformats the long lines in a
+// way that's difficult to read.
+// clang-format off

aaron.ballman wrote:
> We don't typically put clang-format markings into tests -- we don't require 
> that tests be formatted, and it's a bug that precommit CI continues to fail 
> because of it (https://github.com/llvm/llvm-project/issues/55982).
> 
> Feel free to remove this bit when landing.
Got it. Done!

I've also commented on the bug.



Comment at: clang/test/SemaCXX/attr-declspec-ignored.cpp:62
+
+// clang-format on

aaron.ballman wrote:
> Same here for this one.
Done.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128499/new/

https://reviews.llvm.org/D128499

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D128499: [Clang] Fix: Restore warning inadvertently removed by D126061.

2022-06-27 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 440494.
mboehme marked 2 inline comments as done.
mboehme added a comment.

Remove trailing spaces


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128499/new/

https://reviews.llvm.org/D128499

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/SemaCXX/attr-declspec-ignored.cpp

Index: clang/test/SemaCXX/attr-declspec-ignored.cpp
===
--- clang/test/SemaCXX/attr-declspec-ignored.cpp
+++ clang/test/SemaCXX/attr-declspec-ignored.cpp
@@ -6,9 +6,33 @@
   __attribute__((visibility("hidden")))  __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
   // expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
   __attribute__((visibility("hidden")))  __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
-  // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} 
+  // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
   __attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
   // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+  // Test that we get the same warnings for type declarations nested in a record.
+  struct X {
+__attribute__((visibility("hidden")))  __attribute__((aligned)) class A; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+// Also test [[]] attribute syntax. (On a non-nested declaration, these
+// generate a hard "misplaced attributes" error, which we test for
+// elsewhere.)
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] class E; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] struct F; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] union G; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] enum H {H}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+  };
 }
 
 namespace test2 {
@@ -16,4 +40,16 @@
   __attribute__((visibility("hidden")))  __attribute__((aligned)) struct B {} b;
   __attribute__((visibility("hidden")))  __attribute__((aligned)) union C {} c;
   __attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D} d;
+
+  struct X {
+__attribute__((visibility("hidden")))  __attribute_

[PATCH] D128499: [Clang] Fix: Restore warning inadvertently removed by D126061.

2022-06-27 Thread Martin Böhme via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG86866107b89c: [Clang] Fix: Restore warning inadvertently 
removed by D126061. (authored by mboehme).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128499/new/

https://reviews.llvm.org/D128499

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/SemaCXX/attr-declspec-ignored.cpp

Index: clang/test/SemaCXX/attr-declspec-ignored.cpp
===
--- clang/test/SemaCXX/attr-declspec-ignored.cpp
+++ clang/test/SemaCXX/attr-declspec-ignored.cpp
@@ -6,9 +6,33 @@
   __attribute__((visibility("hidden")))  __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
   // expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
   __attribute__((visibility("hidden")))  __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
-  // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}} 
+  // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
   __attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
   // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+  // Test that we get the same warnings for type declarations nested in a record.
+  struct X {
+__attribute__((visibility("hidden")))  __attribute__((aligned)) class A; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
+__attribute__((visibility("hidden")))  __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+// Also test [[]] attribute syntax. (On a non-nested declaration, these
+// generate a hard "misplaced attributes" error, which we test for
+// elsewhere.)
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] class E; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] struct F; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] union G; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
+[[gnu::visibility("hidden")]]  [[gnu::aligned]] enum H {H}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+  };
 }
 
 namespace test2 {
@@ -16,4 +40,16 @@
   __attribute__((visibility("hidden")))  __attribute__((aligned)) struct B {} b;
   __attribute__((visibility("hidden")))  __attribute__((aligned)) union C {} c;
   __attribute__((visibility("hidden"))) 

[PATCH] D128706: [Clang] Disable clang-format entirely for clang/test tree.

2022-06-28 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a subscriber: JDevlieghere.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

See discussion here:

https://github.com/llvm/llvm-project/issues/55982

We don't generally expect test files to be formatted according to the
style guide. Indeed, some tests may require specific formatting for the
purposes of the test.

When tests intentionally do not conform to the "correct" formatting,
this causes errors in the CI, which can drown out real errors and causes
people to stop trusting the CI over time.

>From the history of the clang/test/.clang-format file, it looks as if
there have been attempts to make clang-format do a subset of formatting
that would be useful for tests. However, it looks as if it's hard to
make clang-format do exactly the right thing -- see the back-and-forth
between
13316a7 

and
7b5bddf 
.

Instead, I think the best choice is to entirely disable clang-format on
the clang/test directory.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D128706

Files:
  clang/test/.clang-format


Index: clang/test/.clang-format
===
--- clang/test/.clang-format
+++ clang/test/.clang-format
@@ -1,3 +1 @@
-BasedOnStyle: LLVM
-ColumnLimit: 0
-AlwaysBreakTemplateDeclarations: No
+DisableFormat: true


Index: clang/test/.clang-format
===
--- clang/test/.clang-format
+++ clang/test/.clang-format
@@ -1,3 +1 @@
-BasedOnStyle: LLVM
-ColumnLimit: 0
-AlwaysBreakTemplateDeclarations: No
+DisableFormat: true
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D128706: [Clang] Disable clang-format entirely for clang/test tree.

2022-06-28 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In D128706#3615623 , @aaron.ballman 
wrote:

> The changes here LGTM and I think this is the correct way to go. However, 
> since you discovered that it was perhaps intentional that we did some style 
> checking on tests, do you think we should have a brief community RFC just to 
> make sure everyone's on the same page?

Good point. Done:

https://discourse.llvm.org/t/rfc-disable-clang-format-in-the-clang-test-tree/63498


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128706/new/

https://reviews.llvm.org/D128706

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-03-31 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 419642.
mboehme added a comment.
Herald added a project: All.

Uploading newest version.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CodeGenCXX/annotate-type.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp

Index: clang/test/SemaCXX/annotate-type.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {
+  void f() [[clang::annotate_type("foo")]];
+};
+
+template  struct is_same {
+  static constexpr bool value = false;
+};
+
+template  struct is_same {
+  static constexpr bool value = true;
+};
+
+static_assert(is_same::value);
+static_assert(is_same::value);
+static_assert(is_same::value);
+
+// Cannot overload on types that only differ by `annotate_type` attribute.
+void f(int) {} // expected-note {{previous definition is here}}
+void f(int [[clang::annotate_type("foo")]]) {
+} // expected-error {{redefinition of 'f'}}
+
+// Cannot specialize on types that only differ by `annotate_type` attribute.
+template  struct S2 {};
+
+template <> struct S2 {}; // expected-note {{previous definition is here}}
+
+template <>
+struct S2{}; // expected-error {{redefinition of 'S2'}}
Index: clang/test/Sema/annotate-type.c
===
--- /dev/null
+++ clang/test/Sema/annotate-type.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -fsyntax-only -fdouble-square-bracket-attributes -verify
+
+void foo(float * [[clang::annotate_type("foo")]] a) {
+  int [[clang::annotate_type("bar")]] x1;
+  int * [[clang::annotate_type("bar")]] x2;
+  int * [[clang::annotate_type(1)]] x3; // expected-error {{'annotate_type' attribute requires a string}}
+  int * [[clang::annotate_type("bar", 1)]] x4;
+
+  // GNU spelling is not supported
+  int __attribute__((annotate_type("bar"))) y1; // expected-warning {{unknown attribute 'annotate_type' ignored}}
+  int * __attribute__((annotate_type("bar"))) y2; // expected-warning {{unknown attribute 'annotate_type' ignored}}
+}
Index: clang/test/CodeGenCXX/annotate-type.cpp
===
--- /dev/null
+++ clang/test/CodeGenCXX/annotate-type.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm-only %s -emit-llvm -o
+// - | FileCheck %s
+
+// Test that `annotate_type` does not affect mangled names.
+
+int *[[clang::annotate_type("foo")]] f(int *[[clang::annotate_type("foo")]],
+   int [[clang::annotate_type("foo")]]) {
+  return nullptr;
+}
+// CHECK: @_Z1fPii
+
+template  struct S {};
+
+S
+g(S) {
+  return {};
+}
+// CHECK: @_Z1g1SIPiE()
Index: clang/lib/Sema/SemaType.cpp
===
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -8098,6 +8098,30 @@
 CurType = T;
 }
 
+static void HandleAnnotateTypeAttr(TypeProcessingState &State,
+   QualType &CurType, const ParsedAttr &Attr) {
+  Sema &S = State.getSema();
+
+  // Make sure that there is a string literal as the annotation's first
+  // argument.
+  StringRef Str;
+  if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str))
+return;
+
+  llvm::SmallVector Args;
+  Args.reserve(Attr.getNumArgs() - 1);
+  for (unsigned Idx = 1; Idx < Attr.getNumArgs(); Idx++) {
+assert(!Attr.isArgIdent(Idx));
+Args.push_back(Attr.getArgAsExpr(Idx));
+  }
+  if (!S.ConstantFoldAttrArgs(Attr, Args)) {
+return;
+  }
+  auto *AnnotateTypeAttr =
+  AnnotateTypeAttr::Create(S.Context, Str, Args.data(), Args.size(), Attr);
+  CurType = State.getAttributedType(AnnotateTypeAttr, CurType, CurType);
+}
+
 static void HandleLifetimeBoundAttr(TypeProcessingState &State,
 QualType &CurType,
 ParsedAttr &Attr) {
@@ -8158,10 +8182,11 @@
   if (!IsTypeAttr)
 continue;
 }
-  } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr)) {
+  } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr) &&
+ attr.getKind() != ParsedAttr::AT_AnnotateType) {
 // Otherwise, only consider type processing for a C++11 attribute if
 // it's actually been applied to a type.
-// We also allow C++11 address_space and
+// We also allow C++11 address_space and annotate_type and
 // OpenCL language address space attributes to pass through.
 continue;
   }
@@ -8359,6 +8384,11 @@
   

[PATCH] D114235: [clang] Extend ParsedAttr to allow custom handling for type attributes

2022-04-01 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

As mentioned in my previous comment, here is the RFC proposing a new 
`annotate_type` attribute:

https://discourse.llvm.org/t/rfc-new-attribute-annotate-type-iteration-2/61378


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D114235/new/

https://reviews.llvm.org/D114235

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-07 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 421159.
mboehme added a comment.

Add documentation and a unit test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CodeGenCXX/annotate-type.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/unittests/AST/AttrTest.cpp

Index: clang/unittests/AST/AttrTest.cpp
===
--- clang/unittests/AST/AttrTest.cpp
+++ clang/unittests/AST/AttrTest.cpp
@@ -7,7 +7,10 @@
 //===--===//
 
 #include "clang/AST/Attr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/AttrKinds.h"
+#include "clang/Tooling/Tooling.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -15,10 +18,81 @@
 
 namespace {
 
+using clang::ast_matchers::constantExpr;
+using clang::ast_matchers::equals;
+using clang::ast_matchers::functionDecl;
+using clang::ast_matchers::has;
+using clang::ast_matchers::hasDescendant;
+using clang::ast_matchers::hasName;
+using clang::ast_matchers::integerLiteral;
+using clang::ast_matchers::match;
+using clang::ast_matchers::selectFirst;
+using clang::ast_matchers::stringLiteral;
+using clang::tooling::buildASTFromCode;
+
 TEST(Attr, Doc) {
   EXPECT_THAT(Attr::getDocumentation(attr::Used).str(),
   testing::HasSubstr("The compiler must emit the definition even "
  "if it appears to be unused"));
 }
 
+const FunctionDecl *getFunctionNode(clang::ASTUnit *AST,
+const std::string &Name) {
+  auto Result =
+  match(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("fn");
+}
+
+TEST(Attr, AnnotateType) {
+
+  // Test that the AnnotateType attribute shows up in the right places and that
+  // it stores its arguments correctly.
+
+  auto AST = buildASTFromCode(R"cpp(
+void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
+   int [[clang::annotate_type("bar")]]);
+)cpp");
+
+  const FunctionDecl *Func = getFunctionNode(AST.get(), "f");
+
+  {
+TypeLoc Parm0TL = Func->getParamDecl(0)->getTypeSourceInfo()->getTypeLoc();
+const auto PointerTL = Parm0TL.getAs();
+ASSERT_FALSE(PointerTL.isNull());
+const auto AttributedTL =
+PointerTL.getPointeeLoc().getAs();
+ASSERT_FALSE(AttributedTL.isNull());
+ASSERT_NE(AttributedTL.getAttr(), nullptr);
+ASSERT_TRUE(AttributedTL.getModifiedLoc().getAs());
+
+const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+ASSERT_NE(Annotate, nullptr);
+EXPECT_EQ(Annotate->getAnnotation(), "foo");
+
+EXPECT_EQ(Annotate->args_size(), 2);
+const auto *StringLit = selectFirst(
+"str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
+ *Annotate->args_begin()[0], Func->getASTContext()));
+ASSERT_NE(StringLit, nullptr);
+EXPECT_EQ(StringLit->getString(), "arg1");
+EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2)).bind("int"))),
+*Annotate->args_begin()[1], Func->getASTContext())
+  .size(),
+  1);
+  }
+
+  {
+TypeLoc Parm1TL = Func->getParamDecl(1)->getTypeSourceInfo()->getTypeLoc();
+const auto AttributedTL = Parm1TL.getAs();
+ASSERT_FALSE(AttributedTL.isNull());
+ASSERT_TRUE(AttributedTL.getModifiedLoc().getType() ==
+Func->getASTContext().IntTy);
+
+const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+ASSERT_NE(Annotate, nullptr);
+EXPECT_EQ(Annotate->getAnnotation(), "bar");
+  }
+}
+
 } // namespace
Index: clang/test/SemaCXX/annotate-type.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {
+  void f() [[clang::annotate_type("foo")]];
+};
+
+template  struct is_same {
+  static constexpr bool value = false;
+};
+
+template  struct is_same {
+  static constexpr bool value = true;
+};
+
+static_assert(is_same::value);
+static_assert(is_same::value);
+static_assert(is_same::value);
+
+// Cannot overload on types that only differ by `annotate_type` attribute.
+void f(int) {} // expected-note {{previous definition is here}}
+void f(int [[clang::annotate_type("foo")]]) {} // expected-error {{redefinition of 'f'}}
+
+// Cannot specialize on types that only differ by `annotate_type` attribute.
+template  struct S2 {};
+
+template 

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-08 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 421506.
mboehme added a comment.

Documentation: Added discussion of type system implications and fixed syntax
error in example.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CodeGenCXX/annotate-type.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/unittests/AST/AttrTest.cpp

Index: clang/unittests/AST/AttrTest.cpp
===
--- clang/unittests/AST/AttrTest.cpp
+++ clang/unittests/AST/AttrTest.cpp
@@ -7,7 +7,10 @@
 //===--===//
 
 #include "clang/AST/Attr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/AttrKinds.h"
+#include "clang/Tooling/Tooling.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -15,10 +18,81 @@
 
 namespace {
 
+using clang::ast_matchers::constantExpr;
+using clang::ast_matchers::equals;
+using clang::ast_matchers::functionDecl;
+using clang::ast_matchers::has;
+using clang::ast_matchers::hasDescendant;
+using clang::ast_matchers::hasName;
+using clang::ast_matchers::integerLiteral;
+using clang::ast_matchers::match;
+using clang::ast_matchers::selectFirst;
+using clang::ast_matchers::stringLiteral;
+using clang::tooling::buildASTFromCode;
+
 TEST(Attr, Doc) {
   EXPECT_THAT(Attr::getDocumentation(attr::Used).str(),
   testing::HasSubstr("The compiler must emit the definition even "
  "if it appears to be unused"));
 }
 
+const FunctionDecl *getFunctionNode(clang::ASTUnit *AST,
+const std::string &Name) {
+  auto Result =
+  match(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("fn");
+}
+
+TEST(Attr, AnnotateType) {
+
+  // Test that the AnnotateType attribute shows up in the right places and that
+  // it stores its arguments correctly.
+
+  auto AST = buildASTFromCode(R"cpp(
+void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
+   int [[clang::annotate_type("bar")]]);
+)cpp");
+
+  const FunctionDecl *Func = getFunctionNode(AST.get(), "f");
+
+  {
+TypeLoc Parm0TL = Func->getParamDecl(0)->getTypeSourceInfo()->getTypeLoc();
+const auto PointerTL = Parm0TL.getAs();
+ASSERT_FALSE(PointerTL.isNull());
+const auto AttributedTL =
+PointerTL.getPointeeLoc().getAs();
+ASSERT_FALSE(AttributedTL.isNull());
+ASSERT_NE(AttributedTL.getAttr(), nullptr);
+ASSERT_TRUE(AttributedTL.getModifiedLoc().getAs());
+
+const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+ASSERT_NE(Annotate, nullptr);
+EXPECT_EQ(Annotate->getAnnotation(), "foo");
+
+EXPECT_EQ(Annotate->args_size(), 2);
+const auto *StringLit = selectFirst(
+"str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
+ *Annotate->args_begin()[0], Func->getASTContext()));
+ASSERT_NE(StringLit, nullptr);
+EXPECT_EQ(StringLit->getString(), "arg1");
+EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2)).bind("int"))),
+*Annotate->args_begin()[1], Func->getASTContext())
+  .size(),
+  1);
+  }
+
+  {
+TypeLoc Parm1TL = Func->getParamDecl(1)->getTypeSourceInfo()->getTypeLoc();
+const auto AttributedTL = Parm1TL.getAs();
+ASSERT_FALSE(AttributedTL.isNull());
+ASSERT_TRUE(AttributedTL.getModifiedLoc().getType() ==
+Func->getASTContext().IntTy);
+
+const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+ASSERT_NE(Annotate, nullptr);
+EXPECT_EQ(Annotate->getAnnotation(), "bar");
+  }
+}
+
 } // namespace
Index: clang/test/SemaCXX/annotate-type.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {
+  void f() [[clang::annotate_type("foo")]];
+};
+
+template  struct is_same {
+  static constexpr bool value = false;
+};
+
+template  struct is_same {
+  static constexpr bool value = true;
+};
+
+static_assert(is_same::value);
+static_assert(is_same::value);
+static_assert(is_same::value);
+
+// Cannot overload on types that only differ by `annotate_type` attribute.
+void f(int) {} // expected-note {{previous definition is here}}
+void f(int [[clang::annotate_type("foo")]]) {} // expected-error {{redefinition of 'f'}}
+
+// Cannot specialize on types that only differ by `ann

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-08 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 2 inline comments as done.
mboehme added inline comments.



Comment at: clang/include/clang/Basic/AttrDocs.td:6387
+additional information specific to the annotation category. The optional
+arguments must be constant expressions of arbitrary type.
+

xazax.hun wrote:
> Do we want to mention that it is not actually part of the type system (i.e., 
> annotated and unannotated types are considered the same)?
Good point -- I've added some relevant parts from the RFC below.



Comment at: clang/include/clang/Basic/AttrDocs.td:6393
+
+  int* [[clang::annotate("category1", "foo", 1)]] 
f(int[[clang::annotate("category2"]] *);
+

xazax.hun wrote:
> Missing closing paren for the second annotate. 
Oops -- thanks for catching. Fixed.



Comment at: clang/lib/AST/TypePrinter.cpp:1686
+  // would require retrieving the attribute arguments, which we don't have 
here.
+  if (T->getAttrKind() == attr::AnnotateType)
+return;

xazax.hun wrote:
> Would it make sense to print something without the arguments? I wonder which 
> behavior would be less confusing.
TBH I'm not sure. Is TypePrinter used only to produce debug output or is it 
required that the output of TypePrinter will parse again correctly?

The reason I'm asking is because `annotate_type` has a mandatory first 
argument; if we need the output to be parseable, we would have to print some 
dummy string, e.g. `[[clang::annotate_type("arguments_omitted")]]`. This seems 
a bit strange, but maybe it's still worth doing. OTOH, if the output is used 
only for debugging, I guess we could print something like 
`[[clang::annotate_type(...)]]`, which doesn't parse but by that very nature 
makes it clear that we don't have all the information here.

I guess both of these options could have limited use -- they would at least 
make it clear that there is an annotation on the type, though without the 
arguments, we can't know what the actual annotation is.

Would appreciate some more input on the wider context here.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-11 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 421930.
mboehme marked 2 inline comments as done.
mboehme added a comment.

Various changes in response to review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CodeGenCXX/annotate-type.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/unittests/AST/AttrTest.cpp

Index: clang/unittests/AST/AttrTest.cpp
===
--- clang/unittests/AST/AttrTest.cpp
+++ clang/unittests/AST/AttrTest.cpp
@@ -7,7 +7,10 @@
 //===--===//
 
 #include "clang/AST/Attr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/AttrKinds.h"
+#include "clang/Tooling/Tooling.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -15,10 +18,154 @@
 
 namespace {
 
+using clang::ast_matchers::constantExpr;
+using clang::ast_matchers::equals;
+using clang::ast_matchers::functionDecl;
+using clang::ast_matchers::has;
+using clang::ast_matchers::hasDescendant;
+using clang::ast_matchers::hasName;
+using clang::ast_matchers::integerLiteral;
+using clang::ast_matchers::match;
+using clang::ast_matchers::selectFirst;
+using clang::ast_matchers::stringLiteral;
+using clang::ast_matchers::varDecl;
+using clang::tooling::buildASTFromCode;
+using clang::tooling::buildASTFromCodeWithArgs;
+
 TEST(Attr, Doc) {
   EXPECT_THAT(Attr::getDocumentation(attr::Used).str(),
   testing::HasSubstr("The compiler must emit the definition even "
  "if it appears to be unused"));
 }
 
+const FunctionDecl *getFunctionNode(ASTUnit *AST, const std::string &Name) {
+  auto Result =
+  match(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("fn");
+}
+
+const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
+  auto Result = match(varDecl(hasName(Name)).bind("var"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("var");
+}
+
+template 
+void AssertAnnotatedAs(TypeLoc TL, llvm::StringRef annotation,
+   ModifiedTypeLoc &ModifiedTL,
+   const AnnotateTypeAttr **AnnotateOut = nullptr) {
+  const auto AttributedTL = TL.getAs();
+  ASSERT_FALSE(AttributedTL.isNull());
+  ModifiedTL = AttributedTL.getModifiedLoc().getAs();
+  ASSERT_TRUE(ModifiedTL);
+
+  ASSERT_NE(AttributedTL.getAttr(), nullptr);
+  const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+  ASSERT_NE(Annotate, nullptr);
+  EXPECT_EQ(Annotate->getAnnotation(), annotation);
+  if (AnnotateOut) {
+*AnnotateOut = Annotate;
+  }
+}
+
+TEST(Attr, AnnotateType) {
+
+  // Test that the AnnotateType attribute shows up in the right places and that
+  // it stores its arguments correctly.
+
+  auto AST = buildASTFromCode(R"cpp(
+void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
+   int [[clang::annotate_type("bar")]]);
+
+int [[clang::annotate_type("int")]] * [[clang::annotate_type("ptr")]]
+  array[10] [[clang::annotate_type("arr")]];
+
+void (* [[clang::annotate_type("funcptr")]] fp)(void);
+
+struct S { int mem; };
+int [[clang::annotate_type("int")]]
+S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
+)cpp");
+
+  {
+const FunctionDecl *Func = getFunctionNode(AST.get(), "f");
+
+// First parameter.
+const auto PointerTL = Func->getParamDecl(0)
+   ->getTypeSourceInfo()
+   ->getTypeLoc()
+   .getAs();
+ASSERT_FALSE(PointerTL.isNull());
+PointerTypeLoc PointerPointerTL;
+const AnnotateTypeAttr *Annotate;
+AssertAnnotatedAs(PointerTL.getPointeeLoc(), "foo", PointerPointerTL,
+  &Annotate);
+
+EXPECT_EQ(Annotate->args_size(), 2);
+const auto *StringLit = selectFirst(
+"str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
+ *Annotate->args_begin()[0], AST->getASTContext()));
+ASSERT_NE(StringLit, nullptr);
+EXPECT_EQ(StringLit->getString(), "arg1");
+EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2)).bind("int"))),
+*Annotate->args_begin()[1], AST->getASTContext())
+  .size(),
+  1);
+
+// Second parameter.
+BuiltinTypeLoc IntTL;
+AssertAnnotatedAs(Func

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-11 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 4 inline comments as done.
mboehme added a comment.

In D111548#3439039 , @aaron.ballman 
wrote:

> Also, you should add a release note about the new attribute

Done.

and check the Precommit CI pipeline failure out:

> Failed Tests (1):
>
>   Clang :: CodeGenCXX/annotate-type.cpp

Fixed.




Comment at: clang/include/clang/Basic/AttrDocs.td:6409-6411
+- The attribute will not cause any additional data to be output to LLVM IR,
+  object files or debug information. It is only intended to be consumed using
+  Clang APIs by source-level static analysis tools such as Clang-Tidy.

aaron.ballman wrote:
> It seems to me that because we found reasons for `annotate` to be lowered to 
> LLVM IR, we'll find reasons to lower `annotate_type` eventually. I worry that 
> if we document this, we'll never be able to modify the attribute to output 
> information to LLVM IR because people will rely on it not doing so and be 
> broken by a change. Are we sure we want to commit to this as part of the 
> design?
Good point. I've done what I think you're implying, namely that we should 
remove the comments saying that the attribute won't have any any effect on the 
LLVM IR?



Comment at: clang/lib/AST/TypePrinter.cpp:1686
+  // would require retrieving the attribute arguments, which we don't have 
here.
+  if (T->getAttrKind() == attr::AnnotateType)
+return;

aaron.ballman wrote:
> mboehme wrote:
> > xazax.hun wrote:
> > > Would it make sense to print something without the arguments? I wonder 
> > > which behavior would be less confusing.
> > TBH I'm not sure. Is TypePrinter used only to produce debug output or is it 
> > required that the output of TypePrinter will parse again correctly?
> > 
> > The reason I'm asking is because `annotate_type` has a mandatory first 
> > argument; if we need the output to be parseable, we would have to print 
> > some dummy string, e.g. `[[clang::annotate_type("arguments_omitted")]]`. 
> > This seems a bit strange, but maybe it's still worth doing. OTOH, if the 
> > output is used only for debugging, I guess we could print something like 
> > `[[clang::annotate_type(...)]]`, which doesn't parse but by that very 
> > nature makes it clear that we don't have all the information here.
> > 
> > I guess both of these options could have limited use -- they would at least 
> > make it clear that there is an annotation on the type, though without the 
> > arguments, we can't know what the actual annotation is.
> > 
> > Would appreciate some more input on the wider context here.
> Yeah, the trouble is that you need a `TypeLoc` in order to get back to the 
> actual attribute information that stores the arguments. But the type printer 
> is printing types not specific instances of types at the location they're 
> used.
> 
> The goal with the pretty printers is to print something back that the user 
> actually wrote, but it's not always possible and so this is sort of a 
> best-effort.
So what's your position -- should I not print the attribute at all (which is 
what I'm doing right now) or should I print it as something like 
`[[clang::annotate_type(...)]]`?



Comment at: clang/lib/Sema/SemaAttr.cpp:396-408
+if (E->getType()->isArrayType())
+  E = ImpCastExprToType(E, Context.getPointerType(E->getType()),
+clang::CK_ArrayToPointerDecay)
+  .get();
+if (E->getType()->isFunctionType())
+  E = ImplicitCastExpr::Create(Context,
+   Context.getPointerType(E->getType()),

aaron.ballman wrote:
> This seems an awful lot like doing `DefaultFunctionArrayLValueConversion()` 
> here -- can you call that to do the heavy lifting?
> 
> Oh, I see we're just shuffling code around. Feel free to ignore or make as an 
> NFC change if you'd prefer.
By "NFC change", you mean I could submit this separately as an NFC change?

Since this change is already part of this patch, I think I'd prefer to just 
keep it in here, if that's OK?



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

aaron.ballman wrote:
> Can you also add some test coverage for applying the attribute to a 
> declaration instead of a type or not giving it any arguments? Also, should 
> test arguments which are not a constant expression.
I've added tests as you suggested, though I put most of them in 
Sema/annotate-type.c, as they're not specific to C++.

Thanks for prompting me to do this -- the tests caused me to notice and fix a 
number of bugs.

I haven't managed to diagnose the case when the attribute appears at the 
beginning of the declaration. It seems to me that, at the point where I've 
added the check, this case is indistinguishable from an attribute that appears 
on the type. In both cases, the `TAL` is `T

[PATCH] D123783: [clang] Eliminate TypeProcessingState::trivial.

2022-04-14 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This flag is redundant -- it's true iff `savedAttrs` is empty.

Querying `savedAttrs.empty()` should not take any more time than querying the
`trivial` flag, so this should not have a performance impact either.

I noticed this while working on https://reviews.llvm.org/D111548.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D123783

Files:
  clang/lib/Sema/SemaType.cpp


Index: clang/lib/Sema/SemaType.cpp
===
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -166,9 +166,6 @@
 /// DeclSpec.
 unsigned chunkIndex;
 
-/// Whether there are non-trivial modifications to the decl spec.
-bool trivial;
-
 /// Whether we saved the attributes in the decl spec.
 bool hasSavedAttrs;
 
@@ -200,8 +197,8 @@
   public:
 TypeProcessingState(Sema &sema, Declarator &declarator)
 : sema(sema), declarator(declarator),
-  chunkIndex(declarator.getNumTypeObjects()), trivial(true),
-  hasSavedAttrs(false), parsedNoDeref(false) {}
+  chunkIndex(declarator.getNumTypeObjects()), hasSavedAttrs(false),
+  parsedNoDeref(false) {}
 
 Sema &getSema() const {
   return sema;
@@ -238,7 +235,6 @@
   DeclSpec &spec = getMutableDeclSpec();
   llvm::append_range(savedAttrs,
  llvm::make_pointer_range(spec.getAttributes()));
-  trivial &= savedAttrs.empty();
   hasSavedAttrs = true;
 }
 
@@ -330,7 +326,8 @@
 bool didParseNoDeref() const { return parsedNoDeref; }
 
 ~TypeProcessingState() {
-  if (trivial) return;
+  if (savedAttrs.empty())
+return;
 
   restoreDeclSpecAttrs();
 }


Index: clang/lib/Sema/SemaType.cpp
===
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -166,9 +166,6 @@
 /// DeclSpec.
 unsigned chunkIndex;
 
-/// Whether there are non-trivial modifications to the decl spec.
-bool trivial;
-
 /// Whether we saved the attributes in the decl spec.
 bool hasSavedAttrs;
 
@@ -200,8 +197,8 @@
   public:
 TypeProcessingState(Sema &sema, Declarator &declarator)
 : sema(sema), declarator(declarator),
-  chunkIndex(declarator.getNumTypeObjects()), trivial(true),
-  hasSavedAttrs(false), parsedNoDeref(false) {}
+  chunkIndex(declarator.getNumTypeObjects()), hasSavedAttrs(false),
+  parsedNoDeref(false) {}
 
 Sema &getSema() const {
   return sema;
@@ -238,7 +235,6 @@
   DeclSpec &spec = getMutableDeclSpec();
   llvm::append_range(savedAttrs,
  llvm::make_pointer_range(spec.getAttributes()));
-  trivial &= savedAttrs.empty();
   hasSavedAttrs = true;
 }
 
@@ -330,7 +326,8 @@
 bool didParseNoDeref() const { return parsedNoDeref; }
 
 ~TypeProcessingState() {
-  if (trivial) return;
+  if (savedAttrs.empty())
+return;
 
   restoreDeclSpecAttrs();
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D123783: [clang] Eliminate TypeProcessingState::trivial.

2022-04-18 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang/lib/Sema/SemaType.cpp:170
 /// Whether we saved the attributes in the decl spec.
 bool hasSavedAttrs;
 

aaron.ballman wrote:
> Isn't the same true for this variable? It seems like:
> 
> `trivial` == `savedAttrs.empty()`
> `hasSavedAttrs` == `!savedAttrs.empty()`
That's what I also thought at first -- but the situation for `hasSavedAttrs` is 
a bit more complicated. It gets set whenever `saveDeclAttrs()` is called, even 
if it doesn't actually end up saving any attributes (i.e. if 
`spec.getAttributes()` is empty).

`hasSavedAttrs` is then used to prevent any further calls to 
`saveDeclSpecAttrs()` from doing anything:

```
// Don't try to save them multiple times.
if (hasSavedAttrs) return;
```

Conceivably, `spec` _might_ have had attributes added to it in the meantime -- 
not sure? It might be OK to just replace this logic with `if 
(!savedAttrs.empty()) return;` -- but I'm not familiar enough with how this 
code gets used and therefore decided it would be better not to change it. Can 
you give additional input on this?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123783/new/

https://reviews.llvm.org/D123783

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D123783: [clang] Eliminate TypeProcessingState::trivial.

2022-04-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked an inline comment as done.
mboehme added inline comments.



Comment at: clang/lib/Sema/SemaType.cpp:170
 /// Whether we saved the attributes in the decl spec.
 bool hasSavedAttrs;
 

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > Isn't the same true for this variable? It seems like:
> > > 
> > > `trivial` == `savedAttrs.empty()`
> > > `hasSavedAttrs` == `!savedAttrs.empty()`
> > That's what I also thought at first -- but the situation for 
> > `hasSavedAttrs` is a bit more complicated. It gets set whenever 
> > `saveDeclAttrs()` is called, even if it doesn't actually end up saving any 
> > attributes (i.e. if `spec.getAttributes()` is empty).
> > 
> > `hasSavedAttrs` is then used to prevent any further calls to 
> > `saveDeclSpecAttrs()` from doing anything:
> > 
> > ```
> > // Don't try to save them multiple times.
> > if (hasSavedAttrs) return;
> > ```
> > 
> > Conceivably, `spec` _might_ have had attributes added to it in the meantime 
> > -- not sure? It might be OK to just replace this logic with `if 
> > (!savedAttrs.empty()) return;` -- but I'm not familiar enough with how this 
> > code gets used and therefore decided it would be better not to change it. 
> > Can you give additional input on this?
> I have the impression that is an oversight in the code rather than an 
> intentional behavior. I think it may be okay to replace the logic with 
> `!savedAttrs.empty()` as well; if you do that, do you get any test failures? 
> (If you do, then that's a sign something else might be going on.)
I just tried:

```
// Don't try to save them multiple times.
if (!savedAttrs.empty()) return;
```

 I didn't get any test failures.

Of course, this isn't proof that this is _really_ OK, but it's an indication.

You know this code better than I do, so I would defer to you: How do you think 
I should proceed? Should I eliminate `hasSavedAttrs` too?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123783/new/

https://reviews.llvm.org/D123783

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 423856.
mboehme marked 2 inline comments as done.
mboehme added a comment.

Changes in response to review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/AST/attr-annotate-type.c
  clang/test/CodeGenCXX/annotate-type.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/unittests/AST/AttrTest.cpp

Index: clang/unittests/AST/AttrTest.cpp
===
--- clang/unittests/AST/AttrTest.cpp
+++ clang/unittests/AST/AttrTest.cpp
@@ -7,7 +7,10 @@
 //===--===//
 
 #include "clang/AST/Attr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/AttrKinds.h"
+#include "clang/Tooling/Tooling.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -15,10 +18,154 @@
 
 namespace {
 
+using clang::ast_matchers::constantExpr;
+using clang::ast_matchers::equals;
+using clang::ast_matchers::functionDecl;
+using clang::ast_matchers::has;
+using clang::ast_matchers::hasDescendant;
+using clang::ast_matchers::hasName;
+using clang::ast_matchers::integerLiteral;
+using clang::ast_matchers::match;
+using clang::ast_matchers::selectFirst;
+using clang::ast_matchers::stringLiteral;
+using clang::ast_matchers::varDecl;
+using clang::tooling::buildASTFromCode;
+using clang::tooling::buildASTFromCodeWithArgs;
+
 TEST(Attr, Doc) {
   EXPECT_THAT(Attr::getDocumentation(attr::Used).str(),
   testing::HasSubstr("The compiler must emit the definition even "
  "if it appears to be unused"));
 }
 
+const FunctionDecl *getFunctionNode(ASTUnit *AST, const std::string &Name) {
+  auto Result =
+  match(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("fn");
+}
+
+const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
+  auto Result = match(varDecl(hasName(Name)).bind("var"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("var");
+}
+
+template 
+void AssertAnnotatedAs(TypeLoc TL, llvm::StringRef annotation,
+   ModifiedTypeLoc &ModifiedTL,
+   const AnnotateTypeAttr **AnnotateOut = nullptr) {
+  const auto AttributedTL = TL.getAs();
+  ASSERT_FALSE(AttributedTL.isNull());
+  ModifiedTL = AttributedTL.getModifiedLoc().getAs();
+  ASSERT_TRUE(ModifiedTL);
+
+  ASSERT_NE(AttributedTL.getAttr(), nullptr);
+  const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+  ASSERT_NE(Annotate, nullptr);
+  EXPECT_EQ(Annotate->getAnnotation(), annotation);
+  if (AnnotateOut) {
+*AnnotateOut = Annotate;
+  }
+}
+
+TEST(Attr, AnnotateType) {
+
+  // Test that the AnnotateType attribute shows up in the right places and that
+  // it stores its arguments correctly.
+
+  auto AST = buildASTFromCode(R"cpp(
+void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
+   int [[clang::annotate_type("bar")]]);
+
+int [[clang::annotate_type("int")]] * [[clang::annotate_type("ptr")]]
+  array[10] [[clang::annotate_type("arr")]];
+
+void (* [[clang::annotate_type("funcptr")]] fp)(void);
+
+struct S { int mem; };
+int [[clang::annotate_type("int")]]
+S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
+)cpp");
+
+  {
+const FunctionDecl *Func = getFunctionNode(AST.get(), "f");
+
+// First parameter.
+const auto PointerTL = Func->getParamDecl(0)
+   ->getTypeSourceInfo()
+   ->getTypeLoc()
+   .getAs();
+ASSERT_FALSE(PointerTL.isNull());
+PointerTypeLoc PointerPointerTL;
+const AnnotateTypeAttr *Annotate;
+AssertAnnotatedAs(PointerTL.getPointeeLoc(), "foo", PointerPointerTL,
+  &Annotate);
+
+EXPECT_EQ(Annotate->args_size(), 2);
+const auto *StringLit = selectFirst(
+"str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
+ *Annotate->args_begin()[0], AST->getASTContext()));
+ASSERT_NE(StringLit, nullptr);
+EXPECT_EQ(StringLit->getString(), "arg1");
+EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2)).bind("int"))),
+*Annotate->args_begin()[1], AST->getASTContext())
+  .size(),
+  1);
+
+// Second parameter.
+BuiltinTypeLoc IntT

[PATCH] D124081: [clang] Reject non-declaration C++11 attributes on declarations.

2022-04-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a reviewer: aaron.ballman.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Clang has allowed this so far, transferring the attributes to the declaration's
type instead, as would be done for GNU syntax attributes. However, the C++
standard is clear that attributes in certain positions appertain to the
declaration, so we shouldn't allow type attributes in these positions.

For backwards compatibility, we only warn on non-declaration attributes that we
have historically allowed to be put on declarations. We only produce errors for
new non-declaration attributes.

Depends On D111548 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124081

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -4220,6 +4220,9 @@
 OS << "/*IsStmt=*/";
 OS << (Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr"))
<< ",\n";
+OS << "/*IsDecl=*/";
+OS << (!Attr.isSubClassOf("TypeAttr") && !Attr.isSubClassOf("StmtAttr"))
+   << ",\n";
 OS << "/*IsKnownToGCC=*/";
 OS << IsKnownToGCC(Attr) << ",\n";
 OS << "/*IsSupportedByPragmaAttribute=*/";
Index: clang/test/SemaCXX/annotate-type.cpp
===
--- clang/test/SemaCXX/annotate-type.cpp
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -2,10 +2,7 @@
 
 struct S1 {
   void f() [[clang::annotate_type("foo")]];
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("foo")]] void g();
+  [[clang::annotate_type("foo")]] void g(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 };
 
 template  struct is_same {
@@ -50,10 +47,8 @@
 
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-namespace [[clang::annotate_type("foo")]] my_namespace {}
-struct [[clang::annotate_type("foo")]] S3{};
+namespace [[clang::annotate_type("foo")]] my_namespace {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S3{}; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 void f4() {
-  for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {}
+  for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 }
Index: clang/test/Sema/annotate-type.c
===
--- clang/test/Sema/annotate-type.c
+++ clang/test/Sema/annotate-type.c
@@ -17,10 +17,7 @@
   int *__attribute__((annotate_type("bar"))) y2; // expected-warning {{unknown attribute 'annotate_type' ignored}}
 
   // Various error cases
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("bar")]] int *z1;
+  [[clang::annotate_type("bar")]] int *z1; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   int *z2 [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a statement}}
   int *[[clang::annotate_type(1)]] z3; // expected-error {{'annotate_type' attribute requires a string}}
@@ -33,7 +30,5 @@
 }
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-[[clang::annotate_type("bar")]] int *global;
-void g([[clang::annotate_type("bar")]] int);
+[[clang::annotate_type("bar")]] int *global; // expected-error {{'anno

[PATCH] D124083: [clang] [draft] Reject C++ 11 attributes appertaining to the wrong entity type.

2022-04-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a reviewer: aaron.ballman.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: cfe-commits, sstefan1.
Herald added a project: clang.

DRAFT -- do not review.

Depends On D111548 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124083

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Parse/ParseOpenMP.cpp
  clang/lib/Parse/ParsePragma.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaStmtAttr.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3728,7 +3728,7 @@
 if (!StmtSubjects.empty()) {
   OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
   OS << "const Decl *D) const override {\n";
-  OS << "  S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)\n";
+  OS << "  S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n";
   OS << "<< AL << D->getLocation();\n";
   OS << "  return false;\n";
   OS << "}\n\n";
@@ -3772,7 +3772,7 @@
 if (!DeclSubjects.empty()) {
   OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, ";
   OS << "const Stmt *St) const override {\n";
-  OS << "  S.Diag(AL.getLoc(), diag::err_decl_attribute_invalid_on_stmt)\n";
+  OS << "  S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_stmt)\n";
   OS << "<< AL << St->getBeginLoc();\n";
   OS << "  return false;\n";
   OS << "}\n\n";
@@ -4220,6 +4220,9 @@
 OS << "/*IsStmt=*/";
 OS << (Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr"))
<< ",\n";
+OS << "/*IsDecl=*/";
+OS << (!Attr.isSubClassOf("TypeAttr") && !Attr.isSubClassOf("StmtAttr"))
+   << ",\n";
 OS << "/*IsKnownToGCC=*/";
 OS << IsKnownToGCC(Attr) << ",\n";
 OS << "/*IsSupportedByPragmaAttribute=*/";
Index: clang/test/SemaCXX/annotate-type.cpp
===
--- clang/test/SemaCXX/annotate-type.cpp
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -2,10 +2,7 @@
 
 struct S1 {
   void f() [[clang::annotate_type("foo")]];
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("foo")]] void g();
+  [[clang::annotate_type("foo")]] void g(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 };
 
 template  struct is_same {
@@ -52,8 +49,8 @@
 // Different declarations hit different code paths, so they need separate tests.
 // FIXME: Clang currently generally doesn't prohibit type-only C++11
 // attributes on declarations.
-namespace [[clang::annotate_type("foo")]] my_namespace {}
-struct [[clang::annotate_type("foo")]] S3{};
+namespace [[clang::annotate_type("foo")]] my_namespace {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S3{}; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 void f4() {
-  for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {}
+  for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 }
Index: clang/test/Sema/annotate-type.c
===
--- clang/test/Sema/annotate-type.c
+++ clang/test/Sema/annotate-type.c
@@ -17,10 +17,7 @@
   int *__attribute__((annotate_type("bar"))) y2; // expected-warning {{unknown attribute 'annotate_type' ignored}}
 
   // Various error cases
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("bar")]] int *z1;
+  [[clang::annotate_type("bar")]] int *z1; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   int *z2 [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   [[clang::annotate_type("bar")]]; // expect

[PATCH] D124081: [clang] [draft] Reject non-declaration C++11 attributes on declarations.

2022-04-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

I'd like to mark this patch as a draft so that Herald doesn't keep adding 
reviewers -- but I'm not sure how?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124081/new/

https://reviews.llvm.org/D124081

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 5 inline comments as done.
mboehme added inline comments.



Comment at: clang/lib/AST/TypePrinter.cpp:1686
+  // would require retrieving the attribute arguments, which we don't have 
here.
+  if (T->getAttrKind() == attr::AnnotateType)
+return;

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > mboehme wrote:
> > > > xazax.hun wrote:
> > > > > Would it make sense to print something without the arguments? I 
> > > > > wonder which behavior would be less confusing.
> > > > TBH I'm not sure. Is TypePrinter used only to produce debug output or 
> > > > is it required that the output of TypePrinter will parse again 
> > > > correctly?
> > > > 
> > > > The reason I'm asking is because `annotate_type` has a mandatory first 
> > > > argument; if we need the output to be parseable, we would have to print 
> > > > some dummy string, e.g. 
> > > > `[[clang::annotate_type("arguments_omitted")]]`. This seems a bit 
> > > > strange, but maybe it's still worth doing. OTOH, if the output is used 
> > > > only for debugging, I guess we could print something like 
> > > > `[[clang::annotate_type(...)]]`, which doesn't parse but by that very 
> > > > nature makes it clear that we don't have all the information here.
> > > > 
> > > > I guess both of these options could have limited use -- they would at 
> > > > least make it clear that there is an annotation on the type, though 
> > > > without the arguments, we can't know what the actual annotation is.
> > > > 
> > > > Would appreciate some more input on the wider context here.
> > > Yeah, the trouble is that you need a `TypeLoc` in order to get back to 
> > > the actual attribute information that stores the arguments. But the type 
> > > printer is printing types not specific instances of types at the location 
> > > they're used.
> > > 
> > > The goal with the pretty printers is to print something back that the 
> > > user actually wrote, but it's not always possible and so this is sort of 
> > > a best-effort.
> > So what's your position -- should I not print the attribute at all (which 
> > is what I'm doing right now) or should I print it as something like 
> > `[[clang::annotate_type(...)]]`?
> I think we need to print *something* here because the type printer is used by 
> `QualType::getAsStringInternal()` and `QualType::print()` which are used to 
> produce diagnostics when giving a `QualType` argument. So I would  print 
> `[[clang::annotate]]` as a stop-gap with a FIXME comment that it would be 
> nice to print the arguments here some day.
Makes sense -- done!



Comment at: clang/lib/Parse/ParseDecl.cpp:3184
+continue;
+  // We reject AT_LifetimeBound and AT_AnyX86NoCfCheck, even though 
they
+  // are type attributes, because we historically haven't allowed these

aaron.ballman wrote:
> I think this is a FIXME situation -- our policy is to diagnose attributes 
> that are being ignored, and it seems pretty important to (someday, not part 
> of this patch) diagnose these. Especially the lifetime bound attribute given 
> that it's intended to help harden code.
Maybe I should clarify what's happening here: We _do_ produce diagnostics 
(errors) for AT_LifetimeBound and AT_AnyX86NoCfCheck, both before and after 
this patch. (For these attributes, the code falls through to the 
`Diag(PA.getLoc(), diag::err_attribute_not_type_attr)` call below.)

Before this patch, we would reject (produce errors for) _all_ C++11 attributes 
here. Now, we only reject non-type attributes, and in addition, we also reject 
AT_LifetimeBound and AT_AnyX86NoCfCheck (even though they are type attributes) 
because we historically haven't allowed them to be used in this way. There are 
tests for this behavior, so it seemed important to preserve it.



Comment at: clang/lib/Sema/SemaAttr.cpp:396-408
+if (E->getType()->isArrayType())
+  E = ImpCastExprToType(E, Context.getPointerType(E->getType()),
+clang::CK_ArrayToPointerDecay)
+  .get();
+if (E->getType()->isFunctionType())
+  E = ImplicitCastExpr::Create(Context,
+   Context.getPointerType(E->getType()),

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > This seems an awful lot like doing 
> > > `DefaultFunctionArrayLValueConversion()` here -- can you call that to do 
> > > the heavy lifting?
> > > 
> > > Oh, I see we're just shuffling code around. Feel free to ignore or make 
> > > as an NFC change if you'd prefer.
> > By "NFC change", you mean I could submit this separately as an NFC change?
> > 
> > Since this change is already part of this patch, I think I'd prefer to just 
> > keep it in here, if that's OK?
> > By "NFC change", you mean I could submit this separately as an NFC change?
> 
> Yup!
> 
> > Since this change is already part of this patch, I think I'd prefer to ju

[PATCH] D124081: [clang] [draft] Reject non-declaration C++11 attributes on declarations.

2022-04-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In D124081#3461731 , @aaron.ballman 
wrote:

> In D124081#3461556 , @mboehme wrote:
>
>> I'd like to mark this patch as a draft so that Herald doesn't keep adding 
>> reviewers -- but I'm not sure how?
>
> In that case, I usually set the permissions on the review explicitly so that 
> I'm the only one who can view the draft (but this means precommit CI won't 
> run on it).

In this case, though, I want to be able to show the draft to others and discuss 
it with them. I guess this technique doesn't work for that?

> Most often folks just add [WIP] to the title and reviewers know to ignore the 
> review until the [WIP] is removed.

Ah -- thanks. I'll add [WIP[ then.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124081/new/

https://reviews.llvm.org/D124081

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D124081: [clang] [WIP] Reject non-declaration C++11 attributes on declarations.

2022-04-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In D124081#3461761 , @aaron.ballman 
wrote:

> 

[snip]

> However, it sounds to me like you want anyone to be able to come by and 
> comment if they'd like while you're prepping the patch, so I'd stick with the 
> [WIP] in the title like you've got.

Exactly. Thanks for the explanations!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124081/new/

https://reviews.llvm.org/D124081

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D123783: [clang] Eliminate TypeProcessingState::trivial.

2022-04-26 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 425145.
mboehme marked an inline comment as done.
mboehme added a comment.

Eliminate hasSavedAttrs as well.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123783/new/

https://reviews.llvm.org/D123783

Files:
  clang/lib/Sema/SemaType.cpp


Index: clang/lib/Sema/SemaType.cpp
===
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -166,12 +166,6 @@
 /// DeclSpec.
 unsigned chunkIndex;
 
-/// Whether there are non-trivial modifications to the decl spec.
-bool trivial;
-
-/// Whether we saved the attributes in the decl spec.
-bool hasSavedAttrs;
-
 /// The original set of attributes on the DeclSpec.
 SmallVector savedAttrs;
 
@@ -200,8 +194,7 @@
   public:
 TypeProcessingState(Sema &sema, Declarator &declarator)
 : sema(sema), declarator(declarator),
-  chunkIndex(declarator.getNumTypeObjects()), trivial(true),
-  hasSavedAttrs(false), parsedNoDeref(false) {}
+  chunkIndex(declarator.getNumTypeObjects()), parsedNoDeref(false) {}
 
 Sema &getSema() const {
   return sema;
@@ -233,13 +226,12 @@
 /// Save the current set of attributes on the DeclSpec.
 void saveDeclSpecAttrs() {
   // Don't try to save them multiple times.
-  if (hasSavedAttrs) return;
+  if (!savedAttrs.empty())
+return;
 
   DeclSpec &spec = getMutableDeclSpec();
   llvm::append_range(savedAttrs,
  llvm::make_pointer_range(spec.getAttributes()));
-  trivial &= savedAttrs.empty();
-  hasSavedAttrs = true;
 }
 
 /// Record that we had nowhere to put the given type attribute.
@@ -330,23 +322,18 @@
 bool didParseNoDeref() const { return parsedNoDeref; }
 
 ~TypeProcessingState() {
-  if (trivial) return;
+  if (savedAttrs.empty())
+return;
 
-  restoreDeclSpecAttrs();
+  getMutableDeclSpec().getAttributes().clearListOnly();
+  for (ParsedAttr *AL : savedAttrs)
+getMutableDeclSpec().getAttributes().addAtEnd(AL);
 }
 
   private:
 DeclSpec &getMutableDeclSpec() const {
   return const_cast(declarator.getDeclSpec());
 }
-
-void restoreDeclSpecAttrs() {
-  assert(hasSavedAttrs);
-
-  getMutableDeclSpec().getAttributes().clearListOnly();
-  for (ParsedAttr *AL : savedAttrs)
-getMutableDeclSpec().getAttributes().addAtEnd(AL);
-}
   };
 } // end anonymous namespace
 


Index: clang/lib/Sema/SemaType.cpp
===
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -166,12 +166,6 @@
 /// DeclSpec.
 unsigned chunkIndex;
 
-/// Whether there are non-trivial modifications to the decl spec.
-bool trivial;
-
-/// Whether we saved the attributes in the decl spec.
-bool hasSavedAttrs;
-
 /// The original set of attributes on the DeclSpec.
 SmallVector savedAttrs;
 
@@ -200,8 +194,7 @@
   public:
 TypeProcessingState(Sema &sema, Declarator &declarator)
 : sema(sema), declarator(declarator),
-  chunkIndex(declarator.getNumTypeObjects()), trivial(true),
-  hasSavedAttrs(false), parsedNoDeref(false) {}
+  chunkIndex(declarator.getNumTypeObjects()), parsedNoDeref(false) {}
 
 Sema &getSema() const {
   return sema;
@@ -233,13 +226,12 @@
 /// Save the current set of attributes on the DeclSpec.
 void saveDeclSpecAttrs() {
   // Don't try to save them multiple times.
-  if (hasSavedAttrs) return;
+  if (!savedAttrs.empty())
+return;
 
   DeclSpec &spec = getMutableDeclSpec();
   llvm::append_range(savedAttrs,
  llvm::make_pointer_range(spec.getAttributes()));
-  trivial &= savedAttrs.empty();
-  hasSavedAttrs = true;
 }
 
 /// Record that we had nowhere to put the given type attribute.
@@ -330,23 +322,18 @@
 bool didParseNoDeref() const { return parsedNoDeref; }
 
 ~TypeProcessingState() {
-  if (trivial) return;
+  if (savedAttrs.empty())
+return;
 
-  restoreDeclSpecAttrs();
+  getMutableDeclSpec().getAttributes().clearListOnly();
+  for (ParsedAttr *AL : savedAttrs)
+getMutableDeclSpec().getAttributes().addAtEnd(AL);
 }
 
   private:
 DeclSpec &getMutableDeclSpec() const {
   return const_cast(declarator.getDeclSpec());
 }
-
-void restoreDeclSpecAttrs() {
-  assert(hasSavedAttrs);
-
-  getMutableDeclSpec().getAttributes().clearListOnly();
-  for (ParsedAttr *AL : savedAttrs)
-getMutableDeclSpec().getAttributes().addAtEnd(AL);
-}
   };
 } // end anonymous namespace
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D123783: [clang] Eliminate TypeProcessingState::trivial.

2022-04-26 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked an inline comment as done.
mboehme added inline comments.



Comment at: clang/lib/Sema/SemaType.cpp:170
 /// Whether we saved the attributes in the decl spec.
 bool hasSavedAttrs;
 

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > mboehme wrote:
> > > > aaron.ballman wrote:
> > > > > Isn't the same true for this variable? It seems like:
> > > > > 
> > > > > `trivial` == `savedAttrs.empty()`
> > > > > `hasSavedAttrs` == `!savedAttrs.empty()`
> > > > That's what I also thought at first -- but the situation for 
> > > > `hasSavedAttrs` is a bit more complicated. It gets set whenever 
> > > > `saveDeclAttrs()` is called, even if it doesn't actually end up saving 
> > > > any attributes (i.e. if `spec.getAttributes()` is empty).
> > > > 
> > > > `hasSavedAttrs` is then used to prevent any further calls to 
> > > > `saveDeclSpecAttrs()` from doing anything:
> > > > 
> > > > ```
> > > > // Don't try to save them multiple times.
> > > > if (hasSavedAttrs) return;
> > > > ```
> > > > 
> > > > Conceivably, `spec` _might_ have had attributes added to it in the 
> > > > meantime -- not sure? It might be OK to just replace this logic with 
> > > > `if (!savedAttrs.empty()) return;` -- but I'm not familiar enough with 
> > > > how this code gets used and therefore decided it would be better not to 
> > > > change it. Can you give additional input on this?
> > > I have the impression that is an oversight in the code rather than an 
> > > intentional behavior. I think it may be okay to replace the logic with 
> > > `!savedAttrs.empty()` as well; if you do that, do you get any test 
> > > failures? (If you do, then that's a sign something else might be going 
> > > on.)
> > I just tried:
> > 
> > ```
> > // Don't try to save them multiple times.
> > if (!savedAttrs.empty()) return;
> > ```
> > 
> >  I didn't get any test failures.
> > 
> > Of course, this isn't proof that this is _really_ OK, but it's an 
> > indication.
> > 
> > You know this code better than I do, so I would defer to you: How do you 
> > think I should proceed? Should I eliminate `hasSavedAttrs` too?
> I think you should eliminate it -- I don't think the behavior here was 
> intentional (based on what I can tell from the code).
OK -- done!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123783/new/

https://reviews.llvm.org/D123783

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-28 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 5 inline comments as done.
mboehme added inline comments.



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > mboehme wrote:
> > > > aaron.ballman wrote:
> > > > > Can you also add some test coverage for applying the attribute to a 
> > > > > declaration instead of a type or not giving it any arguments? Also, 
> > > > > should test arguments which are not a constant expression.
> > > > I've added tests as you suggested, though I put most of them in 
> > > > Sema/annotate-type.c, as they're not specific to C++.
> > > > 
> > > > Thanks for prompting me to do this -- the tests caused me to notice and 
> > > > fix a number of bugs.
> > > > 
> > > > I haven't managed to diagnose the case when the attribute appears at 
> > > > the beginning of the declaration. It seems to me that, at the point 
> > > > where I've added the check, this case is indistinguishable from an 
> > > > attribute that appears on the type. In both cases, the `TAL` is 
> > > > `TAL_DeclSpec`, and the attribute is contained in 
> > > > `DeclSpec::getAttributes()`. This is because 
> > > > `Parser::ParseSimpleDeclaration` forwards the declaration attributes to 
> > > > the `DeclSpec`:
> > > > 
> > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > 
> > > > I believe if I wanted to prohibit this case, I would need to add a 
> > > > check to `Parser::ParseStatementOrDeclaration` and prohibit any 
> > > > occurrences of `annotate_type` there. However, this seems the wrong 
> > > > place to do this because it doesn't contain any specific processing for 
> > > > other attributes.
> > > > 
> > > > I've noticed that Clang also doesn't prohibit other type attributes 
> > > > (even ones with C++ 11 syntax) from being applied to declarations. For 
> > > > example: https://godbolt.org/z/Yj1zWY7nn
> > > > 
> > > > How do you think I should proceed here? I think the underlying issue is 
> > > > that Clang doesn't always distinguish cleanly between declaration 
> > > > attributes and type attributes, and fixing this might be nontrivial.
> > > > How do you think I should proceed here? I think the underlying issue is 
> > > > that Clang doesn't always distinguish cleanly between declaration 
> > > > attributes and type attributes, and fixing this might be nontrivial.
> > > 
> > > This is a general issue with attribute processing. I would imagine that 
> > > SemaDeclAttr.cpp should be able to diagnose that case when the attribute 
> > > only applies to types and not declarations, but it'd take some 
> > > investigation for me to be sure.
> > > 
> > > Because this issue isn't new to your situation, I'd recommend filing an 
> > > issue about the general problem and then we can solve that later.
> > I've done some more investigation myself, and I think I've come up with a 
> > solution; actually, two potential solutions. I have draft patches for both 
> > of these; I wanted to run these by you here first, so I haven't opened a 
> > bug yet.
> > 
> > I'd appreciate your input on how you'd prefer me to proceed with this. I do 
> > think it makes sense to do this work now because otherwise, people will 
> > start putting `annotate_type` in places where it doesn't belong, and then 
> > we'll have to keep supporting that in the future.
> > 
> > **My preferred solution**
> > 
> > https://reviews.llvm.org/D124081
> > 
> > This adds a function `DiagnoseCXX11NonDeclAttrs()` and calls it in all 
> > places where we should reject attributes that can't be put on declarations. 
> > (As part of this work, I noticed that `gsl::suppress` should be a 
> > `DeclOrStmtAttr`, not just a `StmtAttr`.)
> > 
> > Advantages:
> > - Not very invasive.
> > Disadvantages:
> > - Need to make sure we call `DiagnoseCXX11NonDeclAttrs()` everywhere that 
> > non-declaration attributes should be rejected. (Not sure if I've identified 
> > all of those places yet?)
> > 
> > **Alternative solution**
> > 
> > https://reviews.llvm.org/D124083
> > 
> > This adds an `appertainsTo` parameter to `ParseCXX11Attributes()` and other 
> > "parse attributes" functions that call it. This parameter specifies whether 
> > the attributes in the place where they're currently being parsed appertain 
> > to a declaration, statement or type. If `ParseCXX11Attributes()` encounters 
> > an attribute that is not compatible with `appertainsTo`, it outputs a 
> > diagnostic.
> > 
> > Advantages:
> > - Every call to `ParseCXX11Attributes()` _has_ to specify `appertainsTo` -- 
> > so there's no risk of missing some case where we have to output diagnostics
> > Disadvantages:
> > - This change is _much_ more invasive.
> > - It's not always clear what value to specify for `appertainsTo`. The 
> > poster child for this is `Parser::ParseStatementOrDeclaration()`: As the 
> > name says, we don't yet 

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-04-29 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > mboehme wrote:
> > > > aaron.ballman wrote:
> > > > > mboehme wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > Can you also add some test coverage for applying the attribute to 
> > > > > > > a declaration instead of a type or not giving it any arguments? 
> > > > > > > Also, should test arguments which are not a constant expression.
> > > > > > I've added tests as you suggested, though I put most of them in 
> > > > > > Sema/annotate-type.c, as they're not specific to C++.
> > > > > > 
> > > > > > Thanks for prompting me to do this -- the tests caused me to notice 
> > > > > > and fix a number of bugs.
> > > > > > 
> > > > > > I haven't managed to diagnose the case when the attribute appears 
> > > > > > at the beginning of the declaration. It seems to me that, at the 
> > > > > > point where I've added the check, this case is indistinguishable 
> > > > > > from an attribute that appears on the type. In both cases, the 
> > > > > > `TAL` is `TAL_DeclSpec`, and the attribute is contained in 
> > > > > > `DeclSpec::getAttributes()`. This is because 
> > > > > > `Parser::ParseSimpleDeclaration` forwards the declaration 
> > > > > > attributes to the `DeclSpec`:
> > > > > > 
> > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > > > 
> > > > > > I believe if I wanted to prohibit this case, I would need to add a 
> > > > > > check to `Parser::ParseStatementOrDeclaration` and prohibit any 
> > > > > > occurrences of `annotate_type` there. However, this seems the wrong 
> > > > > > place to do this because it doesn't contain any specific processing 
> > > > > > for other attributes.
> > > > > > 
> > > > > > I've noticed that Clang also doesn't prohibit other type attributes 
> > > > > > (even ones with C++ 11 syntax) from being applied to declarations. 
> > > > > > For example: https://godbolt.org/z/Yj1zWY7nn
> > > > > > 
> > > > > > How do you think I should proceed here? I think the underlying 
> > > > > > issue is that Clang doesn't always distinguish cleanly between 
> > > > > > declaration attributes and type attributes, and fixing this might 
> > > > > > be nontrivial.
> > > > > > How do you think I should proceed here? I think the underlying 
> > > > > > issue is that Clang doesn't always distinguish cleanly between 
> > > > > > declaration attributes and type attributes, and fixing this might 
> > > > > > be nontrivial.
> > > > > 
> > > > > This is a general issue with attribute processing. I would imagine 
> > > > > that SemaDeclAttr.cpp should be able to diagnose that case when the 
> > > > > attribute only applies to types and not declarations, but it'd take 
> > > > > some investigation for me to be sure.
> > > > > 
> > > > > Because this issue isn't new to your situation, I'd recommend filing 
> > > > > an issue about the general problem and then we can solve that later.
> > > > I've done some more investigation myself, and I think I've come up with 
> > > > a solution; actually, two potential solutions. I have draft patches for 
> > > > both of these; I wanted to run these by you here first, so I haven't 
> > > > opened a bug yet.
> > > > 
> > > > I'd appreciate your input on how you'd prefer me to proceed with this. 
> > > > I do think it makes sense to do this work now because otherwise, people 
> > > > will start putting `annotate_type` in places where it doesn't belong, 
> > > > and then we'll have to keep supporting that in the future.
> > > > 
> > > > **My preferred solution**
> > > > 
> > > > https://reviews.llvm.org/D124081
> > > > 
> > > > This adds a function `DiagnoseCXX11NonDeclAttrs()` and calls it in all 
> > > > places where we should reject attributes that can't be put on 
> > > > declarations. (As part of this work, I noticed that `gsl::suppress` 
> > > > should be a `DeclOrStmtAttr`, not just a `StmtAttr`.)
> > > > 
> > > > Advantages:
> > > > - Not very invasive.
> > > > Disadvantages:
> > > > - Need to make sure we call `DiagnoseCXX11NonDeclAttrs()` everywhere 
> > > > that non-declaration attributes should be rejected. (Not sure if I've 
> > > > identified all of those places yet?)
> > > > 
> > > > **Alternative solution**
> > > > 
> > > > https://reviews.llvm.org/D124083
> > > > 
> > > > This adds an `appertainsTo` parameter to `ParseCXX11Attributes()` and 
> > > > other "parse attributes" functions that call it. This parameter 
> > > > specifies whether the attributes in the place where they're currently 
> > > > being parsed appertain to a declaration, statement or type. If 
> > > > `ParseCXX11Attributes()` encounters an attribute that is not compatible 
> > > > with `appertainsTo`, it outputs a diagnostic.
> > > > 
> > > > Advantages:
> > > > - Every call to `ParseCXX1

[PATCH] D123783: [clang] Eliminate TypeProcessingState::trivial.

2022-04-29 Thread Martin Böhme via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
mboehme marked an inline comment as done.
Closed by commit rG23c10e8d0f97: [clang] Eliminate 
TypeProcessingState::trivial. (authored by mboehme).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123783/new/

https://reviews.llvm.org/D123783

Files:
  clang/lib/Sema/SemaType.cpp


Index: clang/lib/Sema/SemaType.cpp
===
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -166,12 +166,6 @@
 /// DeclSpec.
 unsigned chunkIndex;
 
-/// Whether there are non-trivial modifications to the decl spec.
-bool trivial;
-
-/// Whether we saved the attributes in the decl spec.
-bool hasSavedAttrs;
-
 /// The original set of attributes on the DeclSpec.
 SmallVector savedAttrs;
 
@@ -200,8 +194,7 @@
   public:
 TypeProcessingState(Sema &sema, Declarator &declarator)
 : sema(sema), declarator(declarator),
-  chunkIndex(declarator.getNumTypeObjects()), trivial(true),
-  hasSavedAttrs(false), parsedNoDeref(false) {}
+  chunkIndex(declarator.getNumTypeObjects()), parsedNoDeref(false) {}
 
 Sema &getSema() const {
   return sema;
@@ -233,13 +226,12 @@
 /// Save the current set of attributes on the DeclSpec.
 void saveDeclSpecAttrs() {
   // Don't try to save them multiple times.
-  if (hasSavedAttrs) return;
+  if (!savedAttrs.empty())
+return;
 
   DeclSpec &spec = getMutableDeclSpec();
   llvm::append_range(savedAttrs,
  llvm::make_pointer_range(spec.getAttributes()));
-  trivial &= savedAttrs.empty();
-  hasSavedAttrs = true;
 }
 
 /// Record that we had nowhere to put the given type attribute.
@@ -330,23 +322,18 @@
 bool didParseNoDeref() const { return parsedNoDeref; }
 
 ~TypeProcessingState() {
-  if (trivial) return;
+  if (savedAttrs.empty())
+return;
 
-  restoreDeclSpecAttrs();
+  getMutableDeclSpec().getAttributes().clearListOnly();
+  for (ParsedAttr *AL : savedAttrs)
+getMutableDeclSpec().getAttributes().addAtEnd(AL);
 }
 
   private:
 DeclSpec &getMutableDeclSpec() const {
   return const_cast(declarator.getDeclSpec());
 }
-
-void restoreDeclSpecAttrs() {
-  assert(hasSavedAttrs);
-
-  getMutableDeclSpec().getAttributes().clearListOnly();
-  for (ParsedAttr *AL : savedAttrs)
-getMutableDeclSpec().getAttributes().addAtEnd(AL);
-}
   };
 } // end anonymous namespace
 


Index: clang/lib/Sema/SemaType.cpp
===
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -166,12 +166,6 @@
 /// DeclSpec.
 unsigned chunkIndex;
 
-/// Whether there are non-trivial modifications to the decl spec.
-bool trivial;
-
-/// Whether we saved the attributes in the decl spec.
-bool hasSavedAttrs;
-
 /// The original set of attributes on the DeclSpec.
 SmallVector savedAttrs;
 
@@ -200,8 +194,7 @@
   public:
 TypeProcessingState(Sema &sema, Declarator &declarator)
 : sema(sema), declarator(declarator),
-  chunkIndex(declarator.getNumTypeObjects()), trivial(true),
-  hasSavedAttrs(false), parsedNoDeref(false) {}
+  chunkIndex(declarator.getNumTypeObjects()), parsedNoDeref(false) {}
 
 Sema &getSema() const {
   return sema;
@@ -233,13 +226,12 @@
 /// Save the current set of attributes on the DeclSpec.
 void saveDeclSpecAttrs() {
   // Don't try to save them multiple times.
-  if (hasSavedAttrs) return;
+  if (!savedAttrs.empty())
+return;
 
   DeclSpec &spec = getMutableDeclSpec();
   llvm::append_range(savedAttrs,
  llvm::make_pointer_range(spec.getAttributes()));
-  trivial &= savedAttrs.empty();
-  hasSavedAttrs = true;
 }
 
 /// Record that we had nowhere to put the given type attribute.
@@ -330,23 +322,18 @@
 bool didParseNoDeref() const { return parsedNoDeref; }
 
 ~TypeProcessingState() {
-  if (trivial) return;
+  if (savedAttrs.empty())
+return;
 
-  restoreDeclSpecAttrs();
+  getMutableDeclSpec().getAttributes().clearListOnly();
+  for (ParsedAttr *AL : savedAttrs)
+getMutableDeclSpec().getAttributes().addAtEnd(AL);
 }
 
   private:
 DeclSpec &getMutableDeclSpec() const {
   return const_cast(declarator.getDeclSpec());
 }
-
-void restoreDeclSpecAttrs() {
-  assert(hasSavedAttrs);
-
-  getMutableDeclSpec().getAttributes().clearListOnly();
-  for (ParsedAttr *AL : savedAttrs)
-getMutableDeclSpec().getAttributes().addAtEnd(AL);
-}
   };
 } // end anonymous namespace
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 426977.
mboehme added a comment.

Rebased to a more recent base change.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/AST/attr-annotate-type.c
  clang/test/CodeGenCXX/annotate-type.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/unittests/AST/AttrTest.cpp

Index: clang/unittests/AST/AttrTest.cpp
===
--- clang/unittests/AST/AttrTest.cpp
+++ clang/unittests/AST/AttrTest.cpp
@@ -7,7 +7,10 @@
 //===--===//
 
 #include "clang/AST/Attr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/AttrKinds.h"
+#include "clang/Tooling/Tooling.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -15,10 +18,154 @@
 
 namespace {
 
+using clang::ast_matchers::constantExpr;
+using clang::ast_matchers::equals;
+using clang::ast_matchers::functionDecl;
+using clang::ast_matchers::has;
+using clang::ast_matchers::hasDescendant;
+using clang::ast_matchers::hasName;
+using clang::ast_matchers::integerLiteral;
+using clang::ast_matchers::match;
+using clang::ast_matchers::selectFirst;
+using clang::ast_matchers::stringLiteral;
+using clang::ast_matchers::varDecl;
+using clang::tooling::buildASTFromCode;
+using clang::tooling::buildASTFromCodeWithArgs;
+
 TEST(Attr, Doc) {
   EXPECT_THAT(Attr::getDocumentation(attr::Used).str(),
   testing::HasSubstr("The compiler must emit the definition even "
  "if it appears to be unused"));
 }
 
+const FunctionDecl *getFunctionNode(ASTUnit *AST, const std::string &Name) {
+  auto Result =
+  match(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("fn");
+}
+
+const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
+  auto Result = match(varDecl(hasName(Name)).bind("var"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("var");
+}
+
+template 
+void AssertAnnotatedAs(TypeLoc TL, llvm::StringRef annotation,
+   ModifiedTypeLoc &ModifiedTL,
+   const AnnotateTypeAttr **AnnotateOut = nullptr) {
+  const auto AttributedTL = TL.getAs();
+  ASSERT_FALSE(AttributedTL.isNull());
+  ModifiedTL = AttributedTL.getModifiedLoc().getAs();
+  ASSERT_TRUE(ModifiedTL);
+
+  ASSERT_NE(AttributedTL.getAttr(), nullptr);
+  const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+  ASSERT_NE(Annotate, nullptr);
+  EXPECT_EQ(Annotate->getAnnotation(), annotation);
+  if (AnnotateOut) {
+*AnnotateOut = Annotate;
+  }
+}
+
+TEST(Attr, AnnotateType) {
+
+  // Test that the AnnotateType attribute shows up in the right places and that
+  // it stores its arguments correctly.
+
+  auto AST = buildASTFromCode(R"cpp(
+void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
+   int [[clang::annotate_type("bar")]]);
+
+int [[clang::annotate_type("int")]] * [[clang::annotate_type("ptr")]]
+  array[10] [[clang::annotate_type("arr")]];
+
+void (* [[clang::annotate_type("funcptr")]] fp)(void);
+
+struct S { int mem; };
+int [[clang::annotate_type("int")]]
+S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
+)cpp");
+
+  {
+const FunctionDecl *Func = getFunctionNode(AST.get(), "f");
+
+// First parameter.
+const auto PointerTL = Func->getParamDecl(0)
+   ->getTypeSourceInfo()
+   ->getTypeLoc()
+   .getAs();
+ASSERT_FALSE(PointerTL.isNull());
+PointerTypeLoc PointerPointerTL;
+const AnnotateTypeAttr *Annotate;
+AssertAnnotatedAs(PointerTL.getPointeeLoc(), "foo", PointerPointerTL,
+  &Annotate);
+
+EXPECT_EQ(Annotate->args_size(), 2);
+const auto *StringLit = selectFirst(
+"str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
+ *Annotate->args_begin()[0], AST->getASTContext()));
+ASSERT_NE(StringLit, nullptr);
+EXPECT_EQ(StringLit->getString(), "arg1");
+EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2)).bind("int"))),
+*Annotate->args_begin()[1], AST->getASTContext())
+  .size(),
+  1);
+
+// Second parameter.
+BuiltinTypeLoc IntTL;
+AssertAnnotatedAs(Func->getParamDecl

[PATCH] D124919: [clang] [WIP] Reject non-declaration C++11 attributes on declarations.

2022-05-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a reviewer: aaron.ballman.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

For backwards compatiblity, we only emit a warning if the attribute is one of
the existing type attributes that we have historically allowed to "slide" to the
`DeclSpec` just as if it had been specified in GNU syntax. (We will call these
"legacy type attributes" below.)

The two high-level changes that achieve this are:

- We move any C++11 attributes (except legacy type attributes) that occur in 
the attribute-specifier-seq at the beginning of a simple-declaration (and other 
similar declarations) to `Declarator::Attrs`. This means that we treat them the 
same as if they had been placed after the declarator-id. (Justification below.)

- We make `ProcessDeclAttribute` emit a warning if it sees any non-declaration 
attributes in C++11 syntax, except in the following cases:
  - If it is being called for attributes on a `DeclSpec` or `DeclaratorChunk`
  - If the attribute is a legacy type attribute

The standard justifies treating attributes at the beginning of a
simple-declaration and attributes after a declarator-id the same. Here are some
relevant parts of the standard:

- The attribute-specifier-seq at the beginning of a simple-declaration 
"appertains to each of the entities declared by the declarators of the 
init-declarator-list" (https://eel.is/c++draft/dcl.dcl#dcl.pre-3)

- "In the declaration for an entity, attributes appertaining to that entity can 
appear at the start of the declaration and after the declarator-id for that 
declaration." (https://eel.is/c++draft/dcl.dcl#dcl.pre-note-2)

- "The optional attribute-specifier-seq following a declarator-id appertains to 
the entity that is declared." 
(https://eel.is/c++draft/dcl.dcl#dcl.meaning.general-1)

The standard contains similar wording to that for a simple-declaration in other
similar types of declarations, for example:

- "The optional attribute-specifier-seq in a parameter-declaration appertains 
to the parameter." (https://eel.is/c++draft/dcl.fct#3)

- "The optional attribute-specifier-seq in an exception-declaration appertains 
to the parameter of the catch clause" (https://eel.is/c++draft/except.pre#1)

Things that remain to be done:

- Emit warnings when a legacy type attribute occurs on a declaration. (This is 
not hard to do but will likely require updating a large number of tests, so I'd 
first like to get confirmation that the general direction of this change makes 
sense.)

- Move additional tests added to annotate-type.cpp to 
https://reviews.llvm.org/D111548 instead.

- Various other TODOs in the code

Depends On D111548 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D124919

Files:
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Parse/RAIIObjectsForParser.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/ParsedAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp

Index: clang/test/SemaCXX/annotate-type.cpp
===
--- clang/test/SemaCXX/annotate-type.cpp
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -1,11 +1,10 @@
-// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -fcxx-exceptions -verify
 
 struct S1 {
   void f() [[clang::annotate_type("foo")]];
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("foo")]] void g();
+  [[clang::annotate_type("foo")]] void
+  g(); // expected-error {{'annotate_type' attribute cannot be applied to a
+   // declaration}}
 };
 
 template  struct is_same {
@@ -53,11 +52,31 @@
 
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-namespace [[clang::annotate_type("foo")]] my_namespace {}
-struct [[clang::annotate_type("foo")]] S3{};
+namespace [[clang::annotate_type("foo")]] my_namespace {
+} // namespace my_namespace
+struct [[clang::annotate_type(
+"foo")]] S3{}; // expected-error {{'annotate_type' attribute cannot be
+   // applied to a declaration}}
 void f4() {
   for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {
+  } // expected-error {{'annotate_type' at

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > mboehme wrote:
> > > > aaron.ballman wrote:
> > > > > mboehme wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > mboehme wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > Can you also add some test coverage for applying the 
> > > > > > > > > attribute to a declaration instead of a type or not giving it 
> > > > > > > > > any arguments? Also, should test arguments which are not a 
> > > > > > > > > constant expression.
> > > > > > > > I've added tests as you suggested, though I put most of them in 
> > > > > > > > Sema/annotate-type.c, as they're not specific to C++.
> > > > > > > > 
> > > > > > > > Thanks for prompting me to do this -- the tests caused me to 
> > > > > > > > notice and fix a number of bugs.
> > > > > > > > 
> > > > > > > > I haven't managed to diagnose the case when the attribute 
> > > > > > > > appears at the beginning of the declaration. It seems to me 
> > > > > > > > that, at the point where I've added the check, this case is 
> > > > > > > > indistinguishable from an attribute that appears on the type. 
> > > > > > > > In both cases, the `TAL` is `TAL_DeclSpec`, and the attribute 
> > > > > > > > is contained in `DeclSpec::getAttributes()`. This is because 
> > > > > > > > `Parser::ParseSimpleDeclaration` forwards the declaration 
> > > > > > > > attributes to the `DeclSpec`:
> > > > > > > > 
> > > > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > > > > > 
> > > > > > > > I believe if I wanted to prohibit this case, I would need to 
> > > > > > > > add a check to `Parser::ParseStatementOrDeclaration` and 
> > > > > > > > prohibit any occurrences of `annotate_type` there. However, 
> > > > > > > > this seems the wrong place to do this because it doesn't 
> > > > > > > > contain any specific processing for other attributes.
> > > > > > > > 
> > > > > > > > I've noticed that Clang also doesn't prohibit other type 
> > > > > > > > attributes (even ones with C++ 11 syntax) from being applied to 
> > > > > > > > declarations. For example: https://godbolt.org/z/Yj1zWY7nn
> > > > > > > > 
> > > > > > > > How do you think I should proceed here? I think the underlying 
> > > > > > > > issue is that Clang doesn't always distinguish cleanly between 
> > > > > > > > declaration attributes and type attributes, and fixing this 
> > > > > > > > might be nontrivial.
> > > > > > > > How do you think I should proceed here? I think the underlying 
> > > > > > > > issue is that Clang doesn't always distinguish cleanly between 
> > > > > > > > declaration attributes and type attributes, and fixing this 
> > > > > > > > might be nontrivial.
> > > > > > > 
> > > > > > > This is a general issue with attribute processing. I would 
> > > > > > > imagine that SemaDeclAttr.cpp should be able to diagnose that 
> > > > > > > case when the attribute only applies to types and not 
> > > > > > > declarations, but it'd take some investigation for me to be sure.
> > > > > > > 
> > > > > > > Because this issue isn't new to your situation, I'd recommend 
> > > > > > > filing an issue about the general problem and then we can solve 
> > > > > > > that later.
> > > > > > I've done some more investigation myself, and I think I've come up 
> > > > > > with a solution; actually, two potential solutions. I have draft 
> > > > > > patches for both of these; I wanted to run these by you here first, 
> > > > > > so I haven't opened a bug yet.
> > > > > > 
> > > > > > I'd appreciate your input on how you'd prefer me to proceed with 
> > > > > > this. I do think it makes sense to do this work now because 
> > > > > > otherwise, people will start putting `annotate_type` in places 
> > > > > > where it doesn't belong, and then we'll have to keep supporting 
> > > > > > that in the future.
> > > > > > 
> > > > > > **My preferred solution**
> > > > > > 
> > > > > > https://reviews.llvm.org/D124081
> > > > > > 
> > > > > > This adds a function `DiagnoseCXX11NonDeclAttrs()` and calls it in 
> > > > > > all places where we should reject attributes that can't be put on 
> > > > > > declarations. (As part of this work, I noticed that `gsl::suppress` 
> > > > > > should be a `DeclOrStmtAttr`, not just a `StmtAttr`.)
> > > > > > 
> > > > > > Advantages:
> > > > > > - Not very invasive.
> > > > > > Disadvantages:
> > > > > > - Need to make sure we call `DiagnoseCXX11NonDeclAttrs()` 
> > > > > > everywhere that non-declaration attributes should be rejected. (Not 
> > > > > > sure if I've identified all of those places yet?)
> > > > > > 
> > > > > > **Alternative solution**
> > > > > > 
> > > > > > https://reviews.llvm.org/D124083
> > > > > > 
> > > > > > This adds an `appertainsTo` parameter to `ParseCXX11Attributes()` 
> > >

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 426990.
mboehme added a comment.

Changes in response to review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/AST/attr-annotate-type.c
  clang/test/CodeGenCXX/annotate-type.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/unittests/AST/AttrTest.cpp

Index: clang/unittests/AST/AttrTest.cpp
===
--- clang/unittests/AST/AttrTest.cpp
+++ clang/unittests/AST/AttrTest.cpp
@@ -7,7 +7,10 @@
 //===--===//
 
 #include "clang/AST/Attr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/AttrKinds.h"
+#include "clang/Tooling/Tooling.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -15,10 +18,154 @@
 
 namespace {
 
+using clang::ast_matchers::constantExpr;
+using clang::ast_matchers::equals;
+using clang::ast_matchers::functionDecl;
+using clang::ast_matchers::has;
+using clang::ast_matchers::hasDescendant;
+using clang::ast_matchers::hasName;
+using clang::ast_matchers::integerLiteral;
+using clang::ast_matchers::match;
+using clang::ast_matchers::selectFirst;
+using clang::ast_matchers::stringLiteral;
+using clang::ast_matchers::varDecl;
+using clang::tooling::buildASTFromCode;
+using clang::tooling::buildASTFromCodeWithArgs;
+
 TEST(Attr, Doc) {
   EXPECT_THAT(Attr::getDocumentation(attr::Used).str(),
   testing::HasSubstr("The compiler must emit the definition even "
  "if it appears to be unused"));
 }
 
+const FunctionDecl *getFunctionNode(ASTUnit *AST, const std::string &Name) {
+  auto Result =
+  match(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("fn");
+}
+
+const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
+  auto Result = match(varDecl(hasName(Name)).bind("var"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("var");
+}
+
+template 
+void AssertAnnotatedAs(TypeLoc TL, llvm::StringRef annotation,
+   ModifiedTypeLoc &ModifiedTL,
+   const AnnotateTypeAttr **AnnotateOut = nullptr) {
+  const auto AttributedTL = TL.getAs();
+  ASSERT_FALSE(AttributedTL.isNull());
+  ModifiedTL = AttributedTL.getModifiedLoc().getAs();
+  ASSERT_TRUE(ModifiedTL);
+
+  ASSERT_NE(AttributedTL.getAttr(), nullptr);
+  const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+  ASSERT_NE(Annotate, nullptr);
+  EXPECT_EQ(Annotate->getAnnotation(), annotation);
+  if (AnnotateOut) {
+*AnnotateOut = Annotate;
+  }
+}
+
+TEST(Attr, AnnotateType) {
+
+  // Test that the AnnotateType attribute shows up in the right places and that
+  // it stores its arguments correctly.
+
+  auto AST = buildASTFromCode(R"cpp(
+void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
+   int [[clang::annotate_type("bar")]]);
+
+int [[clang::annotate_type("int")]] * [[clang::annotate_type("ptr")]]
+  array[10] [[clang::annotate_type("arr")]];
+
+void (* [[clang::annotate_type("funcptr")]] fp)(void);
+
+struct S { int mem; };
+int [[clang::annotate_type("int")]]
+S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
+  )cpp");
+
+  {
+const FunctionDecl *Func = getFunctionNode(AST.get(), "f");
+
+// First parameter.
+const auto PointerTL = Func->getParamDecl(0)
+   ->getTypeSourceInfo()
+   ->getTypeLoc()
+   .getAs();
+ASSERT_FALSE(PointerTL.isNull());
+PointerTypeLoc PointerPointerTL;
+const AnnotateTypeAttr *Annotate;
+AssertAnnotatedAs(PointerTL.getPointeeLoc(), "foo", PointerPointerTL,
+  &Annotate);
+
+EXPECT_EQ(Annotate->args_size(), 2);
+const auto *StringLit = selectFirst(
+"str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
+ *Annotate->args_begin()[0], AST->getASTContext()));
+ASSERT_NE(StringLit, nullptr);
+EXPECT_EQ(StringLit->getString(), "arg1");
+EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2)).bind("int"))),
+*Annotate->args_begin()[1], AST->getASTContext())
+  .size(),
+  1);
+
+// Second parameter.
+BuiltinTypeLoc IntTL;
+AssertAnnotatedAs(Func->getParam

[PATCH] D124919: [clang] [WIP] Reject non-declaration C++11 attributes on declarations.

2022-05-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 426991.
mboehme added a comment.

Reuploaded because base revision changed.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124919/new/

https://reviews.llvm.org/D124919

Files:
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Parse/RAIIObjectsForParser.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/ParsedAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp

Index: clang/test/SemaCXX/annotate-type.cpp
===
--- clang/test/SemaCXX/annotate-type.cpp
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -1,11 +1,10 @@
-// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -fcxx-exceptions -verify
 
 struct S1 {
   void f() [[clang::annotate_type("foo")]];
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("foo")]] void g();
+  [[clang::annotate_type("foo")]] void
+  g(); // expected-error {{'annotate_type' attribute cannot be applied to a
+   // declaration}}
 };
 
 template  struct is_same {
@@ -48,11 +47,31 @@
 
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-namespace [[clang::annotate_type("foo")]] my_namespace {}
-struct [[clang::annotate_type("foo")]] S3{};
+namespace [[clang::annotate_type("foo")]] my_namespace {
+} // namespace my_namespace
+struct [[clang::annotate_type(
+"foo")]] S3{}; // expected-error {{'annotate_type' attribute cannot be
+   // applied to a declaration}}
 void f4() {
   for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {
+  } // expected-error {{'annotate_type' attribute cannot be applied to a
+// declaration}}
+  for (; [[clang::annotate_type("foo")]] bool b = false;) {
+  } // expected-error {{'annotate_type' attribute cannot be applied to a
+// declaration}}
+  while ([[clang::annotate_type("foo")]] bool b = false) {
+  } // expected-error {{'annotate_type' attribute cannot be applied to a
+// declaration}}
+  if ([[clang::annotate_type("foo")]] bool b = false) {
+  } // expected-error {{'annotate_type' attribute cannot be applied to a
+// declaration}}
+  try {
+  } catch ([[clang::annotate_type(
+  "foo")]] int i) { // expected-error {{'annotate_type' attribute cannot be
+// applied to a declaration}}
   }
 }
+template 
+[[clang::annotate_type(
+"foo")]] T var_template; // expected-error {{'annotate_type' attribute
+ // cannot be applied to a declaration}}
Index: clang/test/Sema/annotate-type.c
===
--- clang/test/Sema/annotate-type.c
+++ clang/test/Sema/annotate-type.c
@@ -17,10 +17,7 @@
   int *__attribute__((annotate_type("bar"))) y2; // expected-warning {{unknown attribute 'annotate_type' ignored}}
 
   // Various error cases
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("bar")]] int *z1;
+  [[clang::annotate_type("bar")]] int *z1; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   int *z2 [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
   [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a statement}}
   int *[[clang::annotate_type(1)]] z3; // expected-error {{'annotate_type' attribute requires a string}}
@@ -33,7 +30,6 @@
 }
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-[[clang::annotate_type("bar")]] int *global;
-void g([[clang::annotate_type("bar")]] int);
+[[clang::annotate_type("bar")]] int *global; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+[[clang::annotate_type("bar")]] void annotated_function(); // expected-error {{'annotate_type' attribute cannot be applied to a declarati

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 2 inline comments as done.
mboehme added inline comments.



Comment at: clang/unittests/AST/AttrTest.cpp:89
+S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
+)cpp");
+

aaron.ballman wrote:
> The formatting looks a bit off for this in terms of indentation.
Fixed.



Comment at: clang/unittests/AST/AttrTest.cpp:159
+__auto_type [[clang::annotate_type("auto")]] auto_var = 1;
+)c",
+ {"-fdouble-square-bracket-attributes"},

aaron.ballman wrote:
> Formatting looks a bit off here in terms of the indentation for this.
Fixed.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked 3 inline comments as done.
mboehme added a comment.

In D111548#3483275 , @erichkeane 
wrote:

> I don't really know how useful this ends up being, these attributes (since 
> they are part of `AttributedType` end up disappearing pretty quickly/easily.  
> Anything that causes canonicalization will cause these to go away,

This is true, but I also think we don't have much choice in the matter if we 
don't want these attributes to affect the C++ type system. We discuss this at 
length in the RFC:

https://discourse.llvm.org/t/rfc-new-attribute-annotate-type-iteration-2/61378#rationale-5

I go into more depth in this comment:

https://discourse.llvm.org/t/rfc-new-attribute-annotate-type-iteration-2/61378/4?u=martinboehme

However, it is possible for a static analysis to propagate the annotations 
through typedefs, template arguments and such, and we do so in the lifetime 
static analysis (see also below).

> they don't apply to references to these types, etc.

Not sure what you mean here -- do you mean that the annotations don't propagate 
through typedefs? As noted, it's possible for a static analysis tool to perform 
this propagation, and the discussion here is again relevant:

https://discourse.llvm.org/t/rfc-new-attribute-annotate-type-iteration-2/61378/4?u=martinboehme

> But I otherwise don't have concerns.
>
> HOWEVER, have you implemented the lifetime static analysis that you're 
> wanting to do on top of this already

Yes, we have. We are able to propagate lifetime annotations through non-trivial 
C++ constructs, including template arguments. Based on what our current 
prototype can do, we're confident these annotations will do everything we need 
them to. We also believe they are general enough to be useful for other types 
of static analysis.




Comment at: clang/lib/AST/TypePrinter.cpp:1689
+// the type.
+OS << " [[clang::annotate_type]]";
+return;

erichkeane wrote:
> My opinion (though not attached to it) would be `clang::annotate_type(...)` 
> or, `clang::annotate_type()` or something like that.
Good idea -- this makes it more obvious that the arguments were omitted. 
Changed!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-04 Thread Martin Böhme via Phabricator via cfe-commits
mboehme marked an inline comment as done.
mboehme added a comment.

In D111548#3483326 , @xbolva00 wrote:

> This patch should not land until we see some real use cases to justify new 
> hundreds of lines of code. We should more careful and take maintenance cost 
> really into account and not merge every experimental cool research extensions 
> automatically.

I assume you've seen the RFC 
 for the 
primary use case (Rust-style lifetime annotations for C++) that motivates this 
change?

There's a bit of a chicken-and-egg problem here: We obviously can't submit code 
for the lifetime analysis tooling before the type annotations it needs are 
supported. We're conscious that it's not desirable to add features merely for 
the purpose of an experimental tool that may never be stabilized. This is why 
we've consciously steered away from adding attributes that are specific to our 
use case and are instead proposing a general-purpose type annotation attribute.

> Please answer points in “ Contributing Extensions to Clang “
> https://clang.llvm.org/get_involved.html

This makes sense. I'll add an appendix answering these points to the RFC for 
this change 
.
 I probably won't get round to doing this today, but I did want to let you know 
that I've seen your comment. I'll ping this comment again when I've added the 
appendix to the RFC.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-05 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

aaron.ballman wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > mboehme wrote:
> > > > aaron.ballman wrote:
> > > > > mboehme wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > mboehme wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > mboehme wrote:
> > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > Can you also add some test coverage for applying the 
> > > > > > > > > > > attribute to a declaration instead of a type or not 
> > > > > > > > > > > giving it any arguments? Also, should test arguments 
> > > > > > > > > > > which are not a constant expression.
> > > > > > > > > > I've added tests as you suggested, though I put most of 
> > > > > > > > > > them in Sema/annotate-type.c, as they're not specific to 
> > > > > > > > > > C++.
> > > > > > > > > > 
> > > > > > > > > > Thanks for prompting me to do this -- the tests caused me 
> > > > > > > > > > to notice and fix a number of bugs.
> > > > > > > > > > 
> > > > > > > > > > I haven't managed to diagnose the case when the attribute 
> > > > > > > > > > appears at the beginning of the declaration. It seems to me 
> > > > > > > > > > that, at the point where I've added the check, this case is 
> > > > > > > > > > indistinguishable from an attribute that appears on the 
> > > > > > > > > > type. In both cases, the `TAL` is `TAL_DeclSpec`, and the 
> > > > > > > > > > attribute is contained in `DeclSpec::getAttributes()`. This 
> > > > > > > > > > is because `Parser::ParseSimpleDeclaration` forwards the 
> > > > > > > > > > declaration attributes to the `DeclSpec`:
> > > > > > > > > > 
> > > > > > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > > > > > > > 
> > > > > > > > > > I believe if I wanted to prohibit this case, I would need 
> > > > > > > > > > to add a check to `Parser::ParseStatementOrDeclaration` and 
> > > > > > > > > > prohibit any occurrences of `annotate_type` there. However, 
> > > > > > > > > > this seems the wrong place to do this because it doesn't 
> > > > > > > > > > contain any specific processing for other attributes.
> > > > > > > > > > 
> > > > > > > > > > I've noticed that Clang also doesn't prohibit other type 
> > > > > > > > > > attributes (even ones with C++ 11 syntax) from being 
> > > > > > > > > > applied to declarations. For example: 
> > > > > > > > > > https://godbolt.org/z/Yj1zWY7nn
> > > > > > > > > > 
> > > > > > > > > > How do you think I should proceed here? I think the 
> > > > > > > > > > underlying issue is that Clang doesn't always distinguish 
> > > > > > > > > > cleanly between declaration attributes and type attributes, 
> > > > > > > > > > and fixing this might be nontrivial.
> > > > > > > > > > How do you think I should proceed here? I think the 
> > > > > > > > > > underlying issue is that Clang doesn't always distinguish 
> > > > > > > > > > cleanly between declaration attributes and type attributes, 
> > > > > > > > > > and fixing this might be nontrivial.
> > > > > > > > > 
> > > > > > > > > This is a general issue with attribute processing. I would 
> > > > > > > > > imagine that SemaDeclAttr.cpp should be able to diagnose that 
> > > > > > > > > case when the attribute only applies to types and not 
> > > > > > > > > declarations, but it'd take some investigation for me to be 
> > > > > > > > > sure.
> > > > > > > > > 
> > > > > > > > > Because this issue isn't new to your situation, I'd recommend 
> > > > > > > > > filing an issue about the general problem and then we can 
> > > > > > > > > solve that later.
> > > > > > > > I've done some more investigation myself, and I think I've come 
> > > > > > > > up with a solution; actually, two potential solutions. I have 
> > > > > > > > draft patches for both of these; I wanted to run these by you 
> > > > > > > > here first, so I haven't opened a bug yet.
> > > > > > > > 
> > > > > > > > I'd appreciate your input on how you'd prefer me to proceed 
> > > > > > > > with this. I do think it makes sense to do this work now 
> > > > > > > > because otherwise, people will start putting `annotate_type` in 
> > > > > > > > places where it doesn't belong, and then we'll have to keep 
> > > > > > > > supporting that in the future.
> > > > > > > > 
> > > > > > > > **My preferred solution**
> > > > > > > > 
> > > > > > > > https://reviews.llvm.org/D124081
> > > > > > > > 
> > > > > > > > This adds a function `DiagnoseCXX11NonDeclAttrs()` and calls it 
> > > > > > > > in all places where we should reject attributes that can't be 
> > > > > > > > put on declarations. (As part of this work, I noticed that 
> > > > > > > > `gsl::suppress` should be a `DeclOrStmtAttr`, not just a 
> > > > > > > > `StmtAttr`.)
> > > > > > > > 
> > > > > > > > Advantages:
> > > > > > > > - Not very invasive.
> > > > > > > 

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-05 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added a comment.

In D111548#3483326 , @xbolva00 wrote:

> Please answer points in “ Contributing Extensions to Clang “
> https://clang.llvm.org/get_involved.html

I've added these to the RFC:

https://discourse.llvm.org/t/rfc-new-attribute-annotate-type-iteration-2/61378/9?u=martinboehme


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-09 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 428015.
mboehme added a comment.

Move some tests here that I originally added to 
https://reviews.llvm.org/D124919.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111548/new/

https://reviews.llvm.org/D111548

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/AST/attr-annotate-type.c
  clang/test/CodeGenCXX/annotate-type.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/annotate-type.cpp
  clang/unittests/AST/AttrTest.cpp

Index: clang/unittests/AST/AttrTest.cpp
===
--- clang/unittests/AST/AttrTest.cpp
+++ clang/unittests/AST/AttrTest.cpp
@@ -7,7 +7,10 @@
 //===--===//
 
 #include "clang/AST/Attr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/AttrKinds.h"
+#include "clang/Tooling/Tooling.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -15,10 +18,154 @@
 
 namespace {
 
+using clang::ast_matchers::constantExpr;
+using clang::ast_matchers::equals;
+using clang::ast_matchers::functionDecl;
+using clang::ast_matchers::has;
+using clang::ast_matchers::hasDescendant;
+using clang::ast_matchers::hasName;
+using clang::ast_matchers::integerLiteral;
+using clang::ast_matchers::match;
+using clang::ast_matchers::selectFirst;
+using clang::ast_matchers::stringLiteral;
+using clang::ast_matchers::varDecl;
+using clang::tooling::buildASTFromCode;
+using clang::tooling::buildASTFromCodeWithArgs;
+
 TEST(Attr, Doc) {
   EXPECT_THAT(Attr::getDocumentation(attr::Used).str(),
   testing::HasSubstr("The compiler must emit the definition even "
  "if it appears to be unused"));
 }
 
+const FunctionDecl *getFunctionNode(ASTUnit *AST, const std::string &Name) {
+  auto Result =
+  match(functionDecl(hasName(Name)).bind("fn"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("fn");
+}
+
+const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
+  auto Result = match(varDecl(hasName(Name)).bind("var"), AST->getASTContext());
+  EXPECT_EQ(Result.size(), 1u);
+  return Result[0].getNodeAs("var");
+}
+
+template 
+void AssertAnnotatedAs(TypeLoc TL, llvm::StringRef annotation,
+   ModifiedTypeLoc &ModifiedTL,
+   const AnnotateTypeAttr **AnnotateOut = nullptr) {
+  const auto AttributedTL = TL.getAs();
+  ASSERT_FALSE(AttributedTL.isNull());
+  ModifiedTL = AttributedTL.getModifiedLoc().getAs();
+  ASSERT_TRUE(ModifiedTL);
+
+  ASSERT_NE(AttributedTL.getAttr(), nullptr);
+  const auto *Annotate = dyn_cast(AttributedTL.getAttr());
+  ASSERT_NE(Annotate, nullptr);
+  EXPECT_EQ(Annotate->getAnnotation(), annotation);
+  if (AnnotateOut) {
+*AnnotateOut = Annotate;
+  }
+}
+
+TEST(Attr, AnnotateType) {
+
+  // Test that the AnnotateType attribute shows up in the right places and that
+  // it stores its arguments correctly.
+
+  auto AST = buildASTFromCode(R"cpp(
+void f(int* [[clang::annotate_type("foo", "arg1", 2)]] *,
+   int [[clang::annotate_type("bar")]]);
+
+int [[clang::annotate_type("int")]] * [[clang::annotate_type("ptr")]]
+  array[10] [[clang::annotate_type("arr")]];
+
+void (* [[clang::annotate_type("funcptr")]] fp)(void);
+
+struct S { int mem; };
+int [[clang::annotate_type("int")]]
+S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
+  )cpp");
+
+  {
+const FunctionDecl *Func = getFunctionNode(AST.get(), "f");
+
+// First parameter.
+const auto PointerTL = Func->getParamDecl(0)
+   ->getTypeSourceInfo()
+   ->getTypeLoc()
+   .getAs();
+ASSERT_FALSE(PointerTL.isNull());
+PointerTypeLoc PointerPointerTL;
+const AnnotateTypeAttr *Annotate;
+AssertAnnotatedAs(PointerTL.getPointeeLoc(), "foo", PointerPointerTL,
+  &Annotate);
+
+EXPECT_EQ(Annotate->args_size(), 2);
+const auto *StringLit = selectFirst(
+"str", match(constantExpr(hasDescendant(stringLiteral().bind("str"))),
+ *Annotate->args_begin()[0], AST->getASTContext()));
+ASSERT_NE(StringLit, nullptr);
+EXPECT_EQ(StringLit->getString(), "arg1");
+EXPECT_EQ(match(constantExpr(has(integerLiteral(equals(2)).bind("int"))),
+*Annotate->args_begin()[1], AST->getASTContext())
+  .size(),
+  1);
+
+// Second parameter.
+BuiltinTypeLoc IntTL;
+AssertAnnotatedAs(Func->getParamDecl(1)->getTypeSourceInfo()->getTypeLoc(),
+  

[PATCH] D124919: [clang] [WIP] Reject non-declaration C++11 attributes on declarations.

2022-05-09 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 428016.
mboehme edited the summary of this revision.
mboehme added a comment.
Herald added a subscriber: jdoerfert.

- Added warnings for "legacy" type attributes
- Added documentation
- Fixed TODOs in the code


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124919/new/

https://reviews.llvm.org/D124919

Files:
  clang/include/clang/Basic/AttributeCommonInfo.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Parse/RAIIObjectsForParser.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Basic/Attributes.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/ParsedAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/address-space-placement.cpp
  clang/test/SemaCXX/annotate-type.cpp
  clang/test/SemaOpenCL/address-spaces.cl
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3734,7 +3734,7 @@
 if (!StmtSubjects.empty()) {
   OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
   OS << "const Decl *D) const override {\n";
-  OS << "  S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)\n";
+  OS << "  S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n";
   OS << "<< AL << D->getLocation();\n";
   OS << "  return false;\n";
   OS << "}\n\n";
Index: clang/test/SemaOpenCL/address-spaces.cl
===
--- clang/test/SemaOpenCL/address-spaces.cl
+++ clang/test/SemaOpenCL/address-spaces.cl
@@ -266,9 +266,9 @@
   __attribute__((opencl_private)) private_int_t var5;  // expected-warning {{multiple identical address spaces specified for type}}
   __attribute__((opencl_private)) private_int_t *var6; // expected-warning {{multiple identical address spaces specified for type}}
 #if __OPENCL_CPP_VERSION__
-  [[clang::opencl_private]] __global int var7; // expected-error {{multiple address spaces specified for type}}
-  [[clang::opencl_private]] __global int *var8;// expected-error {{multiple address spaces specified for type}}
-  [[clang::opencl_private]] private_int_t var9;// expected-warning {{multiple identical address spaces specified for type}}
-  [[clang::opencl_private]] private_int_t *var10;  // expected-warning {{multiple identical address spaces specified for type}}
+  __global int [[clang::opencl_private]] var7; // expected-error {{multiple address spaces specified for type}}
+  __global int [[clang::opencl_private]] *var8;// expected-error {{multiple address spaces specified for type}}
+  private_int_t [[clang::opencl_private]] var9;// expected-warning {{multiple identical address spaces specified for type}}
+  private_int_t [[clang::opencl_private]] *var10;  // expected-warning {{multiple identical address spaces specified for type}}
 #endif // !__OPENCL_CPP_VERSION__
 }
Index: clang/test/SemaCXX/annotate-type.cpp
===
--- clang/test/SemaCXX/annotate-type.cpp
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -2,10 +2,7 @@
 
 struct S1 {
   void f() [[clang::annotate_type("foo")]];
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("foo")]] void g();
+  [[clang::annotate_type("foo")]] void g(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 };
 
 template  struct is_same {
@@ -48,23 +45,21 @@
 
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-namespace [[clang::annotate_type("foo")]] my_namespace {}
-struct [[clang::annotate_type("foo")]] S3;
-struct [[clang::annotate_type("foo")]] S3{
-  [[clang::annotate_type("foo")]] int member;
+namespace [[clang::annotate_type("foo")]] my_namespace {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S3; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S3{ // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+  [[clang::annotate_type("foo")]] int member; // expected-error {{'annotate_t

[PATCH] D124919: [clang] [WIP] Reject non-declaration C++11 attributes on declarations.

2022-05-10 Thread Martin Böhme via Phabricator via cfe-commits
mboehme updated this revision to Diff 428318.
mboehme added a comment.

Simply code by replacing `ExtractDefiniteDeclAttrs()` function with 
`SlideAttrsToDeclSpec()`. This essentially inverts the logic: Instead of moving 
those attributes to a second list that should definitely remain on the 
declaration, we identify the attributes that should "slide" and move them 
directly to the `DeclSpec`. This obviates the need for an additional 
`ParsedAttributes` list and hence simplifies the callsites.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124919/new/

https://reviews.llvm.org/D124919

Files:
  clang/include/clang/Basic/AttributeCommonInfo.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Parse/RAIIObjectsForParser.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Basic/Attributes.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/ParsedAttr.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/address-space-placement.cpp
  clang/test/SemaCXX/annotate-type.cpp
  clang/test/SemaOpenCL/address-spaces.cl
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3734,7 +3734,7 @@
 if (!StmtSubjects.empty()) {
   OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
   OS << "const Decl *D) const override {\n";
-  OS << "  S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)\n";
+  OS << "  S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n";
   OS << "<< AL << D->getLocation();\n";
   OS << "  return false;\n";
   OS << "}\n\n";
Index: clang/test/SemaOpenCL/address-spaces.cl
===
--- clang/test/SemaOpenCL/address-spaces.cl
+++ clang/test/SemaOpenCL/address-spaces.cl
@@ -266,9 +266,9 @@
   __attribute__((opencl_private)) private_int_t var5;  // expected-warning {{multiple identical address spaces specified for type}}
   __attribute__((opencl_private)) private_int_t *var6; // expected-warning {{multiple identical address spaces specified for type}}
 #if __OPENCL_CPP_VERSION__
-  [[clang::opencl_private]] __global int var7; // expected-error {{multiple address spaces specified for type}}
-  [[clang::opencl_private]] __global int *var8;// expected-error {{multiple address spaces specified for type}}
-  [[clang::opencl_private]] private_int_t var9;// expected-warning {{multiple identical address spaces specified for type}}
-  [[clang::opencl_private]] private_int_t *var10;  // expected-warning {{multiple identical address spaces specified for type}}
+  __global int [[clang::opencl_private]] var7; // expected-error {{multiple address spaces specified for type}}
+  __global int [[clang::opencl_private]] *var8;// expected-error {{multiple address spaces specified for type}}
+  private_int_t [[clang::opencl_private]] var9;// expected-warning {{multiple identical address spaces specified for type}}
+  private_int_t [[clang::opencl_private]] *var10;  // expected-warning {{multiple identical address spaces specified for type}}
 #endif // !__OPENCL_CPP_VERSION__
 }
Index: clang/test/SemaCXX/annotate-type.cpp
===
--- clang/test/SemaCXX/annotate-type.cpp
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -2,10 +2,7 @@
 
 struct S1 {
   void f() [[clang::annotate_type("foo")]];
-  // FIXME: We would want to prohibit the attribute in the following location.
-  // However, Clang currently generally doesn't prohibit type-only C++11
-  // attributes on declarations. This should be fixed more generally.
-  [[clang::annotate_type("foo")]] void g();
+  [[clang::annotate_type("foo")]] void g(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
 };
 
 template  struct is_same {
@@ -48,23 +45,21 @@
 
 // More error cases: Prohibit adding the attribute to declarations.
 // Different declarations hit different code paths, so they need separate tests.
-// FIXME: Clang currently generally doesn't prohibit type-only C++11
-// attributes on declarations.
-namespace [[clang::annotate_type("foo")]] my_namespace {}
-struct [[clang::annotate_type("foo")]] S3;
-struct [[clang::annotate_type("foo")]] S3{
-  [[clang::annotate_type("foo")]] int member;
+namespace [[clang::annotate_type("foo")]] my_namespace {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
+struct [[clang::annotate_type("foo")]] S3; // expected-error {{'annotate_type' at

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-10 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

rsmith wrote:
> mboehme wrote:
> > aaron.ballman wrote:
> > > mboehme wrote:
> > > > aaron.ballman wrote:
> > > > > mboehme wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > mboehme wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > mboehme wrote:
> > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > Can you also add some test coverage for applying the 
> > > > > > > > > > > > > attribute to a declaration instead of a type or not 
> > > > > > > > > > > > > giving it any arguments? Also, should test arguments 
> > > > > > > > > > > > > which are not a constant expression.
> > > > > > > > > > > > I've added tests as you suggested, though I put most of 
> > > > > > > > > > > > them in Sema/annotate-type.c, as they're not specific 
> > > > > > > > > > > > to C++.
> > > > > > > > > > > > 
> > > > > > > > > > > > Thanks for prompting me to do this -- the tests caused 
> > > > > > > > > > > > me to notice and fix a number of bugs.
> > > > > > > > > > > > 
> > > > > > > > > > > > I haven't managed to diagnose the case when the 
> > > > > > > > > > > > attribute appears at the beginning of the declaration. 
> > > > > > > > > > > > It seems to me that, at the point where I've added the 
> > > > > > > > > > > > check, this case is indistinguishable from an attribute 
> > > > > > > > > > > > that appears on the type. In both cases, the `TAL` is 
> > > > > > > > > > > > `TAL_DeclSpec`, and the attribute is contained in 
> > > > > > > > > > > > `DeclSpec::getAttributes()`. This is because 
> > > > > > > > > > > > `Parser::ParseSimpleDeclaration` forwards the 
> > > > > > > > > > > > declaration attributes to the `DeclSpec`:
> > > > > > > > > > > > 
> > > > > > > > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > > > > > > > > > 
> > > > > > > > > > > > I believe if I wanted to prohibit this case, I would 
> > > > > > > > > > > > need to add a check to 
> > > > > > > > > > > > `Parser::ParseStatementOrDeclaration` and prohibit any 
> > > > > > > > > > > > occurrences of `annotate_type` there. However, this 
> > > > > > > > > > > > seems the wrong place to do this because it doesn't 
> > > > > > > > > > > > contain any specific processing for other attributes.
> > > > > > > > > > > > 
> > > > > > > > > > > > I've noticed that Clang also doesn't prohibit other 
> > > > > > > > > > > > type attributes (even ones with C++ 11 syntax) from 
> > > > > > > > > > > > being applied to declarations. For example: 
> > > > > > > > > > > > https://godbolt.org/z/Yj1zWY7nn
> > > > > > > > > > > > 
> > > > > > > > > > > > How do you think I should proceed here? I think the 
> > > > > > > > > > > > underlying issue is that Clang doesn't always 
> > > > > > > > > > > > distinguish cleanly between declaration attributes and 
> > > > > > > > > > > > type attributes, and fixing this might be nontrivial.
> > > > > > > > > > > > How do you think I should proceed here? I think the 
> > > > > > > > > > > > underlying issue is that Clang doesn't always 
> > > > > > > > > > > > distinguish cleanly between declaration attributes and 
> > > > > > > > > > > > type attributes, and fixing this might be nontrivial.
> > > > > > > > > > > 
> > > > > > > > > > > This is a general issue with attribute processing. I 
> > > > > > > > > > > would imagine that SemaDeclAttr.cpp should be able to 
> > > > > > > > > > > diagnose that case when the attribute only applies to 
> > > > > > > > > > > types and not declarations, but it'd take some 
> > > > > > > > > > > investigation for me to be sure.
> > > > > > > > > > > 
> > > > > > > > > > > Because this issue isn't new to your situation, I'd 
> > > > > > > > > > > recommend filing an issue about the general problem and 
> > > > > > > > > > > then we can solve that later.
> > > > > > > > > > I've done some more investigation myself, and I think I've 
> > > > > > > > > > come up with a solution; actually, two potential solutions. 
> > > > > > > > > > I have draft patches for both of these; I wanted to run 
> > > > > > > > > > these by you here first, so I haven't opened a bug yet.
> > > > > > > > > > 
> > > > > > > > > > I'd appreciate your input on how you'd prefer me to proceed 
> > > > > > > > > > with this. I do think it makes sense to do this work now 
> > > > > > > > > > because otherwise, people will start putting 
> > > > > > > > > > `annotate_type` in places where it doesn't belong, and then 
> > > > > > > > > > we'll have to keep supporting that in the future.
> > > > > > > > > > 
> > > > > > > > > > **My preferred solution**
> > > > > > > > > > 
> > > > > > > > > > https://reviews.llvm.org/D124081
> > > > > > > > > > 
> > > > > > > > > > This adds a function `Diag

[PATCH] D126061: [clang] [WIP] Reject non-declaration C++11 attributes on declarations

2022-05-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a reviewer: aaron.ballman.
Herald added a subscriber: jdoerfert.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: cfe-commits, sstefan1.
Herald added a project: clang.

(Iteration #4)

For backwards compatiblity, we emit only a warning instead of an error if the
attribute is one of the existing type attributes that we have historically
allowed to "slide" to the `DeclSpec` just as if it had been specified in GNU
syntax. (We will call these "legacy type attributes" below.)

The high-level changes that achieve this are:

- We introduce a new field `Declarator::DeclarationAttrs` (with appropriate 
accessors) to store C++11 attributes occurring in the attribute-specifier-seq 
at the beginning of a simple-declaration (and other similar declarations). 
Previously, these attributes were placed on the `DeclSpec`, which made it 
impossible to reconstruct later on whether the attributes had in fact been 
placed on the decl-specifier-seq or ahead of the declaration.

- In the parser, we propgate declaration attributes and decl-specifier-seq 
attributes separately until we can place them in `Declarator::DeclarationAttrs` 
or `DeclSpec::Attrs`, respectively.

- In `ProcessDeclAttributes()`, in addition to processing declarator 
attributes, we now also process the attributes from 
`Declarator::DeclarationAttrs` (except if they are legacy type attributes).

- In `ConvertDeclSpecToType()`, in addition to processing `DeclSpec` 
attributes, we also process any legacy type attributes that occur in 
`Declarator::DeclarationAttrs` (and emit a warning).

- We make `ProcessDeclAttribute` emit an error if it sees any non-declaration 
attributes in C++11 syntax, except in the following cases:
  - If it is being called for attributes on a `DeclSpec` or `DeclaratorChunk`
  - If the attribute is a legacy type attribute (in which case we only emit a 
warning)

The standard justifies treating attributes at the beginning of a
simple-declaration and attributes after a declarator-id the same. Here are some
relevant parts of the standard:

- The attribute-specifier-seq at the beginning of a simple-declaration 
"appertains to each of the entities declared by the declarators of the 
init-declarator-list" (https://eel.is/c++draft/dcl.dcl#dcl.pre-3)

- "In the declaration for an entity, attributes appertaining to that entity can 
appear at the start of the declaration and after the declarator-id for that 
declaration." (https://eel.is/c++draft/dcl.dcl#dcl.pre-note-2)

- "The optional attribute-specifier-seq following a declarator-id appertains to 
the entity that is declared." 
(https://eel.is/c++draft/dcl.dcl#dcl.meaning.general-1)

The standard contains similar wording to that for a simple-declaration in other
similar types of declarations, for example:

- "The optional attribute-specifier-seq in a parameter-declaration appertains 
to the parameter." (https://eel.is/c++draft/dcl.fct#3)

- "The optional attribute-specifier-seq in an exception-declaration appertains 
to the parameter of the catch clause" (https://eel.is/c++draft/except.pre#1)

The new behavior is tested both on the newly added type attribute
`annotate_type`, for which we emit errors, and for the legacy type attribute
`address_space` (chosen somewhat randomly from the various legacy type
attributes), for which we emit warnings.

Depends On D111548 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D126061

Files:
  clang/include/clang/Basic/AttributeCommonInfo.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Parse/Parser.h
  clang/include/clang/Parse/RAIIObjectsForParser.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Basic/Attributes.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Parse/ParseStmt.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp
  clang/lib/Sema/ParsedAttr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/Sema/annotate-type.c
  clang/test/SemaCXX/address-space-placement.cpp
  clang/test/SemaCXX/annotate-type.cpp
  clang/test/SemaOpenCL/address-spaces.cl
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3734,7 +3734,7 @@
 if (!StmtSubjects.empty()) {
   OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
   OS << "const Decl *D) const override {\n";
-  OS << "  S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)\n";
+  OS << "  S.Diag(AL.getLoc(), diag::err_

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

rsmith wrote:
> mboehme wrote:
> > rsmith wrote:
> > > mboehme wrote:
> > > > aaron.ballman wrote:
> > > > > mboehme wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > mboehme wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > mboehme wrote:
> > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > Can you also add some test coverage for applying 
> > > > > > > > > > > > > > > the attribute to a declaration instead of a type 
> > > > > > > > > > > > > > > or not giving it any arguments? Also, should test 
> > > > > > > > > > > > > > > arguments which are not a constant expression.
> > > > > > > > > > > > > > I've added tests as you suggested, though I put 
> > > > > > > > > > > > > > most of them in Sema/annotate-type.c, as they're 
> > > > > > > > > > > > > > not specific to C++.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Thanks for prompting me to do this -- the tests 
> > > > > > > > > > > > > > caused me to notice and fix a number of bugs.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > I haven't managed to diagnose the case when the 
> > > > > > > > > > > > > > attribute appears at the beginning of the 
> > > > > > > > > > > > > > declaration. It seems to me that, at the point 
> > > > > > > > > > > > > > where I've added the check, this case is 
> > > > > > > > > > > > > > indistinguishable from an attribute that appears on 
> > > > > > > > > > > > > > the type. In both cases, the `TAL` is 
> > > > > > > > > > > > > > `TAL_DeclSpec`, and the attribute is contained in 
> > > > > > > > > > > > > > `DeclSpec::getAttributes()`. This is because 
> > > > > > > > > > > > > > `Parser::ParseSimpleDeclaration` forwards the 
> > > > > > > > > > > > > > declaration attributes to the `DeclSpec`:
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > I believe if I wanted to prohibit this case, I 
> > > > > > > > > > > > > > would need to add a check to 
> > > > > > > > > > > > > > `Parser::ParseStatementOrDeclaration` and prohibit 
> > > > > > > > > > > > > > any occurrences of `annotate_type` there. However, 
> > > > > > > > > > > > > > this seems the wrong place to do this because it 
> > > > > > > > > > > > > > doesn't contain any specific processing for other 
> > > > > > > > > > > > > > attributes.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > I've noticed that Clang also doesn't prohibit other 
> > > > > > > > > > > > > > type attributes (even ones with C++ 11 syntax) from 
> > > > > > > > > > > > > > being applied to declarations. For example: 
> > > > > > > > > > > > > > https://godbolt.org/z/Yj1zWY7nn
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > How do you think I should proceed here? I think the 
> > > > > > > > > > > > > > underlying issue is that Clang doesn't always 
> > > > > > > > > > > > > > distinguish cleanly between declaration attributes 
> > > > > > > > > > > > > > and type attributes, and fixing this might be 
> > > > > > > > > > > > > > nontrivial.
> > > > > > > > > > > > > > How do you think I should proceed here? I think the 
> > > > > > > > > > > > > > underlying issue is that Clang doesn't always 
> > > > > > > > > > > > > > distinguish cleanly between declaration attributes 
> > > > > > > > > > > > > > and type attributes, and fixing this might be 
> > > > > > > > > > > > > > nontrivial.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > This is a general issue with attribute processing. I 
> > > > > > > > > > > > > would imagine that SemaDeclAttr.cpp should be able to 
> > > > > > > > > > > > > diagnose that case when the attribute only applies to 
> > > > > > > > > > > > > types and not declarations, but it'd take some 
> > > > > > > > > > > > > investigation for me to be sure.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Because this issue isn't new to your situation, I'd 
> > > > > > > > > > > > > recommend filing an issue about the general problem 
> > > > > > > > > > > > > and then we can solve that later.
> > > > > > > > > > > > I've done some more investigation myself, and I think 
> > > > > > > > > > > > I've come up with a solution; actually, two potential 
> > > > > > > > > > > > solutions. I have draft patches for both of these; I 
> > > > > > > > > > > > wanted to run these by you here first, so I haven't 
> > > > > > > > > > > > opened a bug yet.
> > > > > > > > > > > > 
> > > > > > > > > > > > I'd appreciate your input on how you'd prefer me to 
> > > > > > > > > > > > proceed with this. I do thi

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

mboehme wrote:
> rsmith wrote:
> > mboehme wrote:
> > > rsmith wrote:
> > > > mboehme wrote:
> > > > > aaron.ballman wrote:
> > > > > > mboehme wrote:
> > > > > > > aaron.ballman wrote:
> > > > > > > > mboehme wrote:
> > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > mboehme wrote:
> > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > > Can you also add some test coverage for 
> > > > > > > > > > > > > > > > applying the attribute to a declaration instead 
> > > > > > > > > > > > > > > > of a type or not giving it any arguments? Also, 
> > > > > > > > > > > > > > > > should test arguments which are not a constant 
> > > > > > > > > > > > > > > > expression.
> > > > > > > > > > > > > > > I've added tests as you suggested, though I put 
> > > > > > > > > > > > > > > most of them in Sema/annotate-type.c, as they're 
> > > > > > > > > > > > > > > not specific to C++.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Thanks for prompting me to do this -- the tests 
> > > > > > > > > > > > > > > caused me to notice and fix a number of bugs.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > I haven't managed to diagnose the case when the 
> > > > > > > > > > > > > > > attribute appears at the beginning of the 
> > > > > > > > > > > > > > > declaration. It seems to me that, at the point 
> > > > > > > > > > > > > > > where I've added the check, this case is 
> > > > > > > > > > > > > > > indistinguishable from an attribute that appears 
> > > > > > > > > > > > > > > on the type. In both cases, the `TAL` is 
> > > > > > > > > > > > > > > `TAL_DeclSpec`, and the attribute is contained in 
> > > > > > > > > > > > > > > `DeclSpec::getAttributes()`. This is because 
> > > > > > > > > > > > > > > `Parser::ParseSimpleDeclaration` forwards the 
> > > > > > > > > > > > > > > declaration attributes to the `DeclSpec`:
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > I believe if I wanted to prohibit this case, I 
> > > > > > > > > > > > > > > would need to add a check to 
> > > > > > > > > > > > > > > `Parser::ParseStatementOrDeclaration` and 
> > > > > > > > > > > > > > > prohibit any occurrences of `annotate_type` 
> > > > > > > > > > > > > > > there. However, this seems the wrong place to do 
> > > > > > > > > > > > > > > this because it doesn't contain any specific 
> > > > > > > > > > > > > > > processing for other attributes.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > I've noticed that Clang also doesn't prohibit 
> > > > > > > > > > > > > > > other type attributes (even ones with C++ 11 
> > > > > > > > > > > > > > > syntax) from being applied to declarations. For 
> > > > > > > > > > > > > > > example: https://godbolt.org/z/Yj1zWY7nn
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > How do you think I should proceed here? I think 
> > > > > > > > > > > > > > > the underlying issue is that Clang doesn't always 
> > > > > > > > > > > > > > > distinguish cleanly between declaration 
> > > > > > > > > > > > > > > attributes and type attributes, and fixing this 
> > > > > > > > > > > > > > > might be nontrivial.
> > > > > > > > > > > > > > > How do you think I should proceed here? I think 
> > > > > > > > > > > > > > > the underlying issue is that Clang doesn't always 
> > > > > > > > > > > > > > > distinguish cleanly between declaration 
> > > > > > > > > > > > > > > attributes and type attributes, and fixing this 
> > > > > > > > > > > > > > > might be nontrivial.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > This is a general issue with attribute processing. 
> > > > > > > > > > > > > > I would imagine that SemaDeclAttr.cpp should be 
> > > > > > > > > > > > > > able to diagnose that case when the attribute only 
> > > > > > > > > > > > > > applies to types and not declarations, but it'd 
> > > > > > > > > > > > > > take some investigation for me to be sure.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Because this issue isn't new to your situation, I'd 
> > > > > > > > > > > > > > recommend filing an issue about the general problem 
> > > > > > > > > > > > > > and then we can solve that later.
> > > > > > > > > > > > > I've done some more investigation myself, and I think 
> > > > > > > > > > > > > I've come up with a solution; actually, two potential 
> > > > > > > > > > > > > solutions. I have draft patches for both of these; I 
> > > > > > > > > > > > > wanted to run these by you here first, so I have

[PATCH] D126062: [clang] Don't parse MS attributes in `ParseExportDeclaration()`.

2022-05-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

As @rsmith commented on https://reviews.llvm.org/D111548: "That looks like it's
simply a bug as far as I can tell, and that call can be removed. MS attributes
will be parsed as part of the decl specifier sequence as needed and don't need
to be parsed as declaration attributes."


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D126062

Files:
  clang/lib/Parse/ParseDeclCXX.cpp


Index: clang/lib/Parse/ParseDeclCXX.cpp
===
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -438,7 +438,6 @@
 // FIXME: Factor out a ParseExternalDeclarationWithAttrs.
 ParsedAttributes Attrs(AttrFactory);
 MaybeParseCXX11Attributes(Attrs);
-MaybeParseMicrosoftAttributes(Attrs);
 ParseExternalDeclaration(Attrs);
 return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl,
  SourceLocation());
@@ -458,7 +457,6 @@
  Tok.isNot(tok::eof)) {
 ParsedAttributes Attrs(AttrFactory);
 MaybeParseCXX11Attributes(Attrs);
-MaybeParseMicrosoftAttributes(Attrs);
 ParseExternalDeclaration(Attrs);
   }
 


Index: clang/lib/Parse/ParseDeclCXX.cpp
===
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -438,7 +438,6 @@
 // FIXME: Factor out a ParseExternalDeclarationWithAttrs.
 ParsedAttributes Attrs(AttrFactory);
 MaybeParseCXX11Attributes(Attrs);
-MaybeParseMicrosoftAttributes(Attrs);
 ParseExternalDeclaration(Attrs);
 return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl,
  SourceLocation());
@@ -458,7 +457,6 @@
  Tok.isNot(tok::eof)) {
 ParsedAttributes Attrs(AttrFactory);
 MaybeParseCXX11Attributes(Attrs);
-MaybeParseMicrosoftAttributes(Attrs);
 ParseExternalDeclaration(Attrs);
   }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D126066: [clang] Don't plumb access specifier attributes through Parser unnecessarily.

2022-05-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme created this revision.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: cfe-commits, sstefan1.
Herald added a project: clang.

I noticed that a lot of functions in the parser take an `AccessAttrs` parameter,
even though, as far as I can tell, it's sufficient to handle access specifier
attributes locally where the access specifier is parsed.

I have removed all of this plumbing, and tests still pass. Much of the code
involved is pretty old, so I suspect this plumbing was required at some point
but that the underlying reason has now been eliminated. It may also be that at
some point people started simply following the pattern of "pass `AccessAttrs`
wherever an `AccessSpecifier` is passed".

However, I would appreciate a close look from someone who's more familiar with
the code than I am.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D126066

Files:
  clang/include/clang/Parse/Parser.h
  clang/lib/Parse/ParseCXXInlineMethods.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseOpenMP.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Parse/Parser.cpp

Index: clang/lib/Parse/Parser.cpp
===
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -819,7 +819,7 @@
   case tok::annot_attr_openmp:
   case tok::annot_pragma_openmp: {
 AccessSpecifier AS = AS_none;
-return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
+return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS);
   }
   case tok::annot_pragma_ms_pointers_to_members:
 HandlePragmaMSPointersToMembers();
@@ -974,7 +974,7 @@
  diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc);
   SourceLocation DeclEnd;
   return Actions.ConvertDeclToDeclGroup(ParseExplicitInstantiation(
-  DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd, Attrs));
+  DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd));
 }
 goto dont_know;
 
Index: clang/lib/Parse/ParseTemplate.cpp
===
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -35,17 +35,16 @@
 
 /// Parse a template declaration, explicit instantiation, or
 /// explicit specialization.
-Decl *Parser::ParseDeclarationStartingWithTemplate(
-DeclaratorContext Context, SourceLocation &DeclEnd,
-ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
+Decl *Parser::ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
+   SourceLocation &DeclEnd,
+   AccessSpecifier AS) {
   ObjCDeclContextSwitch ObjCDC(*this);
 
   if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
 return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(),
-  DeclEnd, AccessAttrs, AS);
+  DeclEnd, AS);
   }
-  return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs,
-  AS);
+  return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS);
 }
 
 /// Parse a template declaration or an explicit specialization.
@@ -73,8 +72,7 @@
 ///   explicit-specialization: [ C++ temp.expl.spec]
 /// 'template' '<' '>' declaration
 Decl *Parser::ParseTemplateDeclarationOrSpecialization(
-DeclaratorContext Context, SourceLocation &DeclEnd,
-ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
+DeclaratorContext Context, SourceLocation &DeclEnd, AccessSpecifier AS) {
   assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
  "Token does not start a template declaration.");
 
@@ -170,7 +168,7 @@
   return ParseSingleDeclarationAfterTemplate(
   Context,
   ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty),
-  ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
+  ParsingTemplateParams, DeclEnd, AS);
 }
 
 /// Parse a single declaration that declares a template,
@@ -186,7 +184,7 @@
 Decl *Parser::ParseSingleDeclarationAfterTemplate(
 DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
 ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd,
-ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
+AccessSpecifier AS) {
   assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
  "Template information required");
 
@@ -200,8 +198,7 @@
 
   if (Context == DeclaratorContext::Member) {
 // We are parsing a member template.
-ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
-   &DiagsFromTParams);
+ParseCXXClassMemberDeclaration(AS, TemplateInfo, &DiagsFromTParams);
 return nullptr;
   }
 
@@ -1640,7 +1637,6 @@
   

[PATCH] D111548: [Clang] Add the `annotate_type` attribute

2022-05-20 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang/test/SemaCXX/annotate-type.cpp:2
+// RUN: %clang_cc1 %s -std=c++17 -fsyntax-only -verify
+
+struct S1 {

mboehme wrote:
> mboehme wrote:
> > rsmith wrote:
> > > mboehme wrote:
> > > > rsmith wrote:
> > > > > mboehme wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > mboehme wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > mboehme wrote:
> > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > mboehme wrote:
> > > > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > > > Can you also add some test coverage for 
> > > > > > > > > > > > > > > > > applying the attribute to a declaration 
> > > > > > > > > > > > > > > > > instead of a type or not giving it any 
> > > > > > > > > > > > > > > > > arguments? Also, should test arguments which 
> > > > > > > > > > > > > > > > > are not a constant expression.
> > > > > > > > > > > > > > > > I've added tests as you suggested, though I put 
> > > > > > > > > > > > > > > > most of them in Sema/annotate-type.c, as 
> > > > > > > > > > > > > > > > they're not specific to C++.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Thanks for prompting me to do this -- the tests 
> > > > > > > > > > > > > > > > caused me to notice and fix a number of bugs.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > I haven't managed to diagnose the case when the 
> > > > > > > > > > > > > > > > attribute appears at the beginning of the 
> > > > > > > > > > > > > > > > declaration. It seems to me that, at the point 
> > > > > > > > > > > > > > > > where I've added the check, this case is 
> > > > > > > > > > > > > > > > indistinguishable from an attribute that 
> > > > > > > > > > > > > > > > appears on the type. In both cases, the `TAL` 
> > > > > > > > > > > > > > > > is `TAL_DeclSpec`, and the attribute is 
> > > > > > > > > > > > > > > > contained in `DeclSpec::getAttributes()`. This 
> > > > > > > > > > > > > > > > is because `Parser::ParseSimpleDeclaration` 
> > > > > > > > > > > > > > > > forwards the declaration attributes to the 
> > > > > > > > > > > > > > > > `DeclSpec`:
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > https://github.com/llvm/llvm-project/blob/main/clang/lib/Parse/ParseDecl.cpp#L1851
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > I believe if I wanted to prohibit this case, I 
> > > > > > > > > > > > > > > > would need to add a check to 
> > > > > > > > > > > > > > > > `Parser::ParseStatementOrDeclaration` and 
> > > > > > > > > > > > > > > > prohibit any occurrences of `annotate_type` 
> > > > > > > > > > > > > > > > there. However, this seems the wrong place to 
> > > > > > > > > > > > > > > > do this because it doesn't contain any specific 
> > > > > > > > > > > > > > > > processing for other attributes.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > I've noticed that Clang also doesn't prohibit 
> > > > > > > > > > > > > > > > other type attributes (even ones with C++ 11 
> > > > > > > > > > > > > > > > syntax) from being applied to declarations. For 
> > > > > > > > > > > > > > > > example: https://godbolt.org/z/Yj1zWY7nn
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > How do you think I should proceed here? I think 
> > > > > > > > > > > > > > > > the underlying issue is that Clang doesn't 
> > > > > > > > > > > > > > > > always distinguish cleanly between declaration 
> > > > > > > > > > > > > > > > attributes and type attributes, and fixing this 
> > > > > > > > > > > > > > > > might be nontrivial.
> > > > > > > > > > > > > > > > How do you think I should proceed here? I think 
> > > > > > > > > > > > > > > > the underlying issue is that Clang doesn't 
> > > > > > > > > > > > > > > > always distinguish cleanly between declaration 
> > > > > > > > > > > > > > > > attributes and type attributes, and fixing this 
> > > > > > > > > > > > > > > > might be nontrivial.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > This is a general issue with attribute 
> > > > > > > > > > > > > > > processing. I would imagine that SemaDeclAttr.cpp 
> > > > > > > > > > > > > > > should be able to diagnose that case when the 
> > > > > > > > > > > > > > > attribute only applies to types and not 
> > > > > > > > > > > > > > > declarations, but it'd take some investigation 
> > > > > > > > > > > > > > > for me to be sure.
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > Because this issue isn't new to your situation, 
> > > > > > > > > > > > > > > I'd recommend filing an issue about the general 
> > > > > > > > > > > > > > > problem and then we can solve that later.
> > > > > > > > > > > > > > I've done some more investigation myself, and I 
> > > > > > 

[PATCH] D67292: [clang-tidy] Fix bug in bugprone-use-after-move check

2019-09-09 Thread Martin Böhme via Phabricator via cfe-commits
mboehme added inline comments.



Comment at: clang-tools-extra/test/clang-tidy/bugprone-use-after-move.cpp:1198
+}
+  }
   for (int i = 0; i < 10; ++i) {

gribozavr wrote:
> ymandel wrote:
> > gribozavr wrote:
> > > Unless you think it is redundant, could you also add
> > > 
> > > ```
> > > if (A a1; A(std::move(a2)).getInt() > 0) {}
> > > ```
> > > 
> > > Also some true positive tests would be good:
> > > 
> > > ```
> > > if (A a1; A(std::move(a2)).getInt() > A(std::move(a2)).getInt()) {}
> > > ```
> > > 
> > > ```
> > > A a1;
> > > if (A a2 = std::move(a1); A(std::move(a1)) > 0) {}
> > > ```
> > Done, but any idea why everything in this function is placed inside a loop? 
> >  Looks like its just for scoping, but then why not just a compound 
> > statement, as is done above? This feels very odd.
> I think it is to ensure that the checker understands the sequencing. If it 
> didn't, then the loop would trigger the "moved twice" logic.
(Original author of the test here.)

Correct. I should probably have added a comment explaining this when I wrote 
the test. Feel free to add such a comment.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67292/new/

https://reviews.llvm.org/D67292



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   3   4   5   6   >