Distinguish between attributes explicitly written at the request of the user, and attributes implicitly generated to assist in bookkeeping by the compiler. This is done so by table generating a CreateImplicit method for each attribute.

Additionally, remove the optional nature of the spelling list index when creating attributes. This is supported by table generating a Spelling enumeration when the spellings for an attribute are distinct enough to warrant it.

llvm-svn: 199378
This commit is contained in:
Aaron Ballman 2014-01-16 13:03:14 +00:00
parent c61623b170
commit 36a5350e51
15 changed files with 203 additions and 83 deletions

View File

@ -48,10 +48,9 @@ protected:
/// An index into the spelling list of an
/// attribute defined in Attr.td file.
unsigned SpellingListIndex : 4;
bool Inherited : 1;
bool IsPackExpansion : 1;
bool Implicit : 1;
virtual ~Attr();
@ -76,7 +75,7 @@ public:
protected:
Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
: Range(R), AttrKind(AK), SpellingListIndex(SpellingListIndex),
Inherited(false), IsPackExpansion(false) {}
Inherited(false), IsPackExpansion(false), Implicit(false) {}
public:
@ -93,6 +92,11 @@ public:
bool isInherited() const { return Inherited; }
/// \brief Returns true if the attribute has been implicitly created instead
/// of explicitly written by the user.
bool isImplicit() const { return Implicit; }
void setImplicit(bool I) { Implicit = I; }
void setPackExpansion(bool PE) { IsPackExpansion = PE; }
bool isPackExpansion() const { return IsPackExpansion; }

View File

@ -569,6 +569,7 @@ void ASTDumper::dumpAttr(const Attr *A) {
IndentScope Indent(*this);
{
ColorScope Color(*this, AttrColor);
switch (A->getKind()) {
#define ATTR(X) case attr::X: OS << #X; break;
#include "clang/Basic/AttrList.inc"
@ -579,6 +580,8 @@ void ASTDumper::dumpAttr(const Attr *A) {
dumpPointer(A);
dumpSourceRange(A->getRange());
#include "clang/AST/AttrDump.inc"
if (A->isImplicit())
OS << " Implicit";
}
static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {}

View File

@ -941,7 +941,7 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
setSelfDecl(self);
if (selfIsConsumed)
self->addAttr(new (Context) NSConsumedAttr(SourceLocation(), Context));
self->addAttr(NSConsumedAttr::CreateImplicit(Context));
if (selfIsPseudoStrong)
self->setARCPseudoStrong(true);

View File

@ -255,7 +255,7 @@ bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
// If the function is already unavailable, it's not an error.
if (fn->hasAttr<UnavailableAttr>()) return true;
fn->addAttr(new (Context) UnavailableAttr(loc, Context, msg));
fn->addAttr(UnavailableAttr::CreateImplicit(Context, msg, loc));
return true;
}

View File

@ -122,10 +122,9 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
// Otherwise, check to see if we need a max field alignment attribute.
if (unsigned Alignment = Stack->getAlignment()) {
if (Alignment == PackStackEntry::kMac68kAlignmentSentinel)
RD->addAttr(::new (Context) AlignMac68kAttr(SourceLocation(), Context));
RD->addAttr(AlignMac68kAttr::CreateImplicit(Context));
else
RD->addAttr(::new (Context) MaxFieldAlignmentAttr(SourceLocation(),
Context,
RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context,
Alignment * 8));
}
}
@ -133,7 +132,7 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
if (!MSStructPragmaOn)
return;
RD->addAttr(::new (Context) MsStructAttr(SourceLocation(), Context));
RD->addAttr(MsStructAttr::CreateImplicit(Context));
}
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
@ -312,7 +311,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
if (VD->isUsed())
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context));
VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation()));
}
void Sema::AddCFAuditedAttribute(Decl *D) {
@ -324,7 +323,7 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
D->hasAttr<CFUnknownTransferAttr>())
return;
D->addAttr(::new (Context) CFAuditedTransferAttr(Loc, Context));
D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc));
}
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
@ -346,7 +345,7 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) {
= (VisibilityAttr::VisibilityType) rawType;
SourceLocation loc = Stack->back().second;
D->addAttr(::new (Context) VisibilityAttr(loc, Context, type));
D->addAttr(VisibilityAttr::CreateImplicit(Context, type, loc));
}
/// FreeVisContext - Deallocate and null out VisContext.

View File

@ -5420,7 +5420,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0),
Context, Label));
Context, Label, 0));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
@ -6929,7 +6929,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context,
SE->getString()));
SE->getString(), 0));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
@ -7005,7 +7005,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (D.getDeclSpec().isNoreturnSpecified())
NewFD->addAttr(
::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(),
Context));
Context, 0));
// Functions returning a variably modified type violate C99 6.7.5.2p2
// because all functions have linkage.
@ -7027,8 +7027,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Attach the attribute to the new decl. Don't apply the attribute if it
// returns an instance of the class (e.g. assignment operators).
if (!MD || MD->getParent() != Ret) {
NewFD->addAttr(new (Context) WarnUnusedResultAttr(SourceRange(),
Context));
NewFD->addAttr(WarnUnusedResultAttr::CreateImplicit(Context));
}
}
@ -7485,8 +7484,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (OverloadedDecl)
Diag(OverloadedDecl->getLocation(),
diag::note_attribute_overloadable_prev_overload);
NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(),
Context));
NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
}
}
}
@ -7509,8 +7507,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
<< Redeclaration << NewFD;
Diag(Previous.getFoundDecl()->getLocation(),
diag::note_attribute_overloadable_prev_overload);
NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(),
Context));
NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
}
if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
Redeclaration = false;
@ -10090,19 +10087,21 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (FormatIdx < NumParams && // NumParams may be 0 (e.g. vfprintf)
FD->getParamDecl(FormatIdx)->getType()->isObjCObjectPointerType())
fmt = "NSString";
FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
FD->addAttr(FormatAttr::CreateImplicit(Context,
&Context.Idents.get(fmt),
FormatIdx+1,
HasVAListArg ? 0 : FormatIdx+2));
HasVAListArg ? 0 : FormatIdx+2,
FD->getLocation()));
}
}
if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx,
HasVAListArg)) {
if (!FD->hasAttr<FormatAttr>())
FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
FD->addAttr(FormatAttr::CreateImplicit(Context,
&Context.Idents.get("scanf"),
FormatIdx+1,
HasVAListArg ? 0 : FormatIdx+2));
HasVAListArg ? 0 : FormatIdx+2,
FD->getLocation()));
}
// Mark const if we don't care about errno and that is the only
@ -10111,16 +10110,17 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (!getLangOpts().MathErrno &&
Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) {
if (!FD->hasAttr<ConstAttr>())
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
}
if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) &&
!FD->hasAttr<ReturnsTwiceAttr>())
FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context));
FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context,
FD->getLocation()));
if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->hasAttr<NoThrowAttr>())
FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context));
FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation()));
if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->hasAttr<ConstAttr>())
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
}
IdentifierInfo *Name = FD->getIdentifier();
@ -10140,16 +10140,18 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// FIXME: asprintf and vasprintf aren't C99 functions. Should they be
// target-specific builtins, perhaps?
if (!FD->hasAttr<FormatAttr>())
FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
FD->addAttr(FormatAttr::CreateImplicit(Context,
&Context.Idents.get("printf"), 2,
Name->isStr("vasprintf") ? 0 : 3));
Name->isStr("vasprintf") ? 0 : 3,
FD->getLocation()));
}
if (Name->isStr("__CFStringMakeConstantString")) {
// We already have a __builtin___CFStringMakeConstantString,
// but builds that use -fno-constant-cfstrings don't go through that.
if (!FD->hasAttr<FormatArgAttr>())
FD->addAttr(::new (Context) FormatArgAttr(FD->getLocation(), Context, 1));
FD->addAttr(FormatArgAttr::CreateImplicit(Context, 1,
FD->getLocation()));
}
}
@ -11697,8 +11699,9 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
SourceLocation Loc = FD->getLocation();
if (getSourceManager().isInSystemHeader(Loc)) {
if (!FD->hasAttr<UnavailableAttr>())
FD->addAttr(new (Context) UnavailableAttr(Loc, Context,
"this system field has retaining ownership"));
FD->addAttr(UnavailableAttr::CreateImplicit(Context,
"this system field has retaining ownership",
Loc));
return false;
}
}
@ -12071,8 +12074,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
SourceLocation loc = FD->getLocation();
if (getSourceManager().isInSystemHeader(loc)) {
if (!FD->hasAttr<UnavailableAttr>()) {
FD->addAttr(new (Context) UnavailableAttr(loc, Context,
"this system field has retaining ownership"));
FD->addAttr(UnavailableAttr::CreateImplicit(Context,
"this system field has retaining ownership",
loc));
}
} else {
Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
@ -13046,8 +13050,8 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
SourceLocation AliasNameLoc) {
Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc,
LookupOrdinaryName);
AsmLabelAttr *Attr =
::new (Context) AsmLabelAttr(AliasNameLoc, Context, AliasName->getName());
AsmLabelAttr *Attr = ::new (Context) AsmLabelAttr(AliasNameLoc, Context,
AliasName->getName(), 0);
if (PrevDecl)
PrevDecl->addAttr(Attr);
@ -13062,7 +13066,7 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName);
if (PrevDecl) {
PrevDecl->addAttr(::new (Context) WeakAttr(PragmaLoc, Context));
PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc));
} else {
(void)WeakUndeclaredIdentifiers.insert(
std::pair<IdentifierInfo*,WeakInfo>

View File

@ -565,7 +565,8 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkGuardedByAttrCommon(S, D, Attr, Arg))
return;
D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg));
D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg,
Attr.getAttributeSpellingListIndex()));
}
static void handlePtGuardedByAttr(Sema &S, Decl *D,
@ -578,7 +579,8 @@ static void handlePtGuardedByAttr(Sema &S, Decl *D,
return;
D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
S.Context, Arg));
S.Context, Arg,
Attr.getAttributeSpellingListIndex()));
}
static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
@ -1083,7 +1085,8 @@ static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (TagDecl *TD = dyn_cast<TagDecl>(D))
TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
// If the alignment is less than or equal to 8 bits, the packed attribute
// has no effect.
@ -2054,7 +2057,8 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
}
method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(),
S.Context, F));
S.Context, F,
Attr.getAttributeSpellingListIndex()));
}
static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
@ -2297,7 +2301,8 @@ static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
}
D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context,
ParmTSI));
ParmTSI,
Attr.getAttributeSpellingListIndex()));
}
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
@ -3787,8 +3792,10 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D,
return;
}
D->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
D->addAttr(::new (S.Context)
MSP430InterruptAttr(Attr.getLoc(), S.Context, Num,
Attr.getAttributeSpellingListIndex()));
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@ -3819,8 +3826,9 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
return;
}
D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
S.Context));
D->addAttr(::new (S.Context)
X86ForceAlignArgPointerAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
@ -4423,9 +4431,9 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
NewD->addAttr(::new (Context) AliasAttr(W.getLocation(), Context,
NDId->getName()));
NewD->addAttr(::new (Context) WeakAttr(W.getLocation(), Context));
NewD->addAttr(AliasAttr::CreateImplicit(Context, NDId->getName(),
W.getLocation()));
NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation()));
WeakTopLevelDecl.push_back(NewD);
// FIXME: "hideous" code from Sema::LazilyCreateBuiltin
// to insert Decl at TU scope, sorry.
@ -4434,7 +4442,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
PushOnScopeChains(NewD, S);
CurContext = SavedContext;
} else { // just add weak to existing
ND->addAttr(::new (Context) WeakAttr(W.getLocation(), Context));
ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation()));
}
}
@ -4503,8 +4511,9 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) {
static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
Decl *decl) {
if (decl && isForbiddenTypeAllowed(S, decl)) {
decl->addAttr(new (S.Context) UnavailableAttr(diag.Loc, S.Context,
"this system declaration uses an unsupported type"));
decl->addAttr(UnavailableAttr::CreateImplicit(S.Context,
"this system declaration uses an unsupported type",
diag.Loc));
return;
}
if (S.getLangOpts().ObjCAutoRefCount)

View File

@ -1520,7 +1520,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
Invalid = true;
}
if (RD->hasAttr<WeakAttr>())
Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context));
Class->addAttr(WeakAttr::CreateImplicit(Context));
}
}
}
@ -2094,7 +2094,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
if (VS.isOverrideSpecified())
Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context));
Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context, 0));
if (VS.isFinalSpecified())
Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context,
VS.isFinalSpelledSealed()));

