summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
authorErich Keane <erich.keane@intel.com>2018-11-28 20:58:43 +0000
committerErich Keane <erich.keane@intel.com>2018-11-28 20:58:43 +0000
commit7304f0a66eef2951441af1f77aab3baf453825fe (patch)
tree5db4bb5653e5a4f6bad9c9fff4a1730255f7ea10 /clang/lib/Sema/SemaDecl.cpp
parent83db1d219ec154758c3b1209f2696b6c088fa2b0 (diff)
downloadbcm5719-llvm-7304f0a66eef2951441af1f77aab3baf453825fe.tar.gz
bcm5719-llvm-7304f0a66eef2951441af1f77aab3baf453825fe.zip
Correct 'target' default behavior on redecl, allow forward declaration.
Declarations without the attribute were disallowed because it would be ambiguous which 'target' it was supposed to be on. For example: void ___attribute__((target("v1"))) foo(); void foo(); // Redecl of above, or fwd decl of below? void ___attribute__((target("v2"))) foo(); However, a first declaration doesn't have that problem, and erroring prevents it from working in cases where the forward declaration is useful. Additionally, a forward declaration of target==default wouldn't properly cause multiversioning, so this patch fixes that. The patch was not split since the 'default' fix would require implementing the same check for that case, followed by undoing the same change for the fwd-decl implementation. Change-Id: I66f2c5bc2477bcd3f7544b9c16c83ece257077b0 llvm-svn: 347805
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp52
1 files changed, 47 insertions, 5 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e34741608b2..8ccd9ae322b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9404,6 +9404,27 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
return false;
}
+static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
+ MultiVersionKind MVType) {
+ for (const Attr *A : FD->attrs()) {
+ switch (A->getKind()) {
+ case attr::CPUDispatch:
+ case attr::CPUSpecific:
+ if (MVType != MultiVersionKind::CPUDispatch &&
+ MVType != MultiVersionKind::CPUSpecific)
+ return true;
+ break;
+ case attr::Target:
+ if (MVType != MultiVersionKind::Target)
+ return true;
+ break;
+ default:
+ return true;
+ }
+ }
+ return false;
+}
+
static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
const FunctionDecl *NewFD,
bool CausesMV,
@@ -9449,15 +9470,14 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
// For now, disallow all other attributes. These should be opt-in, but
// an analysis of all of them is a future FIXME.
- if (CausesMV && OldFD &&
- std::distance(OldFD->attr_begin(), OldFD->attr_end()) != 1) {
+ if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) {
S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs)
<< IsCPUSpecificCPUDispatchMVType;
S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
return true;
}
- if (std::distance(NewFD->attr_begin(), NewFD->attr_end()) != 1)
+ if (HasNonMultiVersionAttributes(NewFD, MVType))
return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs)
<< IsCPUSpecificCPUDispatchMVType;
@@ -9581,6 +9601,15 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD,
return false;
}
+static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) {
+ for (const Decl *D = FD->getPreviousDecl(); D; D = D->getPreviousDecl()) {
+ if (D->getAsFunction()->getMultiVersionKind() != MultiVersionKind::None)
+ return true;
+ }
+
+ return false;
+}
+
static bool CheckTargetCausesMultiVersioning(
Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, const TargetAttr *NewTA,
bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious,
@@ -9592,7 +9621,8 @@ static bool CheckTargetCausesMultiVersioning(
// If the old decl is NOT MultiVersioned yet, and we don't cause that
// to change, this is a simple redeclaration.
- if (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())
+ if (!NewTA->isDefaultVersion() &&
+ (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()))
return false;
// Otherwise, this decl causes MultiVersioning.
@@ -9614,6 +9644,15 @@ static bool CheckTargetCausesMultiVersioning(
return true;
}
+ // If this is 'default', permit the forward declaration.
+ if (!OldFD->isMultiVersion() && !OldTA && NewTA->isDefaultVersion()) {
+ Redeclaration = true;
+ OldDecl = OldFD;
+ OldFD->setIsMultiVersion();
+ NewFD->setIsMultiVersion();
+ return false;
+ }
+
if (CheckMultiVersionValue(S, OldFD)) {
S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
NewFD->setInvalidDecl();
@@ -9632,7 +9671,10 @@ static bool CheckTargetCausesMultiVersioning(
for (const auto *FD : OldFD->redecls()) {
const auto *CurTA = FD->getAttr<TargetAttr>();
- if (!CurTA || CurTA->isInherited()) {
+ // We allow forward declarations before ANY multiversioning attributes, but
+ // nothing after the fact.
+ if (PreviousDeclsHaveMultiVersionAttribute(FD) &&
+ (!CurTA || CurTA->isInherited())) {
S.Diag(FD->getLocation(), diag::err_multiversion_required_in_redecl)
<< 0;
S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
OpenPOWER on IntegriCloud