summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2012-05-10 02:50:16 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2012-05-10 02:50:16 +0000
commitc67f223c9ee4cbfa478a1d6e9cfe5b03c524b4fa (patch)
treef663bdb4be2998a02f90d5d6a9c8a5891334f75e /clang/lib/Sema
parent62cce9e47d2cb1f3068cd7346bdedb0ce4c7c24d (diff)
downloadbcm5719-llvm-c67f223c9ee4cbfa478a1d6e9cfe5b03c524b4fa.tar.gz
bcm5719-llvm-c67f223c9ee4cbfa478a1d6e9cfe5b03c524b4fa.zip
Fix an old (2009) FIXME:
// FIXME: This needs to happen before we merge declarations. Then, // let attribute merging cope with attribute conflicts. This was already being done for variables, but for functions we were merging then first and then applying the attributes. To avoid duplicating merging logic, some of the helpers in SemaDeclAttr.cpp become methods that can handle merging two attributes in one decl or inheriting attributes from one decl to another. With this change we are now able to produce errors for variables with incompatible visibility attributes or warn about unused dllimports in variables. This changes the attribute list iteration back to being in reverse source code order, as that matches what decl merging does and avoids differentiating the two cases is the merge*Attr methods. llvm-svn: 156531
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp47
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp198
-rw-r--r--clang/lib/Sema/TargetAttributesSema.cpp64
3 files changed, 185 insertions, 124 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index dfe73884d46..691c27cc259 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/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/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 223e517c1ff..280e3d7fca4 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/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/clang/lib/Sema/TargetAttributesSema.cpp b/clang/lib/Sema/TargetAttributesSema.cpp
index c0746388e59..9ace9ad65ac 100644
--- a/clang/lib/Sema/TargetAttributesSema.cpp
+++ b/clang/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 {
OpenPOWER on IntegriCloud