From 36a5350e51a6dcfae424332aaa266a1e5bfb8c4f Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Thu, 16 Jan 2014 13:03:14 +0000 Subject: [PATCH] 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 --- clang/include/clang/AST/Attr.h | 10 +- clang/lib/AST/ASTDumper.cpp | 3 + clang/lib/AST/DeclObjC.cpp | 2 +- clang/lib/Sema/Sema.cpp | 2 +- clang/lib/Sema/SemaAttr.cpp | 13 +-- clang/lib/Sema/SemaDecl.cpp | 58 +++++----- clang/lib/Sema/SemaDeclAttr.cpp | 39 ++++--- clang/lib/Sema/SemaDeclCXX.cpp | 4 +- clang/lib/Sema/SemaDeclObjC.cpp | 15 ++- clang/lib/Sema/SemaExprCXX.cpp | 5 +- clang/lib/Sema/SemaObjCProperty.cpp | 14 +-- clang/lib/Sema/SemaStmtAttr.cpp | 3 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 +- clang/test/Misc/ast-dump-attr.cpp | 7 ++ clang/utils/TableGen/ClangAttrEmitter.cpp | 103 +++++++++++++++++- 15 files changed, 203 insertions(+), 83 deletions(-) diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 61130b5dc12e..01c32c0269b3 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -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; } diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index 5a81966c7029..1ee114f3ddf8 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -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, ...) {} diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index f6685de71aaf..429b235315dc 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -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); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index badff7e0dc8d..9ab3bea27449 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -255,7 +255,7 @@ bool Sema::makeUnavailableInSystemHeader(SourceLocation loc, // If the function is already unavailable, it's not an error. if (fn->hasAttr()) return true; - fn->addAttr(new (Context) UnavailableAttr(loc, Context, msg)); + fn->addAttr(UnavailableAttr::CreateImplicit(Context, msg, loc)); return true; } diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 8f9ab32517d6..0214ba456c7e 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -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()) return; - D->addAttr(::new (Context) CFAuditedTransferAttr(Loc, Context)); + D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc)); } typedef std::vector > 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. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e020df127e41..76472651e1e1 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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::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(E); NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, - SE->getString())); + SE->getString(), 0)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::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(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()) - 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()) - FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); + FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); } if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && !FD->hasAttr()) - FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context)); + FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context, + FD->getLocation())); if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->hasAttr()) - FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); + FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation())); if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->hasAttr()) - 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()) - 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()) - 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()) - 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()) { - 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 diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 30f2e67e2588..49ab6ed1b82c 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -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(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(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) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9647cea407d3..c774f25241bc 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1520,7 +1520,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, Invalid = true; } if (RD->hasAttr()) - 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())); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 34d1965fa580..f7f1b4b5653f 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -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() && !ObjCMethod->hasAttr()) { // merge the attribute into implementation. - ObjCMethod->addAttr( - new (Context) ObjCRequiresSuperAttr(ObjCMethod->getLocation(), Context)); + ObjCMethod->addAttr(ObjCRequiresSuperAttr::CreateImplicit(Context, + ObjCMethod->getLocation())); } if (isa(ImpDecl)) { ObjCMethodFamily family = ObjCMethod->getMethodFamily(); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a29a279e4bab..363c7710b4c7 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2058,8 +2058,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, if (InitialParam1Type == Param1 && (NumParams == 1 || InitialParam2Type == Param2)) { if (AddMallocAttr && !Func->hasAttr()) - 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) diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index b1343301ef80..659b732c810c 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1930,16 +1930,16 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, if (lexicalDC) GetterMethod->setLexicalDeclContext(lexicalDC); if (property->hasAttr()) - GetterMethod->addAttr( - ::new (Context) NSReturnsNotRetainedAttr(Loc, Context)); + GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context, + Loc)); if (property->hasAttr()) GetterMethod->addAttr( - ::new (Context) ObjCReturnsInnerPointerAttr(Loc, Context)); + ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc)); if (const SectionAttr *SA = property->getAttr()) - 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()) - 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) diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 80d203e3f5bc..9bb191d52bbf 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -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()); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6995ae712bb3..2961e08cc800 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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 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?? diff --git a/clang/test/Misc/ast-dump-attr.cpp b/clang/test/Misc/ast-dump-attr.cpp index 3714cdbb0695..5b96797d1204 100644 --- a/clang/test/Misc/ast-dump-attr.cpp +++ b/clang/test/Misc/ast-dump-attr.cpp @@ -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 +} \ No newline at end of file diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index b3950c200346..47de7da6a57a 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -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& Spellings) { + assert(!Spellings.empty() && "An empty list of spellings was provided"); + std::string FirstName = NormalizeNameForSpellingComparison( + Spellings.front()->getValueAsString("Name")); + for (std::vector::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 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::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(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"