View File

@ -98,8 +98,9 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
// If we're in a system header, and this is not a call, just make
// the method unusable.
if (receiverTypeIfCall.isNull() && getSourceManager().isInSystemHeader(loc)) {
method->addAttr(new (Context) UnavailableAttr(loc, Context,
"init method returns a type unrelated to its receiver type"));
method->addAttr(UnavailableAttr::CreateImplicit(Context,
"init method returns a type unrelated to its receiver type",
loc));
return true;
}
@ -230,8 +231,7 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
if (checkInitMethod(method, QualType()))
return true;
method->addAttr(new (Context) NSConsumesSelfAttr(SourceLocation(),
Context));
method->addAttr(NSConsumesSelfAttr::CreateImplicit(Context));
// Don't add a second copy of this attribute, but otherwise don't
// let it be suppressed.
@ -250,8 +250,7 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
break;
}
method->addAttr(new (Context) NSReturnsRetainedAttr(SourceLocation(),
Context));
method->addAttr(NSReturnsRetainedAttr::CreateImplicit(Context));
return false;
}
@ -3167,8 +3166,8 @@ Decl *Sema::ActOnMethodDeclaration(
if (IMD && IMD->hasAttr<ObjCRequiresSuperAttr>() &&
!ObjCMethod->hasAttr<ObjCRequiresSuperAttr>()) {
// merge the attribute into implementation.
ObjCMethod->addAttr(
new (Context) ObjCRequiresSuperAttr(ObjCMethod->getLocation(), Context));
ObjCMethod->addAttr(ObjCRequiresSuperAttr::CreateImplicit(Context,
ObjCMethod->getLocation()));
}
if (isa<ObjCCategoryImplDecl>(ImpDecl)) {
ObjCMethodFamily family = ObjCMethod->getMethodFamily();

View File

@ -2058,8 +2058,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
if (InitialParam1Type == Param1 &&
(NumParams == 1 || InitialParam2Type == Param2)) {
if (AddMallocAttr && !Func->hasAttr<MallocAttr>())
Func->addAttr(::new (Context) MallocAttr(SourceLocation(),
Context));
Func->addAttr(MallocAttr::CreateImplicit(Context));
// Make the function visible to name lookup, even if we found it in
// an unimported module. It either is an implicitly-declared global
// allocation function, or is suppressing that function.
@ -2102,7 +2101,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Alloc->setImplicit();
if (AddMallocAttr)
Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context));
Alloc->addAttr(MallocAttr::CreateImplicit(Context));
ParmVarDecl *ParamDecls[2];
for (unsigned I = 0; I != NumParams; ++I)

View File

@ -1930,16 +1930,16 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
if (lexicalDC)
GetterMethod->setLexicalDeclContext(lexicalDC);
if (property->hasAttr<NSReturnsNotRetainedAttr>())
GetterMethod->addAttr(
::new (Context) NSReturnsNotRetainedAttr(Loc, Context));
GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
Loc));
if (property->hasAttr<ObjCReturnsInnerPointerAttr>())
GetterMethod->addAttr(
::new (Context) ObjCReturnsInnerPointerAttr(Loc, Context));
ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
GetterMethod->addAttr(::new (Context) SectionAttr(Loc,
Context, SA->getName()));
GetterMethod->addAttr(SectionAttr::CreateImplicit(Context, SA->getName(),
Loc));
if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
@ -1991,8 +1991,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
if (lexicalDC)
SetterMethod->setLexicalDeclContext(lexicalDC);
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
SetterMethod->addAttr(::new (Context) SectionAttr(Loc,
Context, SA->getName()));
SetterMethod->addAttr(SectionAttr::CreateImplicit(Context,
SA->getName(), Loc));
// It's possible for the user to have set a very odd custom
// setter selector that causes it to have a method family.
if (getLangOpts().ObjCAutoRefCount)

