forked from OSchip/llvm-project
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:
parent
a1ee70ba75
commit
3b5a8f5ffc
|
@ -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">,
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue