diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2013-11-29 14:57:58 +0000 |
---|---|---|
committer | Aaron Ballman <aaron@aaronballman.com> | 2013-11-29 14:57:58 +0000 |
commit | 80469038c0c420f5f8a4cd580b6f9e69e80ab7f2 (patch) | |
tree | 720d3f46f37e7abf70fd9cde61a2827168265e1d | |
parent | dc5809021372a8cba1e085b80d263bc101b49a70 (diff) | |
download | bcm5719-llvm-80469038c0c420f5f8a4cd580b6f9e69e80ab7f2.tar.gz bcm5719-llvm-80469038c0c420f5f8a4cd580b6f9e69e80ab7f2.zip |
Enables support for custom subject lists for attributes. As a testbed, uses the custom subject for the ibaction attribute.
llvm-svn: 195960
-rw-r--r-- | clang/include/clang/Basic/Attr.td | 6 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 9 | ||||
-rw-r--r-- | clang/include/clang/Sema/AttributeList.h | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 12 | ||||
-rw-r--r-- | clang/test/SemaObjC/ibaction.m | 4 | ||||
-rw-r--r-- | clang/utils/TableGen/ClangAttrEmitter.cpp | 63 |
6 files changed, 68 insertions, 29 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 5e1dba89bd9..307c8b181a7 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -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 { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a314bf493a8..984e34ac3bc 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2036,7 +2036,8 @@ def warn_attribute_wrong_decl_type : Warning< "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 : Error< "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 : Error< 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< diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h index 2e8116c570e..690ccccbef6 100644 --- a/clang/include/clang/Sema/AttributeList.h +++ b/clang/include/clang/Sema/AttributeList.h @@ -858,7 +858,8 @@ enum AttributeDeclKind { ExpectedMethodOrProperty, ExpectedStructOrUnion, ExpectedStructOrUnionOrClass, - ExpectedType + ExpectedType, + ExpectedObjCInstanceMethod }; } // end namespace clang diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index f7d8fa7c417..f49ea11faae 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1119,16 +1119,8 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } 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) { diff --git a/clang/test/SemaObjC/ibaction.m b/clang/test/SemaObjC/ibaction.m index 9c59d7aaec5..43c927ce264 100644 --- a/clang/test/SemaObjC/ibaction.m +++ b/clang/test/SemaObjC/ibaction.m @@ -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. diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index abdb98d8f26..ec076e250c9 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -21,6 +21,7 @@ #include <algorithm> #include <cctype> #include <sstream> +#include <set> using namespace llvm; @@ -1729,7 +1730,19 @@ static std::string CalculateDiagnostic(const Record &S) { 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(const Record &S) { 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(const Record &Attr, raw_ostream &OS) { 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(const Record &Attr, raw_ostream &OS) { 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(const Record &Attr, raw_ostream &OS) { SS << " return true;\n"; SS << "}\n\n"; - if (HasSubsetSubject) - return "DefaultAppertainsTo"; - OS << SS.str(); return FnName; } |