r195960 - Enables support for custom subject lists for attributes. As a testbed, uses the custom subject for the ibaction attribute.

Aaron Ballman aaron at aaronballman.com
Fri Nov 29 06:57:59 PST 2013


Author: aaronballman
Date: Fri Nov 29 08:57:58 2013
New Revision: 195960

URL: http://llvm.org/viewvc/llvm-project?rev=195960&view=rev
Log:
Enables support for custom subject lists for attributes. As a testbed, uses the custom subject for the ibaction attribute.

Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/test/SemaObjC/ibaction.m
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=195960&r1=195959&r2=195960&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Fri Nov 29 08:57:58 2013
@@ -37,6 +37,9 @@ def NormalVar : SubsetSubject<Var,
 def NonBitField : SubsetSubject<Field,
                                 [{!S->isBitField()}]>;
 
+def ObjCInstanceMethod : SubsetSubject<ObjCMethod,
+                                       [{S->isInstanceMethod()}]>;
+
 // A single argument to an attribute
 class Argument<string name, bit optional> {
   string Name = name;
@@ -451,7 +454,8 @@ def Hot : InheritableAttr {
 
 def IBAction : InheritableAttr {
   let Spellings = [GNU<"ibaction">];
-//  let Subjects = [ObjCMethod];
+  let Subjects = SubjectList<[ObjCInstanceMethod], WarnDiag,
+                             "ExpectedObjCInstanceMethod">;
 }
 
 def IBOutlet : InheritableAttr {

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=195960&r1=195959&r2=195960&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Nov 29 08:57:58 2013
@@ -2036,7 +2036,8 @@ def warn_attribute_wrong_decl_type : War
   "variables, functions and tag types|thread-local variables|"
   "variables and fields|variables, data members and tag types|"
   "types and namespaces|Objective-C interfaces|methods and properties|"
-  "struct or union|struct, union or class|types}1">,
+  "struct or union|struct, union or class|types|"
+  "Objective-C instance methods}1">,
   InGroup<IgnoredAttributes>;
 def err_attribute_wrong_decl_type : Error<
   "%0 attribute only applies to %select{functions|unions|"
@@ -2047,7 +2048,8 @@ def err_attribute_wrong_decl_type : Erro
   "variables, functions and tag types|thread-local variables|"
   "variables and fields|variables, data members and tag types|"
   "types and namespaces|Objective-C interfaces|methods and properties|"
-  "struct or union|struct, union or class|types}1">;
+  "struct or union|struct, union or class|types|"
+  "Objective-C instance methods}1">;
 def warn_type_attribute_wrong_type : Warning<
   "'%0' only applies to %select{function|pointer|"
   "Objective-C object or block pointer}1 types; type here is %2">,
@@ -2393,9 +2395,6 @@ def err_attribute_not_supported_in_lang
 def warn_attribute_iboutlet : Warning<
   "%0 attribute can only be applied to instance variables or properties">,
   InGroup<IgnoredAttributes>;
-def warn_attribute_ibaction: Warning<
-  "ibaction attribute can only be applied to Objective-C instance methods">,
-  InGroup<IgnoredAttributes>;
 def err_iboutletcollection_type : Error<
   "invalid type %0 as argument of iboutletcollection attribute">;
 def err_iboutletcollection_builtintype : Error<

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=195960&r1=195959&r2=195960&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Fri Nov 29 08:57:58 2013
@@ -858,7 +858,8 @@ enum AttributeDeclKind {
   ExpectedMethodOrProperty,
   ExpectedStructOrUnion,
   ExpectedStructOrUnionOrClass,
-  ExpectedType
+  ExpectedType,
+  ExpectedObjCInstanceMethod
 };
 
 }  // end namespace clang

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=195960&r1=195959&r2=195960&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Nov 29 08:57:58 2013
@@ -1119,16 +1119,8 @@ static void handlePackedAttr(Sema &S, De
 }
 
 static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
-  // The IBAction attributes only apply to instance methods.
-  if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
-    if (MD->isInstanceMethod()) {
-      D->addAttr(::new (S.Context)
-                 IBActionAttr(Attr.getRange(), S.Context,
-                              Attr.getAttributeSpellingListIndex()));
-      return;
-    }
-
-  S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName();
+  D->addAttr(::new (S.Context) IBActionAttr(Attr.getRange(), S.Context,
+                                        Attr.getAttributeSpellingListIndex()));
 }
 
 static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) {

Modified: cfe/trunk/test/SemaObjC/ibaction.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/ibaction.m?rev=195960&r1=195959&r2=195960&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/ibaction.m (original)
+++ cfe/trunk/test/SemaObjC/ibaction.m Fri Nov 29 08:57:58 2013
@@ -4,12 +4,12 @@
 {
   __attribute__((iboutlet)) id myoutlet;
 }
-+ (void) __attribute__((ibaction)) myClassMethod:(id)msg; // expected-warning{{ibaction attribute can only be applied to Objective-C instance methods}}
++ (void) __attribute__((ibaction)) myClassMethod:(id)msg; // expected-warning{{'ibaction' attribute only applies to Objective-C instance methods}}
 - (void) __attribute__((ibaction)) myMessage:(id)msg;
 @end
 
 @implementation Foo
-+ (void) __attribute__((ibaction)) myClassMethod:(id)msg {} // expected-warning{{ibaction attribute can only be applied to Objective-C instance methods}}
++ (void) __attribute__((ibaction)) myClassMethod:(id)msg {} // expected-warning{{'ibaction' attribute only applies to Objective-C instance methods}}
 // Normally attributes should not be attached to method definitions, but
 // we allow 'ibaction' to be attached because it can be expanded from
 // the IBAction macro.

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=195960&r1=195959&r2=195960&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Fri Nov 29 08:57:58 2013
@@ -21,6 +21,7 @@
 #include <algorithm>
 #include <cctype>
 #include <sstream>
+#include <set>
 
 using namespace llvm;
 
@@ -1729,7 +1730,19 @@ static std::string CalculateDiagnostic(c
   std::vector<Record *> Subjects = S.getValueAsListOfDefs("Subjects");
   for (std::vector<Record *>::const_iterator I = Subjects.begin(),
        E = Subjects.end(); I != E; ++I) {
-    uint32_t V = StringSwitch<uint32_t>((*I)->getName())
+    const Record &R = (**I);
+    std::string Name;
+
+    if (R.isSubClassOf("SubsetSubject")) {
+      PrintError(R.getLoc(), "SubsetSubjects should use a custom diagnostic");
+      // As a fallback, look through the SubsetSubject to see what its base
+      // type is, and use that. This needs to be updated if SubsetSubjects
+      // are allowed within other SubsetSubjects.
+      Name = R.getValueAsDef("Base")->getName();
+    } else
+      Name = R.getName();
+
+    uint32_t V = StringSwitch<uint32_t>(Name)
                    .Case("Function", Func)
                    .Case("Var", Var)
                    .Case("ObjCMethod", ObjCMethod)
@@ -1794,6 +1807,35 @@ static std::string CalculateDiagnostic(c
   return "";
 }
 
+static std::string GenerateCustomAppertainsTo(const Record &Subject,
+                                              raw_ostream &OS) {
+  // If this code has already been generated, simply return the previous
+  // instance of it.
+  static std::set<std::string> CustomSubjectSet;
+  std::set<std::string>::iterator I = CustomSubjectSet.find(Subject.getName());
+  if (I != CustomSubjectSet.end())
+    return *I;
+
+  Record *Base = Subject.getValueAsDef("Base");
+
+  // Not currently support custom subjects within custom subjects.
+  if (Base->isSubClassOf("SubsetSubject")) {
+    PrintFatalError(Subject.getLoc(),
+                    "SubsetSubjects within SubsetSubjects is not supported");
+    return "";
+  }
+
+  std::string FnName = "is" + Subject.getName();
+  OS << "static bool " << FnName << "(const Decl *D) {\n";
+  OS << "  const " << Base->getName() << "Decl *S = cast<" << Base->getName();
+  OS << "Decl>(D);\n";
+  OS << "  return " << Subject.getValueAsString("CheckCode") << ";\n";
+  OS << "}\n\n";
+
+  CustomSubjectSet.insert(FnName);
+  return FnName;
+}
+
 static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
   // If the attribute does not contain a Subjects definition, then use the
   // default appertainsTo logic.
@@ -1808,9 +1850,6 @@ static std::string GenerateAppertainsTo(
   if (Subjects.empty())
     return "DefaultAppertainsTo";
 
-  // If any of the subjects are a SubsetSubject derivative, bail out for now
-  // as though it was using custom parsing.
-  bool HasSubsetSubject = false;
   bool Warn = SubjectObj->getValueAsDef("Diag")->getValueAsBit("Warn");
 
   // Otherwise, generate an appertainsTo check specific to this attribute which
@@ -1823,10 +1862,17 @@ static std::string GenerateAppertainsTo(
   SS << "  if (";
   for (std::vector<Record *>::const_iterator I = Subjects.begin(),
        E = Subjects.end(); I != E; ++I) {
-    if ((*I)->isSubClassOf("SubsetSubject"))
-      HasSubsetSubject = true;
+    // If the subject has custom code associated with it, generate a function
+    // for it. The function cannot be inlined into this check (yet) because it
+    // requires the subject to be of a specific type, and were that information
+    // inlined here, it would not support an attribute with multiple custom
+    // subjects.
+    if ((*I)->isSubClassOf("SubsetSubject")) {
+      SS << "!" << GenerateCustomAppertainsTo(**I, OS) << "(D)";
+    } else {
+      SS << "!isa<" << (*I)->getName() << "Decl>(D)";
+    }
 
-    SS << "!isa<" << (*I)->getName() << "Decl>(D)";
     if (I + 1 != E)
       SS << " && ";
   }
@@ -1842,9 +1888,6 @@ static std::string GenerateAppertainsTo(
   SS << "  return true;\n";
   SS << "}\n\n";
 
-  if (HasSubsetSubject)
-    return "DefaultAppertainsTo";
-
   OS << SS.str();
   return FnName;
 }





More information about the cfe-commits mailing list