From: Richard Smith Date: Wed, 19 May 2021 20:31:13 +0000 (-0700) Subject: Treat implicit deduction guides as being equivalent to their X-Git-Tag: llvmorg-14-init~6148 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d38057f3ecb080e0ae4aba367a737226221327f2;p=platform%2Fupstream%2Fllvm.git Treat implicit deduction guides as being equivalent to their corresponding constructor for access checking purposes. --- 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(D)) { ExplicitSpecifier ESpec = importExplicitSpecifier(Err, Guide->getExplicitSpecifier()); + CXXConstructorDecl *Ctor = + importChecked(Err, Guide->getCorrespondingConstructor()); if (Err) return std::move(Err); if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, ESpec, - NameInfo, T, TInfo, ToEndLoc)) + NameInfo, T, TInfo, ToEndLoc, Ctor)) return ToFunction; cast(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(DC)) { + if (DGD->isImplicit()) { + DC = DGD->getCorrespondingConstructor(); + if (!DC) { + // The copy deduction candidate doesn't have a corresponding + // constructor. + DC = cast(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 MaterializedTypedefs = {}) { DeclarationNameInfo Name(DeductionGuideName, Loc); ArrayRef 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(); 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 class A { public: A(void (*)(T)) {} }; - + void D(int) {} - + void f() { A a(&D); using T = decltype(a); using T = A; } } + +namespace Access { + struct B { + protected: + struct type {}; + }; + template 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 friend D::D(T, typename T::type); // expected-warning {{dependent nested name specifier}} + struct type {}; + }; + D y = {Y(), {}}; + + class Z { + template friend class D; + struct type {}; + }; + D z = {Z(), {}}; +}