Improve some infrastructure for extended parameter infos and

fix a bug with the instantiation of ns_consumed parameter
attributes in ARC.

llvm-svn: 262551
This commit is contained in:
John McCall 2016-03-03 00:10:03 +00:00
parent a1ee70ba75
commit 3b5a8f5ffc
10 changed files with 127 additions and 33 deletions

View File

@ -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">,

View File

@ -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; }

View File

@ -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
//

View File

@ -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());
}
}

View File

@ -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) {
ParmVarDecl *param = cast<ParmVarDecl>(D);
bool typeOK, cf;
S.AddNSConsumedAttr(Attr.getRange(), D, Attr.getAttributeSpellingListIndex(),
Attr.getKind() == AttributeList::AT_NSConsumed,
/*template instantiation*/ false);
}
if (Attr.getKind() == AttributeList::AT_NSConsumed) {
typeOK = isValidSubjectOfNSAttribute(S, param->getType());
cf = false;
void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D,
unsigned spellingIndex, bool isNSConsumed,
bool isTemplateInstantiation) {
ParmVarDecl *param = cast<ParmVarDecl>(D);
bool typeOK;
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;
// 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 (cf)
param->addAttr(::new (S.Context)
CFConsumedAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
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,

View File

@ -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

View File

@ -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;
}

View File

@ -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}}

View File

@ -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}}

View File

@ -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'}}
}
}