aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard@metafoo.co.uk>2021-05-19 13:31:13 -0700
committerRichard Smith <richard@metafoo.co.uk>2021-05-19 13:31:53 -0700
commitd38057f3ecb080e0ae4aba367a737226221327f2 (patch)
tree635172ededbba014be7af30928e08bcdeb67ab42
parent1dfa47910a2332a351ebc5236b4e2bfb3562c23b (diff)
downloadllvm-d38057f3ecb080e0ae4aba367a737226221327f2.zip
llvm-d38057f3ecb080e0ae4aba367a737226221327f2.tar.gz
llvm-d38057f3ecb080e0ae4aba367a737226221327f2.tar.bz2
Treat implicit deduction guides as being equivalent to their
corresponding constructor for access checking purposes.
-rw-r--r--clang/include/clang/AST/DeclCXX.h15
-rw-r--r--clang/lib/AST/ASTImporter.cpp4
-rw-r--r--clang/lib/AST/DeclCXX.cpp14
-rw-r--r--clang/lib/Sema/SemaAccess.cpp14
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp12
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp1
-rw-r--r--clang/test/SemaTemplate/ctad.cpp35
8 files changed, 77 insertions, 19 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index d90732b..c3c326b 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1852,15 +1852,17 @@ private:
CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
ExplicitSpecifier ES,
const DeclarationNameInfo &NameInfo, QualType T,
- TypeSourceInfo *TInfo, SourceLocation EndLocation)
+ TypeSourceInfo *TInfo, SourceLocation EndLocation,
+ CXXConstructorDecl *Ctor)
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
SC_None, false, ConstexprSpecKind::Unspecified),
- ExplicitSpec(ES) {
+ Ctor(Ctor), ExplicitSpec(ES) {
if (EndLocation.isValid())
setRangeEnd(EndLocation);
setIsCopyDeductionCandidate(false);
}
+ CXXConstructorDecl *Ctor;
ExplicitSpecifier ExplicitSpec;
void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; }
@@ -1871,7 +1873,8 @@ public:
static CXXDeductionGuideDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
- TypeSourceInfo *TInfo, SourceLocation EndLocation);
+ TypeSourceInfo *TInfo, SourceLocation EndLocation,
+ CXXConstructorDecl *Ctor = nullptr);
static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -1886,6 +1889,12 @@ public:
return getDeclName().getCXXDeductionGuideTemplate();
}
+ /// Get the constructor from which this deduction guide was generated, if
+ /// this is an implicit deduction guide.
+ CXXConstructorDecl *getCorrespondingConstructor() const {
+ return Ctor;
+ }
+
void setIsCopyDeductionCandidate(bool isCDC = true) {
FunctionDeclBits.IsCopyDeductionCandidate = isCDC;
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 9caa117..c0fc376 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3457,11 +3457,13 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
} else if (auto *Guide = dyn_cast<CXXDeductionGuideDecl>(D)) {
ExplicitSpecifier ESpec =
importExplicitSpecifier(Err, Guide->getExplicitSpecifier());
+ CXXConstructorDecl *Ctor =
+ importChecked(Err, Guide->getCorrespondingConstructor());
if (Err)
return std::move(Err);
if (GetImportedOrCreateDecl<CXXDeductionGuideDecl>(
ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, ESpec,
- NameInfo, T, TInfo, ToEndLoc))
+ NameInfo, T, TInfo, ToEndLoc, Ctor))
return ToFunction;
cast<CXXDeductionGuideDecl>(ToFunction)
->setIsCopyDeductionCandidate(Guide->isCopyDeductionCandidate());
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 081c9eb..3d1faee 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2073,19 +2073,21 @@ ExplicitSpecifier ExplicitSpecifier::getFromDecl(FunctionDecl *Function) {
}
}
-CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
- ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
- ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
- TypeSourceInfo *TInfo, SourceLocation EndLocation) {
+CXXDeductionGuideDecl *
+CXXDeductionGuideDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, ExplicitSpecifier ES,
+ const DeclarationNameInfo &NameInfo, QualType T,
+ TypeSourceInfo *TInfo, SourceLocation EndLocation,
+ CXXConstructorDecl *Ctor) {
return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T,
- TInfo, EndLocation);
+ TInfo, EndLocation, Ctor);
}
CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) CXXDeductionGuideDecl(
C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
- QualType(), nullptr, SourceLocation());
+ QualType(), nullptr, SourceLocation(), nullptr);
}
RequiresExprBodyDecl *RequiresExprBodyDecl::Create(
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index be30445..3af0598 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -84,6 +84,20 @@ struct EffectiveContext {
: Inner(DC),
Dependent(DC->isDependentContext()) {
+ // An implicit deduction guide is semantically in the context enclosing the
+ // class template, but for access purposes behaves like the constructor
+ // from which it was produced.
+ if (auto *DGD = dyn_cast<CXXDeductionGuideDecl>(DC)) {
+ if (DGD->isImplicit()) {
+ DC = DGD->getCorrespondingConstructor();
+ if (!DC) {
+ // The copy deduction candidate doesn't have a corresponding
+ // constructor.
+ DC = cast<DeclContext>(DGD->getDeducedTemplate()->getTemplatedDecl());
+ }
+ }
+ }
+
// C++11 [class.access.nest]p1:
// A nested class is a member and as such has the same access
// rights as any other member.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ae368ba..fd37614 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2217,7 +2217,7 @@ struct ConvertConstructorToDeductionGuideTransform {
return nullptr;
TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
- return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(),
+ return buildDeductionGuide(TemplateParams, CD, CD->getExplicitSpecifier(),
NewTInfo, CD->getBeginLoc(), CD->getLocation(),
CD->getEndLoc(), MaterializedTypedefs);
}
@@ -2247,7 +2247,7 @@ struct ConvertConstructorToDeductionGuideTransform {
Params.push_back(NewParam);
}
- return buildDeductionGuide(Template->getTemplateParameters(),
+ return buildDeductionGuide(Template->getTemplateParameters(), nullptr,
ExplicitSpecifier(), TSI, Loc, Loc, Loc);
}
@@ -2425,9 +2425,9 @@ private:
}
FunctionTemplateDecl *buildDeductionGuide(
- TemplateParameterList *TemplateParams, ExplicitSpecifier ES,
- TypeSourceInfo *TInfo, SourceLocation LocStart, SourceLocation Loc,
- SourceLocation LocEnd,
+ TemplateParameterList *TemplateParams, CXXConstructorDecl *Ctor,
+ ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart,
+ SourceLocation Loc, SourceLocation LocEnd,
llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}) {
DeclarationNameInfo Name(DeductionGuideName, Loc);
ArrayRef<ParmVarDecl *> Params =
@@ -2436,7 +2436,7 @@ private:
// Build the implicit deduction guide template.
auto *Guide =
CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ES, Name,
- TInfo->getType(), TInfo, LocEnd);
+ TInfo->getType(), TInfo, LocEnd, Ctor);
Guide->setImplicit();
Guide->setParams(Params);
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 18ab466..50eb3bb 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1954,6 +1954,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
D->setExplicitSpecifier(Record.readExplicitSpec());
+ D->Ctor = readDeclAs<CXXConstructorDecl>();
VisitFunctionDecl(D);
D->setIsCopyDeductionCandidate(Record.readInt());
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 0a5a846..7674ecd 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -672,6 +672,7 @@ static void addExplicitSpecifier(ExplicitSpecifier ES,
void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
+ Record.AddDeclRef(D->Ctor);
VisitFunctionDecl(D);
Record.push_back(D->isCopyDeductionCandidate());
Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
diff --git a/clang/test/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp
index f294465..4d83683 100644
--- a/clang/test/SemaTemplate/ctad.cpp
+++ b/clang/test/SemaTemplate/ctad.cpp
@@ -1,17 +1,46 @@
// RUN: %clang_cc1 -std=c++17 -verify %s
-// expected-no-diagnostics
namespace pr41427 {
template <typename T> class A {
public:
A(void (*)(T)) {}
};
-
+
void D(int) {}
-
+
void f() {
A a(&D);
using T = decltype(a);
using T = A<int>;
}
}
+
+namespace Access {
+ struct B {
+ protected:
+ struct type {};
+ };
+ template<typename T> struct D : B { // expected-note {{not viable}}
+ D(T, typename T::type); // expected-note {{private member}}
+ };
+ D b = {B(), {}};
+
+ class X {
+ using type = int;
+ };
+ D x = {X(), {}}; // expected-error {{no viable constructor or deduction guide}}
+
+ // Once we implement proper support for dependent nested name specifiers in
+ // friends, this should still work.
+ class Y {
+ template <typename T> friend D<T>::D(T, typename T::type); // expected-warning {{dependent nested name specifier}}
+ struct type {};
+ };
+ D y = {Y(), {}};
+
+ class Z {
+ template <typename T> friend class D;
+ struct type {};
+ };
+ D z = {Z(), {}};
+}