View File

@ -40,7 +40,8 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
return 0;
}
return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context);
return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context,
A.getAttributeSpellingListIndex());
}

View File

@ -157,8 +157,10 @@ static void instantiateDependentEnableIfAttr(
return;
}
EnableIfAttr *EIA = new (S.getASTContext()) EnableIfAttr(
A->getLocation(), S.getASTContext(), Cond, A->getMessage());
EnableIfAttr *EIA = new (S.getASTContext())
EnableIfAttr(A->getLocation(), S.getASTContext(), Cond,
A->getMessage(),
A->getSpellingListIndex());
New->addAttr(EIA);
}
@ -4391,7 +4393,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// find an instantiated decl for (T y) when the ParentDC for y is
// the translation unit.
// e.g. template <class T> void Foo(auto (*p)(T y) -> decltype(y())) {}
// float baz(float(*)()) { return 0.0; }
// float baz(float(*)()) { return 0.0; }
// Foo(baz);
// The better fix here is perhaps to ensure that a ParmVarDecl, by the time
// it gets here, always has a FunctionOrMethod as its ParentDC??

View File

@ -103,3 +103,10 @@ N: __attribute(()) ;
// CHECK: LabelStmt {{.*}} 'N'
// CHECK-NEXT: NullStmt
}
namespace Test {
extern "C" int printf(const char *format, ...);
// CHECK: FunctionDecl{{.*}}printf
// CHECK-NEXT: ParmVarDecl{{.*}}format{{.*}}'const char *'
// CHECK-NEXT: FormatAttr{{.*}}printf 1 2 Implicit
}

