diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 12 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 47 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 198 | ||||
-rw-r--r-- | lib/Sema/TargetAttributesSema.cpp | 64 | ||||
-rw-r--r-- | test/Index/complete-with-annotations.cpp | 2 | ||||
-rw-r--r-- | test/Sema/attr-visibility.c | 3 | ||||
-rw-r--r-- | test/Sema/dllimport-dllexport.c | 3 |
7 files changed, 204 insertions, 125 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0c0b3ead3b..e0ef1cf50a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1560,6 +1560,18 @@ public: TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo); bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); + + /// Attribute merging methods. Return true if a new attribute was added. + bool mergeAvailabilityAttr(Decl *D, SourceRange Range, bool Inherited, + IdentifierInfo *Platform, VersionTuple Introduced, + VersionTuple Deprecated, VersionTuple Obsoleted, + bool IsUnavailable, StringRef Message); + bool mergeVisibilityAttr(Decl *D, SourceRange Range, + bool Inherited, VisibilityAttr::VisibilityType Vis); + bool mergeDLLImportAttr(Decl *D, SourceRange Range, bool Inherited); + bool mergeDLLExportAttr(Decl *D, SourceRange Range, bool Inherited); + bool mergeDeclAttribute(Decl *New, InheritableAttr *Attr); + void mergeDeclAttributes(Decl *New, Decl *Old, bool MergeDeprecation = true); void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old, Scope *S); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index dfe73884d4..691c27cc25 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1658,6 +1658,32 @@ DeclHasAttr(const Decl *D, const Attr *A) { return false; } +bool Sema::mergeDeclAttribute(Decl *D, InheritableAttr *Attr) { + if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr)) + return mergeAvailabilityAttr(D, AA->getRange(), true, AA->getPlatform(), + AA->getIntroduced(), AA->getDeprecated(), + AA->getObsoleted(), AA->getUnavailable(), + AA->getMessage()); + + if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr)) + return mergeVisibilityAttr(D, VA->getRange(), true, VA->getVisibility()); + + if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr)) + return mergeDLLImportAttr(D, ImportA->getRange(), true); + + if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr)) + return mergeDLLExportAttr(D, ExportA->getRange(), true); + + if (!DeclHasAttr(D, Attr)) { + InheritableAttr *NewAttr = cast<InheritableAttr>(Attr->clone(Context)); + NewAttr->setInherited(true); + D->addAttr(NewAttr); + return true; + } + + return false; +} + /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. void Sema::mergeDeclAttributes(Decl *New, Decl *Old, bool MergeDeprecation) { @@ -1681,12 +1707,8 @@ void Sema::mergeDeclAttributes(Decl *New, Decl *Old, isa<AvailabilityAttr>(*i))) continue; - if (!DeclHasAttr(New, *i)) { - InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(Context)); - newAttr->setInherited(true); - New->addAttr(newAttr); + if (mergeDeclAttribute(New, *i)) foundAny = true; - } } if (!foundAny) New->dropAttrs(); @@ -5376,6 +5398,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setInvalidDecl(); } + // Handle attributes. + ProcessDeclAttributes(S, NewFD, D, + /*NonInheritable=*/false, /*Inheritable=*/true); + if (!getLangOpts().CPlusPlus) { // Perform semantic checking on the function declaration. bool isExplicitSpecialization=false; @@ -5623,14 +5649,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << D.getCXXScopeSpec().getRange(); } } - - - // Handle attributes. We need to have merged decls when handling attributes - // (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, - /*NonInheritable=*/false, /*Inheritable=*/true); // attributes declared post-definition are currently ignored // FIXME: This should happen during attribute merging @@ -8715,6 +8733,9 @@ CreateNewDecl: InFunctionDeclarator && Name) DeclsInPrototypeScope.push_back(New); + if (PrevDecl) + mergeDeclAttributes(New, PrevDecl); + OwnedDecl = true; return New; } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 223e517c1f..280e3d7fca 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1729,76 +1729,101 @@ static bool checkAvailabilityAttr(Sema &S, SourceRange Range, return false; } -static void mergeAvailabilityAttr(Sema &S, Decl *D, SourceRange Range, - IdentifierInfo *Platform, - VersionTuple Introduced, - VersionTuple Deprecated, - VersionTuple Obsoleted, - bool IsUnavailable, - StringRef Message) { - VersionTuple MergedIntroduced; - VersionTuple MergedDeprecated; - VersionTuple MergedObsoleted; +bool Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range, + bool Inherited, + IdentifierInfo *Platform, + VersionTuple Introduced, + VersionTuple Deprecated, + VersionTuple Obsoleted, + bool IsUnavailable, + StringRef Message) { + VersionTuple MergedIntroduced = Introduced; + VersionTuple MergedDeprecated = Deprecated; + VersionTuple MergedObsoleted = Obsoleted; bool FoundAny = false; - for (specific_attr_iterator<AvailabilityAttr> - i = D->specific_attr_begin<AvailabilityAttr>(), - e = D->specific_attr_end<AvailabilityAttr>(); - i != e ; ++i) { - const AvailabilityAttr *OldAA = *i; - IdentifierInfo *OldPlatform = OldAA->getPlatform(); - if (OldPlatform != Platform) - continue; - FoundAny = true; - VersionTuple OldIntroduced = OldAA->getIntroduced(); - VersionTuple OldDeprecated = OldAA->getDeprecated(); - VersionTuple OldObsoleted = OldAA->getObsoleted(); - bool OldIsUnavailable = OldAA->getUnavailable(); - StringRef OldMessage = OldAA->getMessage(); - - if ((!OldIntroduced.empty() && !Introduced.empty() && - OldIntroduced != Introduced) || - (!OldDeprecated.empty() && !Deprecated.empty() && - OldDeprecated != Deprecated) || - (!OldObsoleted.empty() && !Obsoleted.empty() && - OldObsoleted != Obsoleted) || - (OldIsUnavailable != IsUnavailable) || - (OldMessage != Message)) { - S.Diag(Range.getBegin(), diag::warn_mismatched_availability); - S.Diag(OldAA->getLocation(), diag::note_previous_attribute); - return; + if (D->hasAttrs()) { + AttrVec &Attrs = D->getAttrs(); + for (unsigned i = 0, e = Attrs.size(); i != e;) { + const AvailabilityAttr *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]); + if (!OldAA) { + ++i; + continue; + } + + IdentifierInfo *OldPlatform = OldAA->getPlatform(); + if (OldPlatform != Platform) { + ++i; + continue; + } + + FoundAny = true; + VersionTuple OldIntroduced = OldAA->getIntroduced(); + VersionTuple OldDeprecated = OldAA->getDeprecated(); + VersionTuple OldObsoleted = OldAA->getObsoleted(); + bool OldIsUnavailable = OldAA->getUnavailable(); + StringRef OldMessage = OldAA->getMessage(); + + if ((!OldIntroduced.empty() && !Introduced.empty() && + OldIntroduced != Introduced) || + (!OldDeprecated.empty() && !Deprecated.empty() && + OldDeprecated != Deprecated) || + (!OldObsoleted.empty() && !Obsoleted.empty() && + OldObsoleted != Obsoleted) || + (OldIsUnavailable != IsUnavailable) || + (OldMessage != Message)) { + Diag(OldAA->getLocation(), diag::warn_mismatched_availability); + Diag(Range.getBegin(), diag::note_previous_attribute); + Attrs.erase(Attrs.begin() + i); + --e; + continue; + } + + VersionTuple MergedIntroduced2 = MergedIntroduced; + VersionTuple MergedDeprecated2 = MergedDeprecated; + VersionTuple MergedObsoleted2 = MergedObsoleted; + + if (MergedIntroduced2.empty()) + MergedIntroduced2 = OldIntroduced; + if (MergedDeprecated2.empty()) + MergedDeprecated2 = OldDeprecated; + if (MergedObsoleted2.empty()) + MergedObsoleted2 = OldObsoleted; + + if (checkAvailabilityAttr(*this, OldAA->getRange(), Platform, + MergedIntroduced2, MergedDeprecated2, + MergedObsoleted2)) { + Attrs.erase(Attrs.begin() + i); + --e; + continue; + } + + MergedIntroduced = MergedIntroduced2; + MergedDeprecated = MergedDeprecated2; + MergedObsoleted = MergedObsoleted2; + ++i; } - if (MergedIntroduced.empty()) - MergedIntroduced = OldIntroduced; - if (MergedDeprecated.empty()) - MergedDeprecated = OldDeprecated; - if (MergedObsoleted.empty()) - MergedObsoleted = OldObsoleted; } if (FoundAny && MergedIntroduced == Introduced && MergedDeprecated == Deprecated && MergedObsoleted == Obsoleted) - return; - - if (MergedIntroduced.empty()) - MergedIntroduced = Introduced; - if (MergedDeprecated.empty()) - MergedDeprecated = Deprecated; - if (MergedObsoleted.empty()) - MergedObsoleted = Obsoleted; + return false; - if (!checkAvailabilityAttr(S, Range, Platform, MergedIntroduced, + if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, MergedDeprecated, MergedObsoleted)) { - D->addAttr(::new (S.Context) AvailabilityAttr(Range, S.Context, - Platform, - Introduced, - Deprecated, - Obsoleted, - IsUnavailable, - Message)); + AvailabilityAttr *Attr = + ::new (Context) AvailabilityAttr(Range, Context, Platform, + Introduced, Deprecated, + Obsoleted, IsUnavailable, Message); + + if (Inherited) + Attr->setInherited(true); + D->addAttr(Attr); + return true; } + return false; } static void handleAvailabilityAttr(Sema &S, Decl *D, @@ -1820,13 +1845,32 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, if (SE) Str = SE->getString(); - mergeAvailabilityAttr(S, D, Attr.getRange(), - Platform, - Introduced.Version, - Deprecated.Version, - Obsoleted.Version, - IsUnavailable, - Str); + S.mergeAvailabilityAttr(D, Attr.getRange(), + false, Platform, + Introduced.Version, + Deprecated.Version, + Obsoleted.Version, + IsUnavailable, + Str); +} + +bool Sema::mergeVisibilityAttr(Decl *D, SourceRange Range, + bool Inherited, + VisibilityAttr::VisibilityType Vis) { + VisibilityAttr *ExistingAttr = D->getAttr<VisibilityAttr>(); + if (ExistingAttr) { + VisibilityAttr::VisibilityType ExistingVis = ExistingAttr->getVisibility(); + if (ExistingVis == Vis) + return false; + Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility); + Diag(Range.getBegin(), diag::note_previous_attribute); + D->dropAttr<VisibilityAttr>(); + } + VisibilityAttr *Attr = ::new (Context) VisibilityAttr(Range, Context, Vis); + if (Inherited) + Attr->setInherited(true); + D->addAttr(Attr); + return true; } static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1867,25 +1911,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - // Find the last Decl that has an attribute. - VisibilityAttr *PrevAttr = 0; - assert(D->redecls_begin() == D); - for (Decl::redecl_iterator I = D->redecls_begin(), E = D->redecls_end(); - I != E; ++I) { - PrevAttr = I->getAttr<VisibilityAttr>() ; - if (PrevAttr) - break; - } - - if (PrevAttr) { - VisibilityAttr::VisibilityType PrevVisibility = PrevAttr->getVisibility(); - if (PrevVisibility != type) { - S.Diag(Attr.getLoc(), diag::err_mismatched_visibility); - S.Diag(PrevAttr->getLocation(), diag::note_previous_attribute); - return; - } - } - D->addAttr(::new (S.Context) VisibilityAttr(Attr.getRange(), S.Context, type)); + S.mergeVisibilityAttr(D, Attr.getRange(), false, type); } static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, @@ -3988,11 +4014,9 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, bool NonInheritable, bool Inheritable) { SmallVector<const AttributeList*, 4> attrs; for (const AttributeList* l = AttrList; l; l = l->getNext()) { + ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable); attrs.push_back(l); } - for (int i = attrs.size() - 1; i >= 0; --i) { - ProcessDeclAttribute(*this, S, D, *attrs[i], NonInheritable, Inheritable); - } // GCC accepts // static int a9 __attribute__((weakref)); diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp index c0746388e5..9ace9ad65a 100644 --- a/lib/Sema/TargetAttributesSema.cpp +++ b/lib/Sema/TargetAttributesSema.cpp @@ -151,6 +151,24 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D, S.Context)); } +bool Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, bool Inherited) { + if (D->hasAttr<DLLExportAttr>()) { + Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport"; + return false; + } + + if (D->hasAttr<DLLImportAttr>()) + return false; + + DLLImportAttr *Attr = + ::new (Context) DLLImportAttr(Range, Context); + if (Inherited) + Attr->setInherited(true); + D->addAttr(Attr); + + return true; +} + static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { @@ -159,13 +177,8 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { } // Attribute can be applied only to functions or variables. - if (isa<VarDecl>(D)) { - D->addAttr(::new (S.Context) DLLImportAttr(Attr.getLoc(), S.Context)); - return; - } - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (!FD) { + if (!FD && !isa<VarDecl>(D)) { // Apparently Visual C++ thinks it is okay to not emit a warning // in this case, so only emit a warning when -fms-extensions is not // specified. @@ -177,17 +190,30 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Currently, the dllimport attribute is ignored for inlined functions. // Warning is emitted. - if (FD->isInlineSpecified()) { + if (FD && FD->isInlineSpecified()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; return; } - if (D->getAttr<DLLExportAttr>()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; - return; + S.mergeDLLImportAttr(D, Attr.getRange(), false); +} + +bool Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, bool Inherited) { + if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) { + Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport"; + D->dropAttr<DLLImportAttr>(); } - D->addAttr(::new (S.Context) DLLImportAttr(Attr.getLoc(), S.Context)); + if (D->hasAttr<DLLExportAttr>()) + return false; + + DLLExportAttr *Attr = + ::new (Context) DLLExportAttr(Range, Context); + if (Inherited) + Attr->setInherited(true); + D->addAttr(Attr); + + return true; } static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -198,13 +224,8 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { } // Attribute can be applied only to functions or variables. - if (isa<VarDecl>(D)) { - D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context)); - return; - } - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (!FD) { + if (!FD && !isa<VarDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; @@ -212,18 +233,13 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Currently, the dllexport attribute is ignored for inlined functions, unless // the -fkeep-inline-functions flag has been used. Warning is emitted; - if (FD->isInlineSpecified()) { + if (FD && FD->isInlineSpecified()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; return; } - if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) { - S.Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport"; - D->dropAttr<DLLImportAttr>(); - } - - D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context)); + S.mergeDLLExportAttr(D, Attr.getRange(), false); } namespace { diff --git a/test/Index/complete-with-annotations.cpp b/test/Index/complete-with-annotations.cpp index 3b37e380f3..afa8d9ed66 100644 --- a/test/Index/complete-with-annotations.cpp +++ b/test/Index/complete-with-annotations.cpp @@ -14,7 +14,7 @@ void X::doSomething() { } // CHECK: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34) -// CHECK: FieldDecl:{ResultType int}{TypedText field} (35) ("one", "two", "three") +// CHECK: FieldDecl:{ResultType int}{TypedText field} (35) ("three", "two", "one") // CHECK: CXXMethod:{ResultType void}{TypedText func2}{LeftParen (}{RightParen )} (34) ("some annotation") // CHECK: FieldDecl:{ResultType int}{TypedText member2} (35) ("another annotation", "some annotation") // CHECK: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (34) diff --git a/test/Sema/attr-visibility.c b/test/Sema/attr-visibility.c index cb549921ab..cc3c54a047 100644 --- a/test/Sema/attr-visibility.c +++ b/test/Sema/attr-visibility.c @@ -17,3 +17,6 @@ struct __attribute__((visibility("default"))) test5; // expected-error {{visibil void test6() __attribute__((visibility("hidden"), // expected-note {{previous attribute is here}} visibility("default"))); // expected-error {{visibility does not match previous declaration}} + +extern int test7 __attribute__((visibility("default"))); // expected-note {{previous attribute is here}} +extern int test7 __attribute__((visibility("hidden"))); // expected-error {{visibility does not match previous declaration}} diff --git a/test/Sema/dllimport-dllexport.c b/test/Sema/dllimport-dllexport.c index 4c04902697..00c9df594b 100644 --- a/test/Sema/dllimport-dllexport.c +++ b/test/Sema/dllimport-dllexport.c @@ -38,3 +38,6 @@ void foo12(){} // expected-warning {{'foo12' redeclared without dllimport attrib void __attribute__((dllimport)) foo13(); // expected-warning{{dllimport attribute ignored}} void __attribute__((dllexport)) foo13(); + +extern int foo14 __attribute__((dllexport)); +extern int foo14 __attribute__((dllimport)); // expected-warning{{dllimport attribute ignored}} |