summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/SemaTemplate.cpp66
-rw-r--r--test/CXX/drs/dr0xx.cpp7
-rw-r--r--test/SemaCXX/PR10177.cpp3
-rw-r--r--test/SemaCXX/libcxx_valarray_hack.cpp32
5 files changed, 84 insertions, 26 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 238c9eec70..059183dbaf 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4384,6 +4384,8 @@ def err_explicit_instantiation_of_typedef : Error<
"explicit instantiation of typedef %0">;
def err_explicit_instantiation_storage_class : Error<
"explicit instantiation cannot have a storage class">;
+def err_explicit_instantiation_internal_linkage : Error<
+ "explicit instantiation declaration of %0 with internal linkage">;
def err_explicit_instantiation_not_known : Error<
"explicit instantiation of %0 does not refer to a function template, "
"variable template, member function, member class, or static data member">;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 1010370838..973911eb84 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -8619,6 +8619,29 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
return false;
}
+/// Common checks for whether an explicit instantiation of \p D is valid.
+static bool CheckExplicitInstantiation(Sema &S, NamedDecl *D,
+ SourceLocation InstLoc,
+ bool WasQualifiedName,
+ TemplateSpecializationKind TSK) {
+ // C++ [temp.explicit]p13:
+ // An explicit instantiation declaration shall not name a specialization of
+ // a template with internal linkage.
+ if (TSK == TSK_ExplicitInstantiationDeclaration &&
+ D->getFormalLinkage() == InternalLinkage) {
+ S.Diag(InstLoc, diag::err_explicit_instantiation_internal_linkage) << D;
+ return true;
+ }
+
+ // C++11 [temp.explicit]p3: [DR 275]
+ // An explicit instantiation shall appear in an enclosing namespace of its
+ // template.
+ if (CheckExplicitInstantiationScope(S, D, InstLoc, WasQualifiedName))
+ return true;
+
+ return false;
+}
+
/// Determine whether the given scope specifier has a template-id in it.
static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
if (!SS.isSet())
@@ -8770,13 +8793,8 @@ DeclResult Sema::ActOnExplicitInstantiation(
TemplateSpecializationKind PrevDecl_TSK
= PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
- // C++0x [temp.explicit]p2:
- // [...] An explicit instantiation shall appear in an enclosing
- // namespace of its template. [...]
- //
- // This is C++ DR 275.
- if (CheckExplicitInstantiationScope(*this, ClassTemplate, TemplateNameLoc,
- SS.isSet()))
+ if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc,
+ SS.isSet(), TSK))
return true;
ClassTemplateSpecializationDecl *Specialization = nullptr;
@@ -8999,12 +9017,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc,
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
- // C++0x [temp.explicit]p2:
- // [...] An explicit instantiation shall appear in an enclosing
- // namespace of its template. [...]
- //
- // This is C++ DR 275.
- CheckExplicitInstantiationScope(*this, Record, NameLoc, true);
+ CheckExplicitInstantiation(*this, Record, NameLoc, true, TSK);
// Verify that it is okay to explicitly instantiate here.
CXXRecordDecl *PrevDecl
@@ -9235,8 +9248,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::ext_explicit_instantiation_without_qualified_id)
<< Prev << D.getCXXScopeSpec().getRange();
- // Check the scope of this explicit instantiation.
- CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
+ CheckExplicitInstantiation(*this, Prev, D.getIdentifierLoc(), true, TSK);
// Verify that it is okay to explicitly instantiate here.
TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind();
@@ -9411,6 +9423,20 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return (Decl*) nullptr;
}
+ // HACK: libc++ has a bug where it attempts to explicitly instantiate the
+ // functions
+ // valarray<size_t>::valarray(size_t) and
+ // valarray<size_t>::~valarray()
+ // that it declared to have internal linkage with the internal_linkage
+ // attribute. Ignore the explicit instantiation declaration in this case.
+ if (Specialization->hasAttr<InternalLinkageAttr>() &&
+ TSK == TSK_ExplicitInstantiationDeclaration) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(Specialization->getDeclContext()))
+ if (RD->getIdentifier() && RD->getIdentifier()->isStr("valarray") &&
+ RD->isInStdNamespace())
+ return (Decl*) nullptr;
+ }
+
ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes());
// In MSVC mode, dllimported explicit instantiation definitions are treated as
@@ -9444,11 +9470,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::ext_explicit_instantiation_without_qualified_id)
<< Specialization << D.getCXXScopeSpec().getRange();
- CheckExplicitInstantiationScope(*this,
- FunTmpl? (NamedDecl *)FunTmpl
- : Specialization->getInstantiatedFromMemberFunction(),
- D.getIdentifierLoc(),
- D.getCXXScopeSpec().isSet());
+ CheckExplicitInstantiation(
+ *this,
+ FunTmpl ? (NamedDecl *)FunTmpl
+ : Specialization->getInstantiatedFromMemberFunction(),
+ D.getIdentifierLoc(), D.getCXXScopeSpec().isSet(), TSK);
// FIXME: Create some kind of ExplicitInstantiationDecl here.
return (Decl*) nullptr;
diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp
index 911aab1747..53bd6f3f05 100644
--- a/test/CXX/drs/dr0xx.cpp
+++ b/test/CXX/drs/dr0xx.cpp
@@ -869,18 +869,17 @@ namespace dr68 { // dr68: yes
}
namespace dr69 { // dr69: yes
- template<typename T> static void f() {}
+ template<typename T> static void f() {} // #dr69-f
// FIXME: Should we warn here?
inline void g() { f<int>(); }
- // FIXME: This should be rejected, per [temp.explicit]p11.
- extern template void f<char>();
+ extern template void f<char>(); // expected-error {{explicit instantiation declaration of 'f' with internal linkage}}
#if __cplusplus < 201103L
// expected-error@-2 {{C++11 extension}}
#endif
template<void(*)()> struct Q {};
Q<&f<int> > q;
#if __cplusplus < 201103L
- // expected-error@-2 {{internal linkage}} expected-note@-11 {{here}}
+ // expected-error@-2 {{internal linkage}} expected-note@#dr69-f {{here}}
#endif
}
diff --git a/test/SemaCXX/PR10177.cpp b/test/SemaCXX/PR10177.cpp
index 59630be508..0d2e792f52 100644
--- a/test/SemaCXX/PR10177.cpp
+++ b/test/SemaCXX/PR10177.cpp
@@ -57,11 +57,10 @@ namespace N {
}
#else
-// expected-no-diagnostics
namespace { template<typename> extern int n; }
template<typename T> int g() { return n<int>; }
-namespace { extern template int n<int>; }
+namespace { extern template int n<int>; } // expected-error {{explicit instantiation declaration of 'n<int>' with internal linkage}}
#endif
diff --git a/test/SemaCXX/libcxx_valarray_hack.cpp b/test/SemaCXX/libcxx_valarray_hack.cpp
new file mode 100644
index 0000000000..03dc573129
--- /dev/null
+++ b/test/SemaCXX/libcxx_valarray_hack.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify
+
+// This is a test for a hack in Clang that works around an issue with libc++'s
+// <valarray> implementation. The <valarray> header contains explicit
+// instantiations of functions that it declared with the internal_linkage
+// attribute, which are ill-formed by [temp.explicit]p13 (and meaningless).
+
+#ifdef BE_THE_HEADER
+
+#pragma GCC system_header
+namespace std {
+ using size_t = __SIZE_TYPE__;
+ template<typename T> struct valarray {
+ __attribute__((internal_linkage)) valarray(size_t) {}
+ __attribute__((internal_linkage)) ~valarray() {}
+ };
+
+ extern template valarray<size_t>::valarray(size_t);
+ extern template valarray<size_t>::~valarray();
+}
+
+#else
+
+#define BE_THE_HEADER
+#include "libcxx_valarray_hack.cpp"
+
+template<typename T> struct foo {
+ __attribute__((internal_linkage)) void x() {};
+};
+extern template void foo<int>::x(); // expected-error {{explicit instantiation declaration of 'x' with internal linkage}}
+
+#endif