Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit d4bb5a2

Browse files
committed
[c++1z] Enforce restriction that deduction guide is declared in the same scope as its template.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@294778 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent a0274b7 commit d4bb5a2

File tree

5 files changed

+58
-22
lines changed

5 files changed

+58
-22
lines changed

include/clang/Basic/DiagnosticSemaKinds.td

+2
Original file line numberDiff line numberDiff line change
@@ -1993,6 +1993,8 @@ def err_deduction_guide_name_not_class_template : Error<
19931993
"cannot specify deduction guide for "
19941994
"%select{<error>|function template|variable template|alias template|"
19951995
"template template parameter|dependent template name}0 %1">;
1996+
def err_deduction_guide_wrong_scope : Error<
1997+
"deduction guide must be declared in the same scope as template %q0">;
19961998
def err_deduction_guide_defines_function : Error<
19971999
"deduction guide cannot have a function definition">;
19982000
def err_deduction_guide_explicit_mismatch : Error<

include/clang/Sema/Sema.h

+1-11
Original file line numberDiff line numberDiff line change
@@ -5831,17 +5831,7 @@ class Sema {
58315831
/// deduction-guide declaration.
58325832
bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
58335833
SourceLocation NameLoc,
5834-
ParsedTemplateTy *Template = nullptr) {
5835-
CXXScopeSpec SS;
5836-
UnqualifiedId Id;
5837-
Id.setIdentifier(&Name, NameLoc);
5838-
TemplateTy TemplateFallback;
5839-
bool MemberOfUnknownSpecialization;
5840-
// FIXME: Use redeclaration lookup!
5841-
return isTemplateName(S, SS, false, Id, ParsedType(), false,
5842-
Template ? *Template : TemplateFallback,
5843-
MemberOfUnknownSpecialization) == TNK_Type_template;
5844-
}
5834+
ParsedTemplateTy *Template = nullptr);
58455835

58465836
bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
58475837
SourceLocation IILoc,

lib/Sema/SemaDeclCXX.cpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -8137,6 +8137,20 @@ struct BadSpecifierDiagnoser {
81378137
/// grammar.
81388138
void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
81398139
StorageClass &SC) {
8140+
TemplateName GuidedTemplate = D.getName().TemplateName.get().get();
8141+
TemplateDecl *GuidedTemplateDecl = GuidedTemplate.getAsTemplateDecl();
8142+
assert(GuidedTemplateDecl && "missing template decl for deduction guide");
8143+
8144+
// C++ [temp.deduct.guide]p3:
8145+
// A deduction-gide shall be declared in the same scope as the
8146+
// corresponding class template.
8147+
if (!CurContext->getRedeclContext()->Equals(
8148+
GuidedTemplateDecl->getDeclContext()->getRedeclContext())) {
8149+
Diag(D.getIdentifierLoc(), diag::err_deduction_guide_wrong_scope)
8150+
<< GuidedTemplateDecl;
8151+
Diag(GuidedTemplateDecl->getLocation(), diag::note_template_decl_here);
8152+
}
8153+
81408154
auto &DS = D.getMutableDeclSpec();
81418155
// We leave 'friend' and 'virtual' to be rejected in the normal way.
81428156
if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() ||
@@ -8196,7 +8210,6 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
81968210
// Check that the return type is written as a specialization of
81978211
// the template specified as the deduction-guide's name.
81988212
ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType();
8199-
TemplateName GuidedTemplate = D.getName().TemplateName.get().get();
82008213
TypeSourceInfo *TSI = nullptr;
82018214
QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI);
82028215
assert(TSI && "deduction guide has valid type but invalid return type?");

lib/Sema/SemaTemplate.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,37 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
242242
return TemplateKind;
243243
}
244244

245+
bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
246+
SourceLocation NameLoc,
247+
ParsedTemplateTy *Template) {
248+
CXXScopeSpec SS;
249+
bool MemberOfUnknownSpecialization = false;
250+
251+
// We could use redeclaration lookup here, but we don't need to: the
252+
// syntactic form of a deduction guide is enough to identify it even
253+
// if we can't look up the template name at all.
254+
LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName);
255+
LookupTemplateName(R, S, SS, /*ObjectType*/QualType(),
256+
/*EnteringContext*/false, MemberOfUnknownSpecialization);
257+
258+
if (R.empty()) return false;
259+
if (R.isAmbiguous()) {
260+
// FIXME: Diagnose an ambiguity if we find at least one template.
261+
R.suppressDiagnostics();
262+
return false;
263+
}
264+
265+
// We only treat template-names that name type templates as valid deduction
266+
// guide names.
267+
TemplateDecl *TD = R.getAsSingle<TemplateDecl>();
268+
if (!TD || !getAsTypeTemplateDecl(TD))
269+
return false;
270+
271+
if (Template)
272+
*Template = TemplateTy::make(TemplateName(TD));
273+
return true;
274+
}
275+
245276
bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
246277
SourceLocation IILoc,
247278
Scope *S,

test/CXX/temp/temp.deduct.guide/p3.cpp

+10-10
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,28 @@ template<typename T> A(T*) -> const A<T>; // expected-error {{deduced type 'cons
4040
// class template.
4141
namespace WrongScope {
4242
namespace {
43-
template<typename T> struct AnonNS1 {};
43+
template<typename T> struct AnonNS1 {}; // expected-note {{here}}
4444
AnonNS1(float) -> AnonNS1<float>; // ok
4545
}
46-
AnonNS1(int) -> AnonNS1<int>; // FIXME
47-
template<typename T> struct AnonNS2 {};
46+
AnonNS1(int) -> AnonNS1<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::}}
47+
template<typename T> struct AnonNS2 {}; // expected-note {{here}}
4848
namespace {
4949
AnonNS1(char) -> AnonNS1<char>; // ok
50-
AnonNS2(int) -> AnonNS2<int>; // FIXME
50+
AnonNS2(int) -> AnonNS2<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::AnonNS2'}}
5151
}
5252
namespace N {
53-
template<typename T> struct NamedNS1 {};
54-
template<typename T> struct NamedNS2 {};
53+
template<typename T> struct NamedNS1 {}; // expected-note {{here}}
54+
template<typename T> struct NamedNS2 {}; // expected-note {{here}}
5555
}
5656
using N::NamedNS1;
57-
NamedNS1(int) -> NamedNS1<int>; // FIXME
57+
NamedNS1(int) -> NamedNS1<int>; // expected-error {{deduction guide must be declared in the same scope as template}}
5858
using namespace N;
59-
NamedNS2(int) -> NamedNS2<int>; // FIXME
59+
NamedNS2(int) -> NamedNS2<int>; // expected-error {{deduction guide must be declared in the same scope as template}}
6060
struct ClassMemberA {
61-
template<typename T> struct X {};
61+
template<typename T> struct X {}; // expected-note {{here}}
6262
};
6363
struct ClassMemberB : ClassMemberA {
64-
X(int) -> X<int>; // FIXME
64+
X(int) -> X<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::ClassMemberA::X'}}
6565
};
6666
template<typename T> struct Local {};
6767
void f() {

0 commit comments

Comments
 (0)