PR37631: verify that a member deduction guide has the same access as its template.

llvm-svn: 333599
This commit is contained in:
Richard Smith 2018-05-30 22:13:43 +00:00
parent e863297775
commit e4899c1648
3 changed files with 54 additions and 7 deletions

View File

@ -2115,9 +2115,16 @@ def err_deduction_guide_explicit_mismatch : Error<
def err_deduction_guide_specialized : Error<"deduction guide cannot be "
"%select{explicitly instantiated|explicitly specialized}0">;
def err_deduction_guide_template_not_deducible : Error<
"deduction guide template contains "
"%select{a template parameter|template parameters}0 that cannot be "
"deduced">;
"deduction guide template contains "
"%select{a template parameter|template parameters}0 that cannot be "
"deduced">;
def err_deduction_guide_wrong_access : Error<
"deduction guide has different access from the corresponding "
"member template">;
def note_deduction_guide_template_access : Note<
"member template declared %0 here">;
def note_deduction_guide_access : Note<
"deduction guide declared %0 by intervening access specifier">;
// C++1y deduced return types
def err_auto_fn_deduction_failure : Error<

View File

@ -3103,14 +3103,38 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Member->setInvalidDecl();
}
NamedDecl *NonTemplateMember = Member;
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member))
NonTemplateMember = FunTmpl->getTemplatedDecl();
else if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(Member))
NonTemplateMember = VarTmpl->getTemplatedDecl();
Member->setAccess(AS);
// If we have declared a member function template or static data member
// template, set the access of the templated declaration as well.
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member))
FunTmpl->getTemplatedDecl()->setAccess(AS);
else if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(Member))
VarTmpl->getTemplatedDecl()->setAccess(AS);
if (NonTemplateMember != Member)
NonTemplateMember->setAccess(AS);
// C++ [temp.deduct.guide]p3:
// A deduction guide [...] for a member class template [shall be
// declared] with the same access [as the template].
if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(NonTemplateMember)) {
auto *TD = DG->getDeducedTemplate();
if (AS != TD->getAccess()) {
Diag(DG->getLocStart(), diag::err_deduction_guide_wrong_access);
Diag(TD->getLocStart(), diag::note_deduction_guide_template_access)
<< TD->getAccess();
const AccessSpecDecl *LastAccessSpec = nullptr;
for (const auto *D : cast<CXXRecordDecl>(CurContext)->decls()) {
if (const auto *AccessSpec = dyn_cast<AccessSpecDecl>(D))
LastAccessSpec = AccessSpec;
}
assert(LastAccessSpec && "differing access with no access specifier");
Diag(LastAccessSpec->getLocStart(), diag::note_deduction_guide_access)
<< AS;
}
}
}
if (VS.isOverrideSpecified())

View File

@ -330,6 +330,22 @@ namespace member_guides {
Bar(int) -> Bar<int>;
};
Foo<int>::Bar b = 0;
struct A {
template<typename T> struct Public; // expected-note {{declared public}}
Public(float) -> Public<float>;
protected: // expected-note {{declared protected by intervening access specifier}}
template<typename T> struct Protected; // expected-note 2{{declared protected}}
Protected(float) -> Protected<float>;
Public(int) -> Public<int>; // expected-error {{different access}}
private: // expected-note {{declared private by intervening access specifier}}
template<typename T> struct Private; // expected-note {{declared private}}
Protected(int) -> Protected<int>; // expected-error {{different access}}
public: // expected-note 2{{declared public by intervening access specifier}}
template<typename T> Public(T) -> Public<T>;
template<typename T> Protected(T) -> Protected<T>; // expected-error {{different access}}
template<typename T> Private(T) -> Private<T>; // expected-error {{different access}}
};
}
#else