forked from OSchip/llvm-project
PR46729: Reject explicit and partial specializations with C linkage.
This commit is contained in:
parent
111a02decd
commit
a648834313
|
@ -6994,19 +6994,18 @@ NamedDecl *Sema::ActOnVariableDeclarator(
|
|||
TemplateParams->getRAngleLoc());
|
||||
TemplateParams = nullptr;
|
||||
} else {
|
||||
// Check that we can declare a template here.
|
||||
if (CheckTemplateDeclScope(S, TemplateParams))
|
||||
return nullptr;
|
||||
|
||||
if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
|
||||
// This is an explicit specialization or a partial specialization.
|
||||
// FIXME: Check that we can declare a specialization here.
|
||||
IsVariableTemplateSpecialization = true;
|
||||
IsPartialSpecialization = TemplateParams->size() > 0;
|
||||
} else { // if (TemplateParams->size() > 0)
|
||||
// This is a template declaration.
|
||||
IsVariableTemplate = true;
|
||||
|
||||
// Check that we can declare a template here.
|
||||
if (CheckTemplateDeclScope(S, TemplateParams))
|
||||
return nullptr;
|
||||
|
||||
// Only C++1y supports variable templates (N3651).
|
||||
Diag(D.getIdentifierLoc(),
|
||||
getLangOpts().CPlusPlus14
|
||||
|
@ -7015,6 +7014,10 @@ NamedDecl *Sema::ActOnVariableDeclarator(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// Check that we can declare a member specialization here.
|
||||
if (!TemplateParamLists.empty() && IsMemberSpecialization &&
|
||||
CheckTemplateDeclScope(S, TemplateParamLists.back()))
|
||||
return nullptr;
|
||||
assert((Invalid ||
|
||||
D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) &&
|
||||
"should have a 'template<>' for this decl");
|
||||
|
@ -8941,13 +8944,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
TemplateParamLists, isFriend, isMemberSpecialization,
|
||||
Invalid);
|
||||
if (TemplateParams) {
|
||||
// Check that we can declare a template here.
|
||||
if (CheckTemplateDeclScope(S, TemplateParams))
|
||||
NewFD->setInvalidDecl();
|
||||
|
||||
if (TemplateParams->size() > 0) {
|
||||
// This is a function template
|
||||
|
||||
// Check that we can declare a template here.
|
||||
if (CheckTemplateDeclScope(S, TemplateParams))
|
||||
NewFD->setInvalidDecl();
|
||||
|
||||
// A destructor cannot be a template.
|
||||
if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
|
||||
Diag(NewFD->getLocation(), diag::err_destructor_template);
|
||||
|
@ -9006,6 +9009,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// Check that we can declare a template here.
|
||||
if (!TemplateParamLists.empty() && isMemberSpecialization &&
|
||||
CheckTemplateDeclScope(S, TemplateParamLists.back()))
|
||||
NewFD->setInvalidDecl();
|
||||
|
||||
// All template param lists were matched against the scope specifier:
|
||||
// this is NOT (an explicit specialization of) a template.
|
||||
if (TemplateParamLists.size() > 0)
|
||||
|
@ -15301,6 +15309,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
isMemberSpecialization = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TemplateParameterLists.empty() && isMemberSpecialization &&
|
||||
CheckTemplateDeclScope(S, TemplateParameterLists.back()))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Figure out the underlying type if this a enum declaration. We need to do
|
||||
|
@ -17300,7 +17312,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
|
|||
CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record);
|
||||
CheckForZeroSize =
|
||||
CXXRecord->getLexicalDeclContext()->isExternCContext() &&
|
||||
!CXXRecord->isDependentType() &&
|
||||
!CXXRecord->isDependentType() && !inTemplateInstantiation() &&
|
||||
CXXRecord->isCLike();
|
||||
}
|
||||
if (CheckForZeroSize) {
|
||||
|
|
|
@ -7771,8 +7771,9 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
|
|||
(S->getFlags() & Scope::TemplateParamScope) != 0)
|
||||
S = S->getParent();
|
||||
|
||||
// C++ [temp]p4:
|
||||
// A template [...] shall not have C linkage.
|
||||
// C++ [temp.pre]p6: [P2096]
|
||||
// A template, explicit specialization, or partial specialization shall not
|
||||
// have C linkage.
|
||||
DeclContext *Ctx = S->getEntity();
|
||||
if (Ctx && Ctx->isExternCContext()) {
|
||||
Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
|
||||
|
@ -7786,6 +7787,12 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
|
|||
// C++ [temp]p2:
|
||||
// A template-declaration can appear only as a namespace scope or
|
||||
// class scope declaration.
|
||||
// C++ [temp.expl.spec]p3:
|
||||
// An explicit specialization may be declared in any scope in which the
|
||||
// corresponding primary template may be defined.
|
||||
// C++ [temp.class.spec]p6: [P2096]
|
||||
// A partial specialization may be declared in any scope in which the
|
||||
// corresponding primary template may be defined.
|
||||
if (Ctx) {
|
||||
if (Ctx->isFileContext())
|
||||
return false;
|
||||
|
@ -8105,6 +8112,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
|
|||
if (Invalid)
|
||||
return true;
|
||||
|
||||
// Check that we can declare a template specialization here.
|
||||
if (TemplateParams && CheckTemplateDeclScope(S, TemplateParams))
|
||||
return true;
|
||||
|
||||
if (TemplateParams && TemplateParams->size() > 0) {
|
||||
isPartialSpecialization = true;
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
// RUN: %clang_cc1 -std=c++20 -verify %s
|
||||
|
||||
// Templates and partial and explicit specializations can't have C linkage.
|
||||
namespace extern_c_templates {
|
||||
|
||||
template<typename T> struct A {
|
||||
static int a;
|
||||
struct b;
|
||||
void c();
|
||||
enum class d;
|
||||
|
||||
template<typename U> static int e;
|
||||
template<typename U> struct f;
|
||||
template<typename U> void g();
|
||||
};
|
||||
|
||||
template<typename T> int B;
|
||||
template<typename T> void C();
|
||||
|
||||
extern "C" { // expected-note 1+{{begins here}}
|
||||
// templates
|
||||
template<typename T> struct A; // expected-error {{templates must have C++ linkage}}
|
||||
template<typename T> int B; // expected-error {{templates must have C++ linkage}}
|
||||
template<typename T> void C(); // expected-error {{templates must have C++ linkage}}
|
||||
|
||||
// non-template members of a template
|
||||
// FIXME: Should these really be valid?
|
||||
template<typename T> int A<T>::a;
|
||||
template<typename T> struct A<T>::b {};
|
||||
template<typename T> void A<T>::c() {}
|
||||
template<typename T> enum class A<T>::d {};
|
||||
|
||||
// templates
|
||||
template<typename T> template<typename U> int A<T>::e; // expected-error {{templates must have C++ linkage}}
|
||||
template<typename T> template<typename U> struct A<T>::f {}; // expected-error {{templates must have C++ linkage}}
|
||||
template<typename T> template<typename U> void A<T>::g() {} // expected-error {{templates must have C++ linkage}}
|
||||
|
||||
// partial specializations
|
||||
template<typename T> struct A<int*>; // expected-error {{templates must have C++ linkage}}
|
||||
template<typename T> int B<int*>; // expected-error {{templates must have C++ linkage}}
|
||||
template<typename T> template<typename U> int A<T>::e<U*>; // expected-error {{templates must have C++ linkage}}
|
||||
template<typename T> template<typename U> struct A<T>::f<U*> {}; // expected-error {{templates must have C++ linkage}}
|
||||
|
||||
// explicit specializations of templates
|
||||
template<> struct A<char> {}; // expected-error {{templates must have C++ linkage}}
|
||||
template<> int B<char>; // expected-error {{templates must have C++ linkage}}
|
||||
template<> void C<char>() {} // expected-error {{templates must have C++ linkage}}
|
||||
|
||||
// explicit specializations of members of a template
|
||||
template<> int A<int>::a; // expected-error {{templates must have C++ linkage}}
|
||||
template<> struct A<int>::b {}; // expected-error {{templates must have C++ linkage}}
|
||||
template<> void A<int>::c() {} // expected-error {{templates must have C++ linkage}}
|
||||
template<> enum class A<int>::d {}; // expected-error {{templates must have C++ linkage}}
|
||||
|
||||
// explicit specializations of member templates
|
||||
template<> template<typename U> int A<int>::e; // expected-error {{templates must have C++ linkage}}
|
||||
template<> template<typename U> struct A<int>::f {}; // expected-error {{templates must have C++ linkage}}
|
||||
template<> template<typename U> void A<int>::g() {} // expected-error {{templates must have C++ linkage}}
|
||||
}
|
||||
|
||||
// Provide valid definitions for the explicit instantiations below.
|
||||
// FIXME: Our recovery from the invalid definitions above isn't very good.
|
||||
template<typename T> template<typename U> int A<T>::e;
|
||||
template<typename T> template<typename U> struct A<T>::f {};
|
||||
template<typename T> template<typename U> void A<T>::g() {}
|
||||
|
||||
extern "C" {
|
||||
// explicit instantiations
|
||||
// FIXME: Should these really be valid?
|
||||
template struct A<double>;
|
||||
template int A<float>::a;
|
||||
template struct A<float>::b;
|
||||
template void A<float>::c();
|
||||
template int A<float>::e<float>;
|
||||
template struct A<float>::f<float>;
|
||||
template void A<float>::g<float>();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,26 @@
|
|||
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
|
||||
|
||||
template<typename T> class A;
|
||||
template<typename T> class A {};
|
||||
|
||||
extern "C++" {
|
||||
template<typename T> class B;
|
||||
template<typename T> class B {};
|
||||
template<typename T> class A<T *>;
|
||||
template<> class A<int[1]>;
|
||||
template class A<int[2]>;
|
||||
template<typename T> class B<T *>;
|
||||
template<> class B<int[1]>;
|
||||
template class B<int[2]>;
|
||||
}
|
||||
|
||||
namespace N {
|
||||
template<typename T> class C;
|
||||
}
|
||||
|
||||
extern "C" { // expected-note {{extern "C" language linkage specification begins here}}
|
||||
extern "C" { // expected-note 3 {{extern "C" language linkage specification begins here}}
|
||||
template<typename T> class D; // expected-error{{templates must have C++ linkage}}
|
||||
template<typename T> class A<T **>; // expected-error{{templates must have C++ linkage}}
|
||||
template<> class A<int[3]>; // expected-error{{templates must have C++ linkage}}
|
||||
template class A<int[4]>; // OK (surprisingly) FIXME: Should we warn on this?
|
||||
}
|
||||
|
||||
extern "C" { // expected-note 2 {{extern "C" language linkage specification begins here}}
|
||||
|
|
Loading…
Reference in New Issue