Hi, This patch series adds support for non-inheritable attributes on declarations. It is a prerequisite for certain aspects of the CUDA support. At the same time it has the side effect of taking care of some FIXMEs associated with the 'overloadable' attribute.
The series isn't perfect by any means but I think it represents a worthwhile incremental improvement. The series does not change default behaviour so the test suite is unmodified. 0001-tblgen-Add-support-for-non-inheritable-attributes.patch is a patch to LLVM (tblgen). I'd particularly appreciate any advice on this patch as I'm not too familiar with tblgen. In particular I'm not sure if this is a reliable way of obtaining the name of the most specific superclass: + const std::string &SuperName = R.getSuperClasses().back()->getName(); Reviews appreciated. Thanks, -- Peter
>From 6578818470ba92d0ca500401dabfb7c6cbd0b0f5 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <[email protected]> Date: Sun, 2 Jan 2011 04:28:22 +0000 Subject: [PATCH 1/3] Generalise support for non-inheritable attributes Inheritable attributes on declarations may be inherited by any later redeclaration at merge time. By contrast, a non-inheritable attribute will not be inherited by later redeclarations. Non-inheritable attributes may be semantically analysed early, allowing them to influence the redeclaration/overloading process. Before this change, the "overloadable" attribute received special handling to be treated as non-inheritable, while all other attributes were treated as inheritable. This patch generalises the concept, while removing a FIXME. Some CUDA location attributes are also marked as non-inheritable in order to support special overloading semantics (to be introduced in a later patch). The patch introduces a new Attr subclass, InheritableAttr, from which all inheritable attributes derive. Non-inheritable attributes simply derive from Attr. N.B. I did not review every attribute to determine whether it should be marked non-inheritable. This can be done later on an incremental basis, as this change does not affect default functionality. --- include/clang/AST/Attr.h | 22 ++++- include/clang/Basic/Attr.td | 154 ++++++++++++++++++----------------- include/clang/Basic/AttrKinds.h | 1 + lib/Sema/SemaDecl.cpp | 10 +- lib/Serialization/ASTReaderDecl.cpp | 2 - lib/Serialization/ASTWriter.cpp | 1 - 6 files changed, 102 insertions(+), 88 deletions(-) diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 62ca49f..a7605d8 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -58,9 +58,10 @@ class Attr { private: SourceLocation Loc; unsigned AttrKind : 16; - bool Inherited : 1; protected: + bool Inherited : 1; + virtual ~Attr(); void* operator new(size_t bytes) throw() { @@ -99,9 +100,6 @@ public: SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } - bool isInherited() const { return Inherited; } - void setInherited(bool I) { Inherited = I; } - // Clone this attribute. virtual Attr* clone(ASTContext &C) const = 0; @@ -109,6 +107,22 @@ public: static bool classof(const Attr *) { return true; } }; +class InheritableAttr : public Attr { +protected: + InheritableAttr(attr::Kind AK, SourceLocation L) + : Attr(AK, L) {} + +public: + bool isInherited() const { return Inherited; } + void setInherited(bool I) { Inherited = I; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() <= attr::LAST_INHERITABLE; + } + static bool classof(const InheritableAttr *) { return true; } +}; + #include "clang/AST/Attrs.inc" /// AttrVec - A vector of Attr, which is how they are stored on the AST. diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 9e5dd79..d3039d2 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -89,92 +89,94 @@ class Attr { code AdditionalMembers = [{}]; } +class InheritableAttr : Attr; + // // Attributes begin here // -def Alias : Attr { +def Alias : InheritableAttr { let Spellings = ["alias"]; let Args = [StringArgument<"Aliasee">]; } -def Aligned : Attr { +def Aligned : InheritableAttr { let Spellings = ["align", "aligned"]; let Subjects = [NonBitField, NormalVar, Tag]; let Args = [AlignedArgument<"Alignment">]; let Namespaces = ["", "std"]; } -def AlignMac68k : Attr { +def AlignMac68k : InheritableAttr { let Spellings = []; } -def AlwaysInline : Attr { +def AlwaysInline : InheritableAttr { let Spellings = ["always_inline"]; } -def AnalyzerNoReturn : Attr { +def AnalyzerNoReturn : InheritableAttr { let Spellings = ["analyzer_noreturn"]; } -def Annotate : Attr { +def Annotate : InheritableAttr { let Spellings = ["annotate"]; let Args = [StringArgument<"Annotation">]; } -def AsmLabel : Attr { +def AsmLabel : InheritableAttr { let Spellings = []; let Args = [StringArgument<"Label">]; } -def BaseCheck : Attr { +def BaseCheck : InheritableAttr { let Spellings = ["base_check"]; let Subjects = [CXXRecord]; let Namespaces = ["", "std"]; } -def Blocks : Attr { +def Blocks : InheritableAttr { let Spellings = ["blocks"]; let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>]; } -def CarriesDependency : Attr { +def CarriesDependency : InheritableAttr { let Spellings = ["carries_dependency"]; let Subjects = [ParmVar, Function]; let Namespaces = ["", "std"]; } -def CDecl : Attr { +def CDecl : InheritableAttr { let Spellings = ["cdecl", "__cdecl"]; } -def CFReturnsRetained : Attr { +def CFReturnsRetained : InheritableAttr { let Spellings = ["cf_returns_retained"]; } -def CFReturnsNotRetained : Attr { +def CFReturnsNotRetained : InheritableAttr { let Spellings = ["cf_returns_not_retained"]; } -def Cleanup : Attr { +def Cleanup : InheritableAttr { let Spellings = ["cleanup"]; let Args = [FunctionArgument<"FunctionDecl">]; } -def Common : Attr { +def Common : InheritableAttr { let Spellings = ["common"]; } -def Const : Attr { +def Const : InheritableAttr { let Spellings = ["const"]; } -def Constructor : Attr { +def Constructor : InheritableAttr { let Spellings = ["constructor"]; let Args = [IntArgument<"Priority">]; } -def CUDAConstant : Attr { +def CUDAConstant : InheritableAttr { let Spellings = ["constant"]; } @@ -182,7 +184,7 @@ def CUDADevice : Attr { let Spellings = ["device"]; } -def CUDAGlobal : Attr { +def CUDAGlobal : InheritableAttr { let Spellings = ["global"]; } @@ -190,120 +192,120 @@ def CUDAHost : Attr { let Spellings = ["host"]; } -def CUDALaunchBounds : Attr { +def CUDALaunchBounds : InheritableAttr { let Spellings = ["launch_bounds"]; let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>]; } -def CUDAShared : Attr { +def CUDAShared : InheritableAttr { let Spellings = ["shared"]; } -def Deprecated : Attr { +def Deprecated : InheritableAttr { let Spellings = ["deprecated"]; let Args = [StringArgument<"Message">]; } -def Destructor : Attr { +def Destructor : InheritableAttr { let Spellings = ["destructor"]; let Args = [IntArgument<"Priority">]; } -def DLLExport : Attr { +def DLLExport : InheritableAttr { let Spellings = ["dllexport"]; } -def DLLImport : Attr { +def DLLImport : InheritableAttr { let Spellings = ["dllimport"]; } -def FastCall : Attr { +def FastCall : InheritableAttr { let Spellings = ["fastcall", "__fastcall"]; } -def Final : Attr { +def Final : InheritableAttr { let Spellings = ["final"]; let Subjects = [CXXRecord, CXXVirtualMethod]; let Namespaces = ["", "std"]; } -def Format : Attr { +def Format : InheritableAttr { let Spellings = ["format"]; let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">, IntArgument<"FirstArg">]; } -def FormatArg : Attr { +def FormatArg : InheritableAttr { let Spellings = ["format_arg"]; let Args = [IntArgument<"FormatIdx">]; } -def GNUInline : Attr { +def GNUInline : InheritableAttr { let Spellings = ["gnu_inline"]; } -def Hiding : Attr { +def Hiding : InheritableAttr { let Spellings = ["hiding"]; let Subjects = [Field, CXXMethod]; let Namespaces = ["", "std"]; } -def IBAction : Attr { +def IBAction : InheritableAttr { let Spellings = ["ibaction"]; } -def IBOutlet : Attr { +def IBOutlet : InheritableAttr { let Spellings = ["iboutlet"]; } -def IBOutletCollection : Attr { +def IBOutletCollection : InheritableAttr { let Spellings = ["iboutletcollection"]; let Args = [TypeArgument<"Interface">]; } -def Malloc : Attr { +def Malloc : InheritableAttr { let Spellings = ["malloc"]; } -def MaxFieldAlignment : Attr { +def MaxFieldAlignment : InheritableAttr { let Spellings = []; let Args = [UnsignedArgument<"Alignment">]; } -def MayAlias : Attr { +def MayAlias : InheritableAttr { let Spellings = ["may_alias"]; } -def MSP430Interrupt : Attr { +def MSP430Interrupt : InheritableAttr { let Spellings = []; let Args = [UnsignedArgument<"Number">]; } -def MBlazeInterruptHandler : Attr { +def MBlazeInterruptHandler : InheritableAttr { let Spellings = []; } -def MBlazeSaveVolatiles : Attr { +def MBlazeSaveVolatiles : InheritableAttr { let Spellings = []; } -def Naked : Attr { +def Naked : InheritableAttr { let Spellings = ["naked"]; } -def NoCommon : Attr { +def NoCommon : InheritableAttr { let Spellings = ["nocommon"]; } -def NoDebug : Attr { +def NoDebug : InheritableAttr { let Spellings = ["nodebug"]; } -def NoInline : Attr { +def NoInline : InheritableAttr { let Spellings = ["noinline"]; } -def NonNull : Attr { +def NonNull : InheritableAttr { let Spellings = ["nonnull"]; let Args = [VariadicUnsignedArgument<"Args">]; let AdditionalMembers = @@ -316,39 +318,39 @@ def NonNull : Attr { } }]; } -def NoReturn : Attr { +def NoReturn : InheritableAttr { let Spellings = ["noreturn"]; // FIXME: Does GCC allow this on the function instead? let Subjects = [Function]; let Namespaces = ["", "std"]; } -def NoInstrumentFunction : Attr { +def NoInstrumentFunction : InheritableAttr { let Spellings = ["no_instrument_function"]; let Subjects = [Function]; } -def NoThrow : Attr { +def NoThrow : InheritableAttr { let Spellings = ["nothrow"]; } -def NSReturnsRetained : Attr { +def NSReturnsRetained : InheritableAttr { let Spellings = ["ns_returns_retained"]; } -def NSReturnsNotRetained : Attr { +def NSReturnsNotRetained : InheritableAttr { let Spellings = ["ns_returns_not_retained"]; } -def ObjCException : Attr { +def ObjCException : InheritableAttr { let Spellings = ["objc_exception"]; } -def ObjCNSObject : Attr { +def ObjCNSObject : InheritableAttr { let Spellings = ["NSOjbect"]; } -def Override : Attr { +def Override : InheritableAttr { let Spellings = ["override"]; let Subjects = [CXXVirtualMethod]; let Namespaces = ["", "std"]; @@ -358,7 +360,7 @@ def Overloadable : Attr { let Spellings = ["overloadable"]; } -def Ownership : Attr { +def Ownership : InheritableAttr { let Spellings = ["ownership_holds", "ownership_returns", "ownership_takes"]; let Args = [EnumArgument<"OwnKind", "OwnershipKind", ["ownership_holds", "ownership_returns", "ownership_takes"], @@ -366,104 +368,104 @@ def Ownership : Attr { StringArgument<"Module">, VariadicUnsignedArgument<"Args">]; } -def Packed : Attr { +def Packed : InheritableAttr { let Spellings = ["packed"]; } -def Pure : Attr { +def Pure : InheritableAttr { let Spellings = ["pure"]; } -def Regparm : Attr { +def Regparm : InheritableAttr { let Spellings = ["regparm"]; let Args = [UnsignedArgument<"NumParams">]; } -def ReqdWorkGroupSize : Attr { +def ReqdWorkGroupSize : InheritableAttr { let Spellings = ["reqd_work_group_size"]; let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">, UnsignedArgument<"ZDim">]; } -def InitPriority : Attr { +def InitPriority : InheritableAttr { let Spellings = ["init_priority"]; let Args = [UnsignedArgument<"Priority">]; } -def Section : Attr { +def Section : InheritableAttr { let Spellings = ["section"]; let Args = [StringArgument<"Name">]; } -def Sentinel : Attr { +def Sentinel : InheritableAttr { let Spellings = ["sentinel"]; let Args = [DefaultIntArgument<"Sentinel", 0>, DefaultIntArgument<"NullPos", 0>]; } -def StdCall : Attr { +def StdCall : InheritableAttr { let Spellings = ["stdcall", "__stdcall"]; } -def ThisCall : Attr { +def ThisCall : InheritableAttr { let Spellings = ["thiscall", "__thiscall"]; } -def Pascal : Attr { +def Pascal : InheritableAttr { let Spellings = ["pascal", "__pascal"]; } -def TransparentUnion : Attr { +def TransparentUnion : InheritableAttr { let Spellings = ["transparent_union"]; } -def Unavailable : Attr { +def Unavailable : InheritableAttr { let Spellings = ["unavailable"]; let Args = [StringArgument<"Message">]; } -def Unused : Attr { +def Unused : InheritableAttr { let Spellings = ["unused"]; } -def Used : Attr { +def Used : InheritableAttr { let Spellings = ["used"]; } -def Uuid : Attr { +def Uuid : InheritableAttr { let Spellings = ["uuid"]; let Args = [StringArgument<"Guid">]; let Subjects = [CXXRecord]; } -def Visibility : Attr { +def Visibility : InheritableAttr { let Spellings = ["visibility"]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; } -def VecReturn : Attr { +def VecReturn : InheritableAttr { let Spellings = ["vecreturn"]; let Subjects = [CXXRecord]; } -def WarnUnusedResult : Attr { +def WarnUnusedResult : InheritableAttr { let Spellings = ["warn_unused_result"]; } -def Weak : Attr { +def Weak : InheritableAttr { let Spellings = ["weak"]; } -def WeakImport : Attr { +def WeakImport : InheritableAttr { let Spellings = ["weak_import"]; } -def WeakRef : Attr { +def WeakRef : InheritableAttr { let Spellings = ["weakref"]; } -def X86ForceAlignArgPointer : Attr { +def X86ForceAlignArgPointer : InheritableAttr { let Spellings = []; } diff --git a/include/clang/Basic/AttrKinds.h b/include/clang/Basic/AttrKinds.h index 822573b..65c4f98 100644 --- a/include/clang/Basic/AttrKinds.h +++ b/include/clang/Basic/AttrKinds.h @@ -21,6 +21,7 @@ namespace attr { // Kind - This is a list of all the recognized kinds of attributes. enum Kind { #define ATTR(X) X, +#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X, #include "clang/Basic/AttrList.inc" NUM_ATTRS }; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index abd6319..e1cdaec 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1018,11 +1018,11 @@ static void MergeDeclAttributes(Decl *New, Decl *Old, ASTContext &C) { // we process them. if (!New->hasAttrs()) New->setAttrs(AttrVec()); - for (Decl::attr_iterator i = Old->attr_begin(), e = Old->attr_end(); i != e; - ++i) { - // FIXME: Make this more general than just checking for Overloadable. - if (!DeclHasAttr(New, *i) && (*i)->getKind() != attr::Overloadable) { - Attr *NewAttr = (*i)->clone(C); + for (specific_attr_iterator<InheritableAttr> + i = Old->specific_attr_begin<InheritableAttr>(), + e = Old->specific_attr_end<InheritableAttr>(); i != e; ++i) { + if (!DeclHasAttr(New, *i)) { + InheritableAttr *NewAttr = cast<InheritableAttr>((*i)->clone(C)); NewAttr->setInherited(true); New->addAttr(NewAttr); } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index f2183ea..d58ed7c 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1241,12 +1241,10 @@ void ASTReader::ReadAttributes(PerFileData &F, AttrVec &Attrs, Attr *New = 0; attr::Kind Kind = (attr::Kind)Record[Idx++]; SourceLocation Loc = ReadSourceLocation(F, Record, Idx); - bool isInherited = Record[Idx++]; #include "clang/Serialization/AttrPCHRead.inc" assert(New && "Unable to decode attribute?"); - New->setInherited(isInherited); Attrs.push_back(New); } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 8c0fb42..9782fff 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -2230,7 +2230,6 @@ void ASTWriter::WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record) { const Attr * A = *i; Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs AddSourceLocation(A->getLocation(), Record); - Record.push_back(A->isInherited()); #include "clang/Serialization/AttrPCHWrite.inc" -- 1.7.1
>From 70069bd799753a4e708d580a3b636896c2cdfb9b Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <[email protected]> Date: Sun, 2 Jan 2011 04:26:45 +0000 Subject: [PATCH] tblgen: Add support for non-inheritable attributes This patch makes the necessary changes to TableGen to support non-inheritable attributes. --- utils/TableGen/ClangAttrEmitter.cpp | 59 +++++++++++++++++++++++++++------- 1 files changed, 47 insertions(+), 12 deletions(-) diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index db10d79..f33cb50 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -462,8 +462,9 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) { for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); i != e; ++i) { Record &R = **i; + const std::string &SuperName = R.getSuperClasses().back()->getName(); - OS << "class " << R.getName() << "Attr : public Attr {\n"; + OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n"; std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args"); std::vector<Argument*> Args; @@ -494,7 +495,7 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) { } OS << " )\n"; - OS << " : Attr(attr::" << R.getName() << ", L)\n"; + OS << " : " << SuperName << "(attr::" << R.getName() << ", L)\n"; for (ai = Args.begin(); ai != ae; ++ai) { OS << " , "; @@ -558,31 +559,58 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) { } } +static void EmitAttrList(raw_ostream &OS, StringRef Class, + const std::vector<Record*> &AttrList) { + std::vector<Record*>::const_iterator i = AttrList.begin(), e = AttrList.end(); + + if (i != e) { + // Move the end iterator back to emit the last attribute. + for(--e; i != e; ++i) + OS << Class << "(" << (*i)->getName() << ")\n"; + + OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n"; + } +} + void ClangAttrListEmitter::run(raw_ostream &OS) { OS << "// This file is generated by TableGen. Do not edit.\n\n"; OS << "#ifndef LAST_ATTR\n"; OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n"; OS << "#endif\n\n"; - - std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); - if (i != e) { - // Move the end iterator back to emit the last attribute. - for(--e; i != e; ++i) - OS << "ATTR(" << (*i)->getName() << ")\n"; - - OS << "LAST_ATTR(" << (*i)->getName() << ")\n\n"; + OS << "#ifndef INHERITABLE_ATTR\n"; + OS << "#define INHERITABLE_ATTR(NAME) ATTR(NAME)\n"; + OS << "#endif\n\n"; + + OS << "#ifndef LAST_INHERITABLE_ATTR\n"; + OS << "#define LAST_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; + OS << "#endif\n\n"; + + Record *InhClass = Records.getClass("InheritableAttr"); + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), + NonInhAttrs, InhAttrs; + for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(); + i != e; ++i) { + if ((*i)->isSubClassOf(InhClass)) + InhAttrs.push_back(*i); + else + NonInhAttrs.push_back(*i); } + EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs); + EmitAttrList(OS, "ATTR", NonInhAttrs); + OS << "#undef LAST_ATTR\n"; + OS << "#undef INHERITABLE_ATTR\n"; + OS << "#undef LAST_INHERITABLE_ATTR\n"; OS << "#undef ATTR\n"; } void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { OS << "// This file is generated by TableGen. Do not edit.\n\n"; + Record *InhClass = Records.getClass("InheritableAttr"); std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), ArgRecords; std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae; @@ -596,6 +624,8 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { for (; i != e; ++i) { Record &R = **i; OS << " case attr::" << R.getName() << ": {\n"; + if (R.isSubClassOf(InhClass)) + OS << " bool isInherited = Record[Idx++];\n"; ArgRecords = R.getValueAsListOfDefs("Args"); Args.clear(); for (ai = ArgRecords.begin(), ae = ArgRecords.end(); ai != ae; ++ai) { @@ -609,6 +639,8 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { (*ri)->writePCHReadArgs(OS); } OS << ");\n"; + if (R.isSubClassOf(InhClass)) + OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n"; OS << " break;\n"; OS << " }\n"; } @@ -616,6 +648,7 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { } void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) { + Record *InhClass = Records.getClass("InheritableAttr"); std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args; std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae; @@ -627,9 +660,11 @@ void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) { Record &R = **i; OS << " case attr::" << R.getName() << ": {\n"; Args = R.getValueAsListOfDefs("Args"); - if (!Args.empty()) + if (R.isSubClassOf(InhClass) || !Args.empty()) OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName() << "Attr>(A);\n"; + if (R.isSubClassOf(InhClass)) + OS << " Record.push_back(SA->isInherited());\n"; for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai) createArgument(**ai, R.getName())->writePCHWrite(OS); OS << " break;\n"; -- 1.7.1
>From b5d2f047de468b4c2e7642cfed59bb992c2e4d51 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <[email protected]> Date: Mon, 3 Jan 2011 01:40:55 +0000 Subject: [PATCH 2/3] Sema: support for processing non-inheritable declaration attributes early --- include/clang/Sema/Sema.h | 6 ++- lib/Sema/SemaDeclAttr.cpp | 71 +++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 24 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 57f480f..341fa25 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1366,8 +1366,10 @@ public: // More parsing and symbol table subroutines. // Decl attributes - this routine is the top level dispatcher. - void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); - void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL); + void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, + bool NonInheritable = true, bool Inheritable = true); + void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, + bool NonInheritable = true, bool Inheritable = true); void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, bool &IncompleteImpl, unsigned DiagID); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 0e8ba23..2d5595f 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2583,18 +2583,19 @@ static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Top Level Sema Entry Points //===----------------------------------------------------------------------===// -/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if -/// the attribute applies to decls. If the attribute is a type attribute, just -/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to -/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). -static void ProcessDeclAttribute(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) { - if (Attr.isInvalid()) - return; +static void ProcessNonInheritableDeclAttr(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) { + switch (Attr.getKind()) { + case AttributeList::AT_device: HandleDeviceAttr (D, Attr, S); break; + case AttributeList::AT_host: HandleHostAttr (D, Attr, S); break; + case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break; + default: + break; + } +} - if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr)) - // FIXME: Try to deal with other __declspec attributes! - return; +static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) { switch (Attr.getKind()) { case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break; case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; @@ -2608,6 +2609,12 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, // Ignore these, these are type attributes, handled by // ProcessTypeAttributes. break; + case AttributeList::AT_device: + case AttributeList::AT_host: + case AttributeList::AT_overloadable: + // Ignore, this is a non-inheritable attribute, handled + // by ProcessNonInheritableDeclAttr. + break; case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; case AttributeList::AT_always_inline: @@ -2623,7 +2630,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break; - case AttributeList::AT_device: HandleDeviceAttr (D, Attr, S); break; case AttributeList::AT_ext_vector_type: HandleExtVectorTypeAttr(scope, D, Attr, S); break; @@ -2633,7 +2639,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_global: HandleGlobalAttr (D, Attr, S); break; case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break; case AttributeList::AT_hiding: HandleHidingAttr (D, Attr, S); break; - case AttributeList::AT_host: HandleHostAttr (D, Attr, S); break; case AttributeList::AT_launch_bounds: HandleLaunchBoundsAttr(D, Attr, S); break; @@ -2683,7 +2688,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_objc_exception: HandleObjCExceptionAttr(D, Attr, S); break; - case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break; case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; @@ -2719,18 +2723,40 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, } } +/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if +/// the attribute applies to decls. If the attribute is a type attribute, just +/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to +/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). +static void ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S, + bool NonInheritable, bool Inheritable) { + if (Attr.isInvalid()) + return; + + if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr)) + // FIXME: Try to deal with other __declspec attributes! + return; + + if (NonInheritable) + ProcessNonInheritableDeclAttr(scope, D, Attr, S); + + if (Inheritable) + ProcessInheritableDeclAttr(scope, D, Attr, S); +} + /// ProcessDeclAttributeList - Apply all the decl attributes in the specified /// attribute list to the specified decl, ignoring any type attributes. void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, - const AttributeList *AttrList) { + const AttributeList *AttrList, + bool NonInheritable, bool Inheritable) { for (const AttributeList* l = AttrList; l; l = l->getNext()) { - ProcessDeclAttribute(S, D, *l, *this); + ProcessDeclAttribute(S, D, *l, *this, NonInheritable, Inheritable); } // GCC accepts // static int a9 __attribute__((weakref)); // but that looks really pointless. We reject it. - if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { + if (Inheritable && D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) << dyn_cast<NamedDecl>(D)->getNameAsString(); return; @@ -2790,10 +2816,11 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { /// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in /// it, apply them to D. This is a bit tricky because PD can have attributes /// specified in many different places, and we need to find and apply them all. -void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { +void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, + bool NonInheritable, bool Inheritable) { // It's valid to "forward-declare" #pragma weak, in which case we // have to do this. - if (!WeakUndeclaredIdentifiers.empty()) { + if (Inheritable && !WeakUndeclaredIdentifiers.empty()) { if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { if (IdentifierInfo *Id = ND->getIdentifier()) { llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I @@ -2809,7 +2836,7 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { // Apply decl attributes from the DeclSpec if present. if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable); // Walk the declarator structure, applying decl attributes that were in a type // position to the decl itself. This handles cases like: @@ -2817,11 +2844,11 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { // when X is a decl attribute. for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable); // Finally, apply any attributes on the decl itself. if (const AttributeList *Attrs = PD.getAttributes()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable); } /// PushParsingDeclaration - Enter a new "scope" of deprecation -- 1.7.1
>From 9de86c93bc9c203b034ac352aa058ab7c1ef1444 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <[email protected]> Date: Mon, 3 Jan 2011 01:41:54 +0000 Subject: [PATCH 3/3] Sema: process non-inheritable attributes on function declarations early This allows us to simplify the handling for the overloadable attribute, removing a number of FIXMEs. --- include/clang/Sema/Sema.h | 3 +- lib/Sema/SemaDecl.cpp | 48 ++++++++++++++++------------- lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 +---- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 341fa25..04961b4 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -724,8 +724,7 @@ public: void CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, - bool &Redeclaration, - bool &OverloadableAttrRequired); + bool &Redeclaration); void CheckMain(FunctionDecl *FD); Decl *ActOnParamDeclarator(Scope *S, Declarator &D); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e1cdaec..db63c1f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3848,13 +3848,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Params.data(), Params.size()); - bool OverloadableAttrRequired=false; // FIXME: HACK! + // Process the non-inheritable attributes on this declaration. + ProcessDeclAttributes(S, NewFD, D, + /*NonInheritable=*/true, /*Inheritable=*/false); + if (!getLangOptions().CPlusPlus) { // Perform semantic checking on the function declaration. bool isExplctSpecialization=false; CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization, - Redeclaration, - /*FIXME:*/OverloadableAttrRequired); + Redeclaration); assert((NewFD->isInvalidDecl() || !Redeclaration || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); @@ -3930,9 +3932,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } // Perform semantic checking on the function declaration. - bool flag_c_overloaded=false; // unused for c++ CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, - Redeclaration, /*FIXME:*/flag_c_overloaded); + Redeclaration); assert((NewFD->isInvalidDecl() || !Redeclaration || Previous.getResultKind() != LookupResult::FoundOverloaded) && @@ -4039,7 +4040,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // (for example to check for conflicts, etc). // FIXME: This needs to happen before we merge declarations. Then, // let attribute merging cope with attribute conflicts. - ProcessDeclAttributes(S, NewFD, D); + ProcessDeclAttributes(S, NewFD, D, + /*NonInheritable=*/false, /*Inheritable=*/true); // attributes declared post-definition are currently ignored // FIXME: This should happen during attribute merging @@ -4054,17 +4056,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AddKnownFunctionAttributes(NewFD); - if (OverloadableAttrRequired && !NewFD->hasAttr<OverloadableAttr>()) { - // If a function name is overloadable in C, then every function - // with that name must be marked "overloadable". - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) - << Redeclaration << NewFD; - if (!Previous.empty()) - Diag(Previous.getRepresentativeDecl()->getLocation(), - diag::note_attribute_overloadable_prev_overload); - NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(), Context)); - } - if (NewFD->hasAttr<OverloadableAttr>() && !NewFD->getType()->getAs<FunctionProtoType>()) { Diag(NewFD->getLocation(), @@ -4125,8 +4116,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, - bool &Redeclaration, - bool &OverloadableAttrRequired) { + bool &Redeclaration) { // If NewFD is already known erroneous, don't do any of this checking. if (NewFD->isInvalidDecl()) { // If this is a class member, mark the class invalid immediately. @@ -4171,9 +4161,6 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = true; OldDecl = Previous.getFoundDecl(); } else { - if (!getLangOptions().CPlusPlus) - OverloadableAttrRequired = true; - switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { case Ovl_Match: @@ -4188,6 +4175,23 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = false; break; } + + if (!getLangOptions().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) { + // If a function name is overloadable in C, then every function + // with that name must be marked "overloadable". + Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) + << Redeclaration << NewFD; + NamedDecl *OverloadedDecl = 0; + if (Redeclaration) + OverloadedDecl = OldDecl; + else if (!Previous.empty()) + OverloadedDecl = Previous.getRepresentativeDecl(); + if (OverloadedDecl) + Diag(OverloadedDecl->getLocation(), + diag::note_attribute_overloadable_prev_overload); + NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(), + Context)); + } } if (Redeclaration) { diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9db3a8c..d023f13 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1079,7 +1079,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Function->setInvalidDecl(); bool Redeclaration = false; - bool OverloadableAttrRequired = false; bool isExplicitSpecialization = false; LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), @@ -1131,8 +1130,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, - isExplicitSpecialization, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); + isExplicitSpecialization, Redeclaration); NamedDecl *PrincipalDecl = (TemplateParams ? cast<NamedDecl>(FunctionTemplate) @@ -1415,9 +1413,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } bool Redeclaration = false; - bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); + SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); -- 1.7.1
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
