Check for internal weak decls after merging.
This fixes pr14946. The problem was that the linkage computation was done too
early, so things like "extern int a;" would be given external linkage, even if
a previous declaration was static.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172667 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 994b212..0316654 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4312,6 +4312,15 @@
return false;
}
+static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
+ // 'weak' only applies to declarations with external linkage.
+ WeakAttr *WA = ND.getAttr<WeakAttr>();
+ if (WA && ND.getLinkage() != ExternalLinkage) {
+ S.Diag(WA->getLocation(), diag::err_attribute_weak_static);
+ ND.dropAttr<WeakAttr>();
+ }
+}
+
NamedDecl*
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -4590,6 +4599,8 @@
NewVD->setInvalidDecl();
}
+ checkAttributesAfterMerging(*this, *NewVD);
+
// If this is a locally-scoped extern C variable, update the map of
// such variables.
if (CurContext->isFunctionOrMethod() && NewVD->isExternC() &&
@@ -6056,6 +6067,8 @@
}
}
+ checkAttributesAfterMerging(*this, *NewFD);
+
AddKnownFunctionAttributes(NewFD);
if (NewFD->hasAttr<OverloadableAttr>() &&
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 85f48ec..efeafa6 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2511,12 +2511,6 @@
NamedDecl *nd = cast<NamedDecl>(D);
- // 'weak' only applies to declarations with external linkage.
- if (hasEffectivelyInternalLinkage(nd)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_weak_static);
- return;
- }
-
nd->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
}
diff --git a/test/Sema/attr-weak.c b/test/Sema/attr-weak.c
index adedf12..df74554 100644
--- a/test/Sema/attr-weak.c
+++ b/test/Sema/attr-weak.c
@@ -16,3 +16,9 @@
// rdar://9538608
int C; // expected-note {{previous definition is here}}
extern int C __attribute__((weak_import)); // expected-warning {{an already-declared variable is made a weak_import declaration}}
+
+static int pr14946_x;
+extern int pr14946_x __attribute__((weak)); // expected-error {{weak declaration cannot have internal linkage}}
+
+static void pr14946_f();
+void pr14946_f() __attribute__((weak)); // expected-error {{weak declaration cannot have internal linkage}}
diff --git a/test/SemaCXX/attr-weak.cpp b/test/SemaCXX/attr-weak.cpp
index b6a9e0a..8939a28 100644
--- a/test/SemaCXX/attr-weak.cpp
+++ b/test/SemaCXX/attr-weak.cpp
@@ -21,9 +21,16 @@
};
}
+// GCC rejects the instantiation with the internal type, but some existing
+// code expects it. It is also not that different from giving hidden visibility
+// to parts of a template that have explicit default visibility, so we accept
+// this.
template <class T> struct Test7 {
void test7() __attribute__((weak)) {}
+ static int var __attribute__((weak));
};
+template <class T>
+int Test7<T>::var;
namespace { class Internal; }
template struct Test7<Internal>;
template struct Test7<int>;