View File

@ -14,6 +14,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
@ -61,6 +62,17 @@ static StringRef NormalizeAttrName(StringRef AttrName) {
return AttrName;
}
// Normalize the name by removing any and all leading and trailing underscores.
// This is different from NormalizeAttrName in that it also handles names like
// _pascal and __pascal.
static StringRef NormalizeNameForSpellingComparison(StringRef Name) {
while (Name.startswith("_"))
Name = Name.substr(1, Name.size());
while (Name.endswith("_"))
Name = Name.substr(0, Name.size() - 1);
return Name;
}
// Normalize attribute spelling only if the spelling has both leading
// and trailing underscores. For example, __ms_struct__ will be
// normalized to "ms_struct"; __cdecl will remain intact.
@ -151,6 +163,10 @@ namespace {
virtual bool isEnumArg() const { return false; }
virtual bool isVariadicEnumArg() const { return false; }
virtual void writeImplicitCtorArgs(raw_ostream &OS) const {
OS << getUpperName();
}
};
class SimpleArgument : public Argument {
@ -394,6 +410,9 @@ namespace {
void writeCtorParameters(raw_ostream &OS) const {
OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName();
}
void writeImplicitCtorArgs(raw_ostream &OS) const {
OS << "Is" << getUpperName() << "Expr, " << getUpperName();
}
void writeDeclarations(raw_ostream &OS) const {
OS << "bool is" << getLowerName() << "Expr;\n";
OS << "union {\n";
@ -491,6 +510,9 @@ namespace {
OS << getType() << " *" << getUpperName() << ", unsigned "
<< getUpperName() << "Size";
}
void writeImplicitCtorArgs(raw_ostream &OS) const {
OS << getUpperName() << ", " << getUpperName() << "Size";
}
void writeDeclarations(raw_ostream &OS) const {
OS << " unsigned " << getLowerName() << "Size;\n";
OS << " " << getType() << " *" << getLowerName() << ";";
@ -1104,6 +1126,20 @@ static void writeAttrAccessorDefinition(Record &R, raw_ostream &OS) {
}
}
static bool SpellingNamesAreCommon(const std::vector<Record *>& Spellings) {
assert(!Spellings.empty() && "An empty list of spellings was provided");
std::string FirstName = NormalizeNameForSpellingComparison(
Spellings.front()->getValueAsString("Name"));
for (std::vector<Record *>::const_iterator I = llvm::next(Spellings.begin()),
E = Spellings.end(); I != E; ++I) {
std::string Name = NormalizeNameForSpellingComparison(
(*I)->getValueAsString("Name"));
if (Name != FirstName)
return false;
}
return true;
}
namespace clang {
// Emits the class definitions for attributes.
@ -1153,7 +1189,58 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
ae = Args.end();
OS << "\n public:\n";
OS << "\npublic:\n";
std::vector<Record *> Spellings = R.getValueAsListOfDefs("Spellings");
// If there are zero or one spellings, all spelling-related functionality
// can be elided. If all of the spellings share the same name, the spelling
// functionality can also be elided.
bool ElideSpelling = (Spellings.size() <= 1) ||
SpellingNamesAreCommon(Spellings);
if (!ElideSpelling) {
OS << " enum Spelling {\n";
for (std::vector<Record *>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
if (I != Spellings.begin())
OS << ",\n";
const Record &S = **I;
std::string Variety = S.getValueAsString("Variety");
std::string Spelling = S.getValueAsString("Name");
std::string Namespace = "";
if (Variety == "CXX11")
Namespace = S.getValueAsString("Namespace");
OS << " " << Variety << "_";
if (!Namespace.empty())
OS << Namespace << "_";
OS << Spelling;
}
OS << "\n };\n\n";
}
OS << " static " << R.getName() << "Attr *CreateImplicit(";
OS << "ASTContext &Ctx";
if (!ElideSpelling)
OS << ", Spelling S";
for (ai = Args.begin(); ai != ae; ++ai) {
OS << ", ";
(*ai)->writeCtorParameters(OS);
}
OS << ", SourceRange Loc = SourceRange()";
OS << ") {\n";
OS << " " << R.getName() << "Attr *A = new (Ctx) " << R.getName();
OS << "Attr(Loc, Ctx, ";
for (ai = Args.begin(); ai != ae; ++ai) {
(*ai)->writeImplicitCtorArgs(OS);
OS << ", ";
}
OS << (ElideSpelling ? "0" : "S") << ");\n";
OS << " A->setImplicit(true);\n";
OS << " return A;\n }\n\n";
OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
bool HasOpt = false;
@ -1166,7 +1253,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
OS << " , ";
OS << "unsigned SI = 0\n";
OS << "unsigned SI\n";
OS << " )\n";
OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
@ -1198,7 +1285,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
OS << " , ";
OS << "unsigned SI = 0\n";
OS << "unsigned SI\n";
OS << " )\n";
OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
@ -1483,6 +1570,8 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
OS << " case attr::" << R.getName() << ": {\n";
if (R.isSubClassOf(InhClass))
OS << " bool isInherited = Record[Idx++];\n";
OS << " bool isImplicit = Record[Idx++];\n";
OS << " unsigned Spelling = Record[Idx++];\n";
ArgRecords = R.getValueAsListOfDefs("Args");
Args.clear();
for (ai = ArgRecords.begin(), ae = ArgRecords.end(); ai != ae; ++ai) {
@ -1495,9 +1584,10 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
OS << ", ";
(*ri)->writePCHReadArgs(OS);
}
OS << ");\n";
OS << ", Spelling);\n";
if (R.isSubClassOf(InhClass))
OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n";
OS << " New->setImplicit(isImplicit);\n";
OS << " break;\n";
OS << " }\n";
}
@ -1527,6 +1617,9 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
<< "Attr>(A);\n";
if (R.isSubClassOf(InhClass))
OS << " Record.push_back(SA->isInherited());\n";
OS << " Record.push_back(A->isImplicit());\n";
OS << " Record.push_back(A->getSpellingListIndex());\n";
for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai)
createArgument(**ai, R.getName())->writePCHWrite(OS);
OS << " break;\n";
@ -1806,7 +1899,7 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
OS << ", ";
(*ai)->writeTemplateInstantiationArgs(OS);
}
OS << ");\n }\n";
OS << ", A->getSpellingListIndex());\n }\n";
}
OS << " } // end switch\n"
<< " llvm_unreachable(\"Unknown attribute!\");\n"