aaron.ballman updated this revision to Diff 195790.
aaron.ballman marked 3 inline comments as done.
aaron.ballman added a comment.

Updated based on review feedback.


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

https://reviews.llvm.org/D60872

Files:
  include/clang/Basic/DiagnosticCommonKinds.td
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaStmtAttr.cpp
  lib/Sema/SemaType.cpp
  test/SemaCXX/attr-cxx0x.cpp
  utils/TableGen/ClangAttrEmitter.cpp

Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -17,7 +17,6 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -2551,6 +2550,16 @@
       ::emitAttrList(OS, Descriptor.MacroName, Attrs);
     }
 
+    void addAttrNamespacesTo(std::set<std::string> &S) const {
+      for (const Record *R : Attrs) {
+        std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*R);
+        for (const auto &Spell : Spellings) {
+          if (!Spell.nameSpace().empty())
+            S.insert(Spell.nameSpace());
+        }
+      }
+    }
+
     void classifyAttrOnRoot(Record *Attr) {
       bool result = classifyAttr(Attr);
       assert(result && "failed to classify on root"); (void) result;
@@ -2621,6 +2630,19 @@
 #endif
     }
 
+    void emitAttrNamespaces(raw_ostream &OS) const {
+      // Gather the unique set of attribute namespaces Clang knows about. We
+      // want this set to be ordered so we can do efficient lookups.
+      std::set<std::string> Namespaces;
+      for (const auto &Class : Classes) {
+        Class->addAttrNamespacesTo(Namespaces);
+      }
+      // Emit the list of namespaces.
+      for (const auto &Namespace : Namespaces) {
+        OS << "ATTR_NAMESPACE(" << Namespace << ")\n";
+      }
+    }
+
     void emitDefaultDefines(raw_ostream &OS) const {
       for (auto &Class : Classes) {
         Class->emitDefaultDefines(OS);
@@ -2682,6 +2704,7 @@
   // Add defaulting macro definitions.
   Hierarchy.emitDefaultDefines(OS);
   emitDefaultDefine(OS, "PRAGMA_SPELLING_ATTR", nullptr);
+  emitDefaultDefine(OS, "ATTR_NAMESPACE", nullptr);
 
   std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
   std::vector<Record *> PragmaAttrs;
@@ -2702,6 +2725,7 @@
 
   // Emit the ad hoc groups.
   emitAttrList(OS, "PRAGMA_SPELLING_ATTR", PragmaAttrs);
+  Hierarchy.emitAttrNamespaces(OS);
 
   // Emit the attribute ranges.
   OS << "#ifdef ATTR_RANGE\n";
@@ -2711,6 +2735,7 @@
 
   Hierarchy.emitUndefs(OS);
   OS << "#undef PRAGMA_SPELLING_ATTR\n";
+  OS << "#undef ATTR_NAMESPACE\n";
 }
 
 // Emits the enumeration list for attributes.
Index: test/SemaCXX/attr-cxx0x.cpp
===================================================================
--- test/SemaCXX/attr-cxx0x.cpp
+++ test/SemaCXX/attr-cxx0x.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -pedantic -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -pedantic -DUNKNOWN_ATTRS -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -pedantic -Wno-unknown-attributes -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -pedantic -Wno-unknown-attributes -Wunknown-attribute-namespaces -DUNKNOWN_NAMESPACE -std=c++11 %s
 
 int align_illegal alignas(3); //expected-error {{requested alignment is not a power of 2}}
 char align_big alignas(int);
@@ -46,7 +48,25 @@
 
 static_assert(alignof(int(int)) >= 1, "alignof(function) not positive"); // expected-error{{invalid application of 'alignof' to a function type}}
 
-[[__carries_dependency__]]  // expected-warning{{unknown attribute '__carries_dependency__' ignored}}
+#if defined(UNKNOWN_ATTRS) || defined(UNKNOWN_NAMESPACE)
+// expected-warning@+2 {{unknown attribute '__carries_dependency__' ignored}}
+#endif
+[[__carries_dependency__]]
 void func(void);
 
 alignas(4) auto PR19252 = 0;
+
+#if defined(UNKNOWN_ATTRS) || defined(UNKNOWN_NAMESPACE)
+// expected-warning@+2 {{unknown attribute 'frobble' ignored}}
+#endif
+[[frobble]] int unknown1;
+
+#if defined(UNKNOWN_ATTRS) || defined(UNKNOWN_NAMESPACE)
+// expected-warning@+2 {{unknown attribute 'bobble' ignored}}
+#endif
+[[frobble::bobble]] int unknown2;
+
+#ifdef UNKNOWN_ATTRS
+// expected-warning@+2 {{unknown attribute 'unknown_attribute' ignored}}
+#endif
+[[gsl::unknown_attribute]] int unknown3;
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -7441,9 +7441,7 @@
 
     case ParsedAttr::UnknownAttribute:
       if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk)
-        state.getSema().Diag(attr.getLoc(),
-                             diag::warn_unknown_attribute_ignored)
-          << attr.getName();
+        state.getSema().diagnoseUnknownAttribute(attr);
       break;
 
     case ParsedAttr::IgnoredAttribute:
