From ae6ebd3af525c23c6216b76dd28a282790dce78f Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 10 Nov 2015 21:28:44 +0000 Subject: Implement __attribute__((internal_linkage)). The attrubite is applicable to functions and variables and changes the linkage of the subject to internal. This is the same functionality as C-style "static", but applicable to class methods; and the same as anonymouns namespaces, but can apply to individual methods of a class. Following the proposal in http://lists.llvm.org/pipermail/cfe-dev/2015-October/045580.html llvm-svn: 252648 --- clang/lib/Sema/SemaDecl.cpp | 24 +++++++++++++ clang/lib/Sema/SemaDeclAttr.cpp | 79 ++++++++++++++++++++++++++++++++++------- 2 files changed, 90 insertions(+), 13 deletions(-) (limited to 'clang/lib/Sema') diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 009fe16f948..92bbadd627d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2216,6 +2216,15 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex); else if (const auto *OA = dyn_cast(Attr)) NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex); + else if (const auto *InternalLinkageA = dyn_cast(Attr)) + NewAttr = S.mergeInternalLinkageAttr( + D, InternalLinkageA->getRange(), + &S.Context.Idents.get(InternalLinkageA->getSpelling()), + AttrSpellingListIndex); + else if (const auto *CommonA = dyn_cast(Attr)) + NewAttr = S.mergeCommonAttr(D, CommonA->getRange(), + &S.Context.Idents.get(CommonA->getSpelling()), + AttrSpellingListIndex); else if (isa(Attr)) // AlignedAttrs are handled separately, because we need to handle all // such attributes on a declaration at the same time. @@ -2664,6 +2673,13 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, } } + if (New->hasAttr() && + !Old->hasAttr()) { + Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) + << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + New->dropAttr(); + } // If a function is first declared with a calling convention, but is later // declared or defined without one, all following decls assume the calling @@ -3377,6 +3393,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->dropAttr(); } + if (New->hasAttr() && + !Old->hasAttr()) { + Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) + << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + New->dropAttr(); + } + // Merge the types. VarDecl *MostRecent = Old->getMostRecentDecl(); if (MostRecent != Old) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5b85bf0da2c..a9473d2e119 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -244,11 +244,12 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr, /// \brief Diagnose mutually exclusive attributes when present on a given /// declaration. Returns true if diagnosed. template -static bool checkAttrMutualExclusion(Sema &S, Decl *D, - const AttributeList &Attr) { +static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, + IdentifierInfo *Ident) { if (AttrTy *A = D->getAttr()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << Attr.getName() << A; + S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident + << A; + S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } return false; @@ -1523,7 +1524,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion(S, D, Attr)) + if (checkAttrMutualExclusion(S, D, Attr.getRange(), Attr.getName())) return; D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context, @@ -1531,7 +1532,7 @@ static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion(S, D, Attr)) + if (checkAttrMutualExclusion(S, D, Attr.getRange(), Attr.getName())) return; D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context, @@ -1573,12 +1574,13 @@ static void handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CPlusPlus) { S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::Cpp; + << Attr.getName() << AttributeLangSupport::Cpp; return; } - D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + if (CommonAttr *CA = S.mergeCommonAttr(D, Attr.getRange(), Attr.getName(), + Attr.getAttributeSpellingListIndex())) + D->addAttr(CA); } static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { @@ -1703,7 +1705,8 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, static void handleNotTailCalledAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion(S, D, Attr)) + if (checkAttrMutualExclusion(S, D, Attr.getRange(), + Attr.getName())) return; D->addAttr(::new (S.Context) NotTailCalledAttr( @@ -3392,6 +3395,42 @@ AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } +CommonAttr *Sema::mergeCommonAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex) { + if (checkAttrMutualExclusion(*this, D, Range, Ident)) + return nullptr; + + return ::new (Context) CommonAttr(Range, Context, AttrSpellingListIndex); +} + +InternalLinkageAttr * +Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex) { + if (auto VD = dyn_cast(D)) { + // Attribute applies to Var but not any subclass of it (like ParmVar, + // ImplicitParm or VarTemplateSpecialization). + if (VD->getKind() != Decl::Var) { + Diag(Range.getBegin(), diag::warn_attribute_wrong_decl_type) + << Ident << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); + return nullptr; + } + // Attribute does not apply to non-static local variables. + if (VD->hasLocalStorage()) { + Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage); + return nullptr; + } + } + + if (checkAttrMutualExclusion(*this, D, Range, Ident)) + return nullptr; + + return ::new (Context) + InternalLinkageAttr(Range, Context, AttrSpellingListIndex); +} + MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (OptimizeNoneAttr *Optnone = D->getAttr()) { @@ -3428,7 +3467,8 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, static void handleAlwaysInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion(S, D, Attr)) + if (checkAttrMutualExclusion(S, D, Attr.getRange(), + Attr.getName())) return; if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( @@ -4014,7 +4054,8 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, static void handleCFAuditedTransferAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion(S, D, Attr)) + if (checkAttrMutualExclusion(S, D, Attr.getRange(), + Attr.getName())) return; D->addAttr(::new (S.Context) @@ -4024,7 +4065,8 @@ static void handleCFAuditedTransferAttr(Sema &S, Decl *D, static void handleCFUnknownTransferAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion(S, D, Attr)) + if (checkAttrMutualExclusion(S, D, Attr.getRange(), + Attr.getName())) return; D->addAttr(::new (S.Context) @@ -4646,6 +4688,14 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleInternalLinkageAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (InternalLinkageAttr *Internal = + S.mergeInternalLinkageAttr(D, Attr.getRange(), Attr.getName(), + Attr.getAttributeSpellingListIndex())) + D->addAttr(Internal); +} + /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. @@ -5090,6 +5140,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_OpenCLImageAccess: handleSimpleAttribute(S, D, Attr); break; + case AttributeList::AT_InternalLinkage: + handleInternalLinkageAttr(S, D, Attr); + break; // Microsoft attributes: case AttributeList::AT_MSNoVTable: -- cgit v1.2.3