diff options
author | John McCall <rjmccall@apple.com> | 2016-03-03 00:10:03 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2016-03-03 00:10:03 +0000 |
commit | 3b5a8f5ffc83a92fe865e53f7b7af8f0be635bd8 (patch) | |
tree | 227076e392c489c0f986d018f110ca64299ae362 | |
parent | a1ee70ba752bedb1904c315d753c2be607a9a463 (diff) | |
download | bcm5719-llvm-3b5a8f5ffc83a92fe865e53f7b7af8f0be635bd8.tar.gz bcm5719-llvm-3b5a8f5ffc83a92fe865e53f7b7af8f0be635bd8.zip |
Improve some infrastructure for extended parameter infos and
fix a bug with the instantiation of ns_consumed parameter
attributes in ARC.
llvm-svn: 262551
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | clang/include/clang/Sema/AttributeList.h | 35 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 4 | ||||
-rw-r--r-- | clang/lib/AST/TypePrinter.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 56 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 41 | ||||
-rw-r--r-- | clang/test/SemaCXX/cxx11-gnu-attrs.cpp | 1 | ||||
-rw-r--r-- | clang/test/SemaObjCXX/arc-nsconsumed-errors.mm | 4 | ||||
-rw-r--r-- | clang/test/SemaObjCXX/arc-templates.mm | 8 |
10 files changed, 129 insertions, 35 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7f5ecca9b6a..1d000341c64 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2934,6 +2934,9 @@ def warn_ns_attribute_wrong_return_type : Warning< "%0 attribute only applies to %select{functions|methods|properties}1 that " "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">, InGroup<IgnoredAttributes>; +def err_ns_attribute_wrong_parameter_type : Error< + "%0 attribute only applies to " + "%select{Objective-C object|pointer|pointer-to-CF-pointer}1 parameters">; def warn_ns_attribute_wrong_parameter_type : Warning< "%0 attribute only applies to " "%select{Objective-C object|pointer|pointer-to-CF-pointer}1 parameters">, diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h index 836646de609..ddcc3e90907 100644 --- a/clang/include/clang/Sema/AttributeList.h +++ b/clang/include/clang/Sema/AttributeList.h @@ -94,9 +94,11 @@ private: SourceLocation ScopeLoc; SourceLocation EllipsisLoc; + unsigned AttrKind : 16; + /// The number of expression arguments this attribute has. /// The expressions themselves are stored after the object. - unsigned NumArgs : 15; + unsigned NumArgs : 16; /// Corresponds to the Syntax enum. unsigned SyntaxUsed : 3; @@ -122,7 +124,11 @@ private: /// True if this has a ParsedType unsigned HasParsedType : 1; - unsigned AttrKind : 8; + /// True if the processing cache is valid. + mutable unsigned HasProcessingCache : 1; + + /// A cached value. + mutable unsigned ProcessingCache : 8; /// \brief The location of the 'unavailable' keyword in an /// availability attribute. @@ -231,7 +237,8 @@ private: ScopeLoc(scopeLoc), EllipsisLoc(ellipsisLoc), NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), - HasParsedType(false), NextInPosition(nullptr), NextInPool(nullptr) { + HasParsedType(false), HasProcessingCache(false), + NextInPosition(nullptr), NextInPool(nullptr) { if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion)); AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } @@ -249,8 +256,8 @@ private: ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), - UnavailableLoc(unavailable), MessageExpr(messageExpr), - NextInPosition(nullptr), NextInPool(nullptr) { + HasProcessingCache(false), UnavailableLoc(unavailable), + MessageExpr(messageExpr), NextInPosition(nullptr), NextInPool(nullptr) { ArgsUnion PVal(Parm); memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); @@ -271,7 +278,7 @@ private: ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(3), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), - NextInPosition(nullptr), NextInPool(nullptr) { + HasProcessingCache(false), NextInPosition(nullptr), NextInPool(nullptr) { ArgsVector Args; Args.push_back(Parm1); Args.push_back(Parm2); @@ -289,7 +296,7 @@ private: ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(true), IsProperty(false), HasParsedType(false), - NextInPosition(nullptr), NextInPool(nullptr) { + HasProcessingCache(false), NextInPosition(nullptr), NextInPool(nullptr) { ArgsUnion PVal(ArgKind); memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion)); TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot(); @@ -307,7 +314,7 @@ private: ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true), - NextInPosition(nullptr), NextInPool(nullptr) { + HasProcessingCache(false), NextInPosition(nullptr), NextInPool(nullptr){ new (&getTypeBuffer()) ParsedType(typeArg); AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } @@ -321,7 +328,7 @@ private: ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false), - NextInPosition(nullptr), NextInPool(nullptr) { + HasProcessingCache(false), NextInPosition(nullptr), NextInPool(nullptr) { new (&getPropertyDataBuffer()) PropertyData(getterId, setterId); AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } @@ -373,6 +380,16 @@ public: bool isInvalid() const { return Invalid; } void setInvalid(bool b = true) const { Invalid = b; } + bool hasProcessingCache() const { return HasProcessingCache; } + unsigned getProcessingCache() const { + assert(hasProcessingCache()); + return ProcessingCache; + } + void setProcessingCache(unsigned value) const { + ProcessingCache = value; + HasProcessingCache = true; + } + bool isUsedAsTypeAttr() const { return UsedAsTypeAttr; } void setUsedAsTypeAttr() { UsedAsTypeAttr = true; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 22879d3b1c0..21d4d4312e6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7786,6 +7786,10 @@ public: void AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, unsigned SpellingListIndex, bool InInstantiation = false); + void AddNSConsumedAttr(SourceRange AttrRange, Decl *D, + unsigned SpellingListIndex, bool isNSConsumed, + bool isTemplateInstantiation); + //===--------------------------------------------------------------------===// // C++ Coroutines TS // diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index b202523bdaf..f6dbc78c471 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -641,6 +641,10 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, ParamPolicyRAII ParamPolicy(Policy); for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) { if (i) OS << ", "; + + auto EPI = T->getExtParameterInfo(i); + if (EPI.isConsumed()) OS << "__attribute__((ns_consumed)) "; + print(T->getParamType(i), OS, StringRef()); } } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b031e38c757..942d920fe30 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3777,6 +3777,11 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, if (attr.isInvalid()) return true; + if (attr.hasProcessingCache()) { + CC = (CallingConv) attr.getProcessingCache(); + return false; + } + unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0; if (!checkAttributeNumArgs(*this, attr, ReqArgs)) { attr.setInvalid(); @@ -3836,6 +3841,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, CC = TI.getDefaultCallingConv(MT); } + attr.setProcessingCache((unsigned) CC); return false; } @@ -4030,31 +4036,45 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { } static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + S.AddNSConsumedAttr(Attr.getRange(), D, Attr.getAttributeSpellingListIndex(), + Attr.getKind() == AttributeList::AT_NSConsumed, + /*template instantiation*/ false); +} + +void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D, + unsigned spellingIndex, bool isNSConsumed, + bool isTemplateInstantiation) { ParmVarDecl *param = cast<ParmVarDecl>(D); - bool typeOK, cf; + bool typeOK; - if (Attr.getKind() == AttributeList::AT_NSConsumed) { - typeOK = isValidSubjectOfNSAttribute(S, param->getType()); - cf = false; + if (isNSConsumed) { + typeOK = isValidSubjectOfNSAttribute(*this, param->getType()); } else { - typeOK = isValidSubjectOfCFAttribute(S, param->getType()); - cf = true; + typeOK = isValidSubjectOfCFAttribute(*this, param->getType()); } if (!typeOK) { - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getRange() << Attr.getName() << cf; - return; - } - - if (cf) - param->addAttr(::new (S.Context) - CFConsumedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + // These attributes are normally just advisory, but in ARC, ns_consumed + // is significant. Allow non-dependent code to contain inappropriate + // attributes even in ARC, but require template instantiations to be + // set up correctly. + Diag(D->getLocStart(), + (isTemplateInstantiation && isNSConsumed && + getLangOpts().ObjCAutoRefCount + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type)) + << attrRange + << (isNSConsumed ? "ns_consumed" : "cf_consumed") + << (isNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); + return; + } + + if (isNSConsumed) + param->addAttr(::new (Context) + NSConsumedAttr(attrRange, Context, spellingIndex)); else - param->addAttr(::new (S.Context) - NSConsumedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + param->addAttr(::new (Context) + CFConsumedAttr(attrRange, Context, spellingIndex)); } static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index ffb7eeda4f1..af93cde68c1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -286,6 +286,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, } } + if (isa<NSConsumedAttr>(TmplAttr) || isa<CFConsumedAttr>(TmplAttr)) { + AddNSConsumedAttr(TmplAttr->getRange(), New, + TmplAttr->getSpellingListIndex(), + isa<NSConsumedAttr>(TmplAttr), + /*template instantiation*/ true); + continue; + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 54276b6940c..d76b0d71b3e 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -100,9 +100,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, case AttributeList::AT_ObjCGC: \ case AttributeList::AT_ObjCOwnership -// Function type attributes. -#define FUNCTION_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_NoReturn: \ +// Calling convention attributes. +#define CALLING_CONV_ATTRS_CASELIST \ case AttributeList::AT_CDecl: \ case AttributeList::AT_FastCall: \ case AttributeList::AT_StdCall: \ @@ -111,10 +110,15 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, case AttributeList::AT_VectorCall: \ case AttributeList::AT_MSABI: \ case AttributeList::AT_SysVABI: \ - case AttributeList::AT_Regparm: \ case AttributeList::AT_Pcs: \ case AttributeList::AT_IntelOclBicc +// Function type attributes. +#define FUNCTION_TYPE_ATTRS_CASELIST \ + case AttributeList::AT_NoReturn: \ + case AttributeList::AT_Regparm: \ + CALLING_CONV_ATTRS_CASELIST + // Microsoft-specific type qualifiers. #define MS_TYPE_ATTRS_CASELIST \ case AttributeList::AT_Ptr32: \ @@ -2957,6 +2961,26 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D, unsigned ChunkIndex) { assert(D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function); + // Check for an explicit CC attribute. + for (auto Attr = FTI.AttrList; Attr; Attr = Attr->getNext()) { + switch (Attr->getKind()) { + CALLING_CONV_ATTRS_CASELIST: { + // Ignore attributes that don't validate or can't apply to the + // function type. We'll diagnose the failure to apply them in + // handleFunctionTypeAttr. + CallingConv CC; + if (!S.CheckCallingConvAttr(*Attr, CC) && + (!FTI.isVariadic || supportsVariadicCall(CC))) { + return CC; + } + break; + } + + default: + break; + } + } + bool IsCXXInstanceMethod = false; if (S.getLangOpts().CPlusPlus) { @@ -5986,9 +6010,14 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, // Modify the CC from the wrapped function type, wrap it all back, and then // wrap the whole thing in an AttributedType as written. The modified type // might have a different CC if we ignored the attribute. - FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC); - QualType Equivalent = + QualType Equivalent; + if (CCOld == CC) { + Equivalent = type; + } else { + auto EI = unwrapped.get()->getExtInfo().withCallingConv(CC); + Equivalent = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + } type = S.Context.getAttributedType(CCAttrKind, type, Equivalent); return true; } diff --git a/clang/test/SemaCXX/cxx11-gnu-attrs.cpp b/clang/test/SemaCXX/cxx11-gnu-attrs.cpp index d20617815e6..231be727714 100644 --- a/clang/test/SemaCXX/cxx11-gnu-attrs.cpp +++ b/clang/test/SemaCXX/cxx11-gnu-attrs.cpp @@ -19,6 +19,7 @@ int *[[gnu::unused]] attr_on_ptr; [[gnu::fastcall]] void pr17424_4() [[gnu::stdcall]]; // expected-warning@-1 {{calling convention 'fastcall' ignored for this target}} // expected-warning@-2 {{attribute 'stdcall' ignored, because it cannot be applied to a type}} +// expected-warning@-3 {{calling convention 'stdcall' ignored for this target}} void pr17424_5 [[gnu::fastcall]](); // expected-warning@-1 {{calling convention 'fastcall' ignored for this target}} diff --git a/clang/test/SemaObjCXX/arc-nsconsumed-errors.mm b/clang/test/SemaObjCXX/arc-nsconsumed-errors.mm index c78d8a5f4ad..638a1ebd2ad 100644 --- a/clang/test/SemaObjCXX/arc-nsconsumed-errors.mm +++ b/clang/test/SemaObjCXX/arc-nsconsumed-errors.mm @@ -29,9 +29,9 @@ void releaser(__attribute__((ns_consumed)) id); releaser_t r2 = releaser; // no-warning template <typename T> -void templateFunction(T) { } // expected-note {{candidate template ignored: could not match 'void (__strong id)' against 'void (id)'}} \ +void templateFunction(T) { } // expected-note {{candidate template ignored: could not match 'void (__strong id)' against 'void (__attribute__((ns_consumed)) id)'}} \ // expected-note {{candidate template ignored: failed template argument deduction}} -releaser_t r3 = templateFunction<id>; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (id)'}} +releaser_t r3 = templateFunction<id>; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (__attribute__((ns_consumed)) id)'}} template <typename T> void templateReleaser(__attribute__((ns_consumed)) T) { } // expected-note 2{{candidate template ignored: failed template argument deduction}} diff --git a/clang/test/SemaObjCXX/arc-templates.mm b/clang/test/SemaObjCXX/arc-templates.mm index 81425985e62..97854dff8c1 100644 --- a/clang/test/SemaObjCXX/arc-templates.mm +++ b/clang/test/SemaObjCXX/arc-templates.mm @@ -442,3 +442,11 @@ namespace produced_nested { take_no(produces<4>::fn); // expected-error {{no matching function}} } } + +namespace instantiate_consumed { + template <class T> void take(CONSUMED T t) {} // expected-note {{candidate template ignored: substitution failure [with T = int]: ns_consumed attribute only applies to Objective-C object parameters}} + void test() { + take((id) 0); + take((int) 0); // expected-error {{no matching function for call to 'take'}} + } +} |