Index: lib/Sema/SemaStmtAttr.cpp
===================================================================
--- lib/Sema/SemaStmtAttr.cpp
+++ lib/Sema/SemaStmtAttr.cpp
@@ -329,10 +329,7 @@
                                   SourceRange Range) {
   switch (A.getKind()) {
   case ParsedAttr::UnknownAttribute:
-    S.Diag(A.getLoc(), A.isDeclspecAttribute()
-                           ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
-                           : (unsigned)diag::warn_unknown_attribute_ignored)
-        << A.getName();
+    S.diagnoseUnknownAttribute(A);
     return nullptr;
   case ParsedAttr::AT_FallThrough:
     return handleFallThroughAttr(S, St, A, Range);
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -2348,10 +2348,10 @@
   for (const ParsedAttr &AL : Attributes) {
     if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
       continue;
-    Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute
-                          ? (unsigned)diag::warn_unknown_attribute_ignored
-                          : (unsigned)diag::err_base_specifier_attribute)
-        << AL.getName();
+    if (AL.getKind() == ParsedAttr::UnknownAttribute)
+      diagnoseUnknownAttribute(AL);
+    else
+      Diag(AL.getLoc(), diag::err_base_specifier_attribute) << AL;
   }
 
   TypeSourceInfo *TInfo = nullptr;
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -34,6 +34,7 @@
 #include "clang/Sema/SemaInternal.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/MathExtras.h"
 
 using namespace clang;
@@ -2067,7 +2068,7 @@
 bool Sema::CheckAttrTarget(const ParsedAttr &AL) {
   // Check whether the attribute is valid on the current target.
   if (!AL.existsInTarget(Context.getTargetInfo())) {
-    Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL;
+    diagnoseUnknownAttribute(AL);
     AL.setInvalid();
     return true;
   }
@@ -6585,11 +6586,7 @@
   // though they were unknown attributes.
   if (AL.getKind() == ParsedAttr::UnknownAttribute ||
       !AL.existsInTarget(S.Context.getTargetInfo())) {
-    S.Diag(AL.getLoc(),
-           AL.isDeclspecAttribute()
-               ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
-               : (unsigned)diag::warn_unknown_attribute_ignored)
-        << AL;
+    S.diagnoseUnknownAttribute(AL);
     return;
   }
 
@@ -7412,13 +7409,11 @@
     if (AL.getKind() == ParsedAttr::IgnoredAttribute)
       continue;
 
-    if (AL.getKind() == ParsedAttr::UnknownAttribute) {
-      S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
+    if (AL.getKind() == ParsedAttr::UnknownAttribute)
+      S.diagnoseUnknownAttribute(AL);
+    else
+      S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl)
           << AL << AL.getRange();
-    } else {
-      S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) << AL
-                                                            << AL.getRange();
-    }
   }
 }
 
@@ -8617,3 +8612,27 @@
   EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
                           UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
 }
+
+void Sema::diagnoseUnknownAttribute(const ParsedAttr &A) {
+  // We emit a few different "unknown attribute" diagnostics, depending on the
+  // circumstances, such as a scoped attribute with an unknown namespace, etc.
+  unsigned Warning = diag::warn_unknown_attribute_ignored;
+  if (A.isDeclspecAttribute()) {
+    Warning = diag::warn_unhandled_ms_attribute_ignored;
+  } else if (A.hasScope()) {
+    if (llvm::StringSwitch<bool>(A.getScopeName()->getName())
+#define ATTR(A)
+#define ATTR_NAMESPACE(A) .Case(#A, false)
+#include "clang/Basic/AttrList.inc"
+            .Default(true))
+      Warning = diag::warn_unknown_attribute_namespace_ignored;
+  } else if (A.isC2xAttribute() || A.isCXX11Attribute()) {
+    // We use the namespaced attribute warning for a C2x or C++11 attribute
+    // without a scope. This ensures that a user who does
+    // -Wno-unknown-attributes -Wunknown-attribute-namespaces still gets a
+    // diagnostic for attributes that could have a scope but do not (e.g.,
+    // [[unknown_attribute]]).
+    Warning = diag::warn_unknown_attribute_namespace_ignored;
+  }
+  Diag(A.getLoc(), Warning) << A << A.getRange();
+}
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -1633,7 +1633,7 @@
     if (!AL.isCXX11Attribute() && !AL.isC2xAttribute())
       continue;
     if (AL.getKind() == ParsedAttr::UnknownAttribute)
-      Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName();
+      Actions.diagnoseUnknownAttribute(AL);
     else {
       Diag(AL.getLoc(), DiagID) << AL.getName();
       AL.setInvalid();
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2983,6 +2983,10 @@
   bool diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND,
                                              SourceLocation Loc);
 
+  /// Emits a diagnostic about an attribute that is unknown.
+  void diagnoseUnknownAttribute(const ParsedAttr &A);
+
+
   /// Returns whether the given function's address can be taken or not,
   /// optionally emitting a diagnostic if the address can't be taken.
   ///
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -572,7 +572,9 @@
 def NSReturnsMismatch : DiagGroup<"nsreturns-mismatch">;
 
 def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
-def UnknownAttributes : DiagGroup<"unknown-attributes">;
+def UnknownAttributeNamespaces : DiagGroup<"unknown-attribute-namespaces">;
+def UnknownAttributes
+    : DiagGroup<"unknown-attributes", [UnknownAttributeNamespaces]>;
 def IgnoredAttributes : DiagGroup<"ignored-attributes">;
 def Attributes : DiagGroup<"attributes", [UnknownAttributes,
                                           IgnoredAttributes]>;
Index: include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- include/clang/Basic/DiagnosticCommonKinds.td
+++ include/clang/Basic/DiagnosticCommonKinds.td
@@ -137,6 +137,9 @@
 
 def warn_unknown_attribute_ignored : Warning<
   "unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
+def warn_unknown_attribute_namespace_ignored : Warning<
+  warn_unknown_attribute_ignored.Text>, InGroup<UnknownAttributeNamespaces>;
+
 def err_use_of_tag_name_without_tag : Error<
   "must use '%1' tag to refer to type %0%select{| in this scope}2">;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to