Add support for derived class special members hiding functions brought in from
a base class via a using-declaration. If a class has a using-declaration declaring either a constructor or an assignment operator, eagerly declare its special members in case they need to displace a shadow declaration from a using-declaration. llvm-svn: 269398
This commit is contained in:
parent
845d0d74ba
commit
12e7931d0b
|
@ -382,6 +382,14 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// provided default ctor also doesn't have an in-class initializer.
|
||||
unsigned HasUninitializedFields : 1;
|
||||
|
||||
/// \brief True if there are any member using-declarations that inherit
|
||||
/// constructors from a base class.
|
||||
unsigned HasInheritedConstructor : 1;
|
||||
|
||||
/// \brief True if there are any member using-declarations named
|
||||
/// 'operator='.
|
||||
unsigned HasInheritedAssignment : 1;
|
||||
|
||||
/// \brief These flags are \c true if a defaulted corresponding special
|
||||
/// member can't be fully analyzed without performing overload resolution.
|
||||
/// @{
|
||||
|
@ -1308,6 +1316,18 @@ public:
|
|||
return data().HasNonLiteralTypeFieldsOrBases;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has a using-declaration that names
|
||||
/// a base class constructor.
|
||||
bool hasInheritedConstructor() const {
|
||||
return data().HasInheritedConstructor;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has a using-declaration that names
|
||||
/// a base class assignment operator.
|
||||
bool hasInheritedAssignment() const {
|
||||
return data().HasInheritedAssignment;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class is considered trivially copyable per
|
||||
/// (C++11 [class]p6).
|
||||
bool isTriviallyCopyable() const;
|
||||
|
|
|
@ -4540,6 +4540,9 @@ public:
|
|||
/// class.
|
||||
void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class);
|
||||
|
||||
/// \brief Check a completed declaration of an implicit special member.
|
||||
void CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD);
|
||||
|
||||
/// \brief Determine whether the given function is an implicitly-deleted
|
||||
/// special member function.
|
||||
bool isImplicitlyDeleted(FunctionDecl *FD);
|
||||
|
|
|
@ -2115,6 +2115,8 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
|
|||
ToData.HasUninitializedReferenceMember
|
||||
= FromData.HasUninitializedReferenceMember;
|
||||
ToData.HasUninitializedFields = FromData.HasUninitializedFields;
|
||||
ToData.HasInheritedConstructor = FromData.HasInheritedConstructor;
|
||||
ToData.HasInheritedAssignment = FromData.HasInheritedAssignment;
|
||||
ToData.NeedOverloadResolutionForMoveConstructor
|
||||
= FromData.NeedOverloadResolutionForMoveConstructor;
|
||||
ToData.NeedOverloadResolutionForMoveAssignment
|
||||
|
|
|
@ -53,6 +53,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
|||
HasPublicFields(false), HasMutableFields(false), HasVariantMembers(false),
|
||||
HasOnlyCMembers(true), HasInClassInitializer(false),
|
||||
HasUninitializedReferenceMember(false), HasUninitializedFields(false),
|
||||
HasInheritedConstructor(false), HasInheritedAssignment(false),
|
||||
NeedOverloadResolutionForMoveConstructor(false),
|
||||
NeedOverloadResolutionForMoveAssignment(false),
|
||||
NeedOverloadResolutionForDestructor(false),
|
||||
|
@ -955,6 +956,15 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
|||
data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess());
|
||||
}
|
||||
}
|
||||
|
||||
if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) {
|
||||
if (Using->getDeclName().getNameKind() ==
|
||||
DeclarationName::CXXConstructorName)
|
||||
data().HasInheritedConstructor = true;
|
||||
|
||||
if (Using->getDeclName().getCXXOverloadedOperator() == OO_Equal)
|
||||
data().HasInheritedAssignment = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
|
||||
|
|
|
@ -6455,20 +6455,28 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
if (!ClassDecl->hasUserDeclaredConstructor())
|
||||
++ASTContext::NumImplicitDefaultConstructors;
|
||||
|
||||
// If this class inherited any constructors, declare the default constructor
|
||||
// now in case it displaces one from a base class.
|
||||
if (ClassDecl->needsImplicitDefaultConstructor() &&
|
||||
ClassDecl->hasInheritedConstructor())
|
||||
DeclareImplicitDefaultConstructor(ClassDecl);
|
||||
|
||||
if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
|
||||
++ASTContext::NumImplicitCopyConstructors;
|
||||
|
||||
// If the properties or semantics of the copy constructor couldn't be
|
||||
// determined while the class was being declared, force a declaration
|
||||
// of it now.
|
||||
if (ClassDecl->needsOverloadResolutionForCopyConstructor())
|
||||
if (ClassDecl->needsOverloadResolutionForCopyConstructor() ||
|
||||
ClassDecl->hasInheritedConstructor())
|
||||
DeclareImplicitCopyConstructor(ClassDecl);
|
||||
}
|
||||
|
||||
if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) {
|
||||
++ASTContext::NumImplicitMoveConstructors;
|
||||
|
||||
if (ClassDecl->needsOverloadResolutionForMoveConstructor())
|
||||
if (ClassDecl->needsOverloadResolutionForMoveConstructor() ||
|
||||
ClassDecl->hasInheritedConstructor())
|
||||
DeclareImplicitMoveConstructor(ClassDecl);
|
||||
}
|
||||
|
||||
|
@ -6480,7 +6488,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
// it shows up in the right place in the vtable and that we diagnose
|
||||
// problems with the implicit exception specification.
|
||||
if (ClassDecl->isDynamicClass() ||
|
||||
ClassDecl->needsOverloadResolutionForCopyAssignment())
|
||||
ClassDecl->needsOverloadResolutionForCopyAssignment() ||
|
||||
ClassDecl->hasInheritedAssignment())
|
||||
DeclareImplicitCopyAssignment(ClassDecl);
|
||||
}
|
||||
|
||||
|
@ -6489,7 +6498,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
|
||||
// Likewise for the move assignment operator.
|
||||
if (ClassDecl->isDynamicClass() ||
|
||||
ClassDecl->needsOverloadResolutionForMoveAssignment())
|
||||
ClassDecl->needsOverloadResolutionForMoveAssignment() ||
|
||||
ClassDecl->hasInheritedAssignment())
|
||||
DeclareImplicitMoveAssignment(ClassDecl);
|
||||
}
|
||||
|
||||
|
@ -8898,10 +8908,11 @@ namespace {
|
|||
struct DeclaringSpecialMember {
|
||||
Sema &S;
|
||||
Sema::SpecialMemberDecl D;
|
||||
Sema::ContextRAII SavedContext;
|
||||
bool WasAlreadyBeingDeclared;
|
||||
|
||||
DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
|
||||
: S(S), D(RD, CSM) {
|
||||
: S(S), D(RD, CSM), SavedContext(S, RD) {
|
||||
WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second;
|
||||
if (WasAlreadyBeingDeclared)
|
||||
// This almost never happens, but if it does, ensure that our cache
|
||||
|
@ -8923,6 +8934,20 @@ struct DeclaringSpecialMember {
|
|||
};
|
||||
}
|
||||
|
||||
void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) {
|
||||
// Look up any existing declarations, but don't trigger declaration of all
|
||||
// implicit special members with this name.
|
||||
DeclarationName Name = FD->getDeclName();
|
||||
LookupResult R(*this, Name, SourceLocation(), LookupOrdinaryName,
|
||||
ForRedeclaration);
|
||||
for (auto *D : FD->getParent()->lookup(Name))
|
||||
if (auto *Acceptable = R.getAcceptableDecl(D))
|
||||
R.addDecl(Acceptable);
|
||||
R.resolveKind();
|
||||
|
||||
CheckFunctionDeclaration(S, FD, R, /*IsExplicitSpecialization*/false);
|
||||
}
|
||||
|
||||
CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
|
||||
CXXRecordDecl *ClassDecl) {
|
||||
// C++ [class.ctor]p5:
|
||||
|
@ -8971,13 +8996,16 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
|
|||
// constructors is easy to compute.
|
||||
DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
|
||||
|
||||
if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
|
||||
SetDeclDeleted(DefaultCon, ClassLoc);
|
||||
|
||||
// Note that we have declared this constructor.
|
||||
++ASTContext::NumImplicitDefaultConstructorsDeclared;
|
||||
|
||||
if (Scope *S = getScopeForContext(ClassDecl))
|
||||
Scope *S = getScopeForContext(ClassDecl);
|
||||
CheckImplicitSpecialMemberDeclaration(S, DefaultCon);
|
||||
|
||||
if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
|
||||
SetDeclDeleted(DefaultCon, ClassLoc);
|
||||
|
||||
if (S)
|
||||
PushOnScopeChains(DefaultCon, S, false);
|
||||
ClassDecl->addDecl(DefaultCon);
|
||||
|
||||
|
@ -9433,20 +9461,21 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
|
|||
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor);
|
||||
Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
|
||||
|
||||
AddOverriddenMethods(ClassDecl, Destructor);
|
||||
|
||||
// We don't need to use SpecialMemberIsTrivial here; triviality for
|
||||
// destructors is easy to compute.
|
||||
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
|
||||
|
||||
if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
|
||||
SetDeclDeleted(Destructor, ClassLoc);
|
||||
|
||||
// Note that we have declared this destructor.
|
||||
++ASTContext::NumImplicitDestructorsDeclared;
|
||||
|
||||
Scope *S = getScopeForContext(ClassDecl);
|
||||
CheckImplicitSpecialMemberDeclaration(S, Destructor);
|
||||
|
||||
if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
|
||||
SetDeclDeleted(Destructor, ClassLoc);
|
||||
|
||||
// Introduce this destructor into its scope.
|
||||
if (Scope *S = getScopeForContext(ClassDecl))
|
||||
if (S)
|
||||
PushOnScopeChains(Destructor, S, false);
|
||||
ClassDecl->addDecl(Destructor);
|
||||
|
||||
|
@ -10147,20 +10176,21 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
|
|||
nullptr);
|
||||
CopyAssignment->setParams(FromParam);
|
||||
|
||||
AddOverriddenMethods(ClassDecl, CopyAssignment);
|
||||
|
||||
CopyAssignment->setTrivial(
|
||||
ClassDecl->needsOverloadResolutionForCopyAssignment()
|
||||
? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
|
||||
: ClassDecl->hasTrivialCopyAssignment());
|
||||
|
||||
if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
|
||||
SetDeclDeleted(CopyAssignment, ClassLoc);
|
||||
|
||||
// Note that we have added this copy-assignment operator.
|
||||
++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
|
||||
|
||||
if (Scope *S = getScopeForContext(ClassDecl))
|
||||
Scope *S = getScopeForContext(ClassDecl);
|
||||
CheckImplicitSpecialMemberDeclaration(S, CopyAssignment);
|
||||
|
||||
if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
|
||||
SetDeclDeleted(CopyAssignment, ClassLoc);
|
||||
|
||||
if (S)
|
||||
PushOnScopeChains(CopyAssignment, S, false);
|
||||
ClassDecl->addDecl(CopyAssignment);
|
||||
|
||||
|
@ -10538,22 +10568,23 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
|
|||
nullptr);
|
||||
MoveAssignment->setParams(FromParam);
|
||||
|
||||
AddOverriddenMethods(ClassDecl, MoveAssignment);
|
||||
|
||||
MoveAssignment->setTrivial(
|
||||
ClassDecl->needsOverloadResolutionForMoveAssignment()
|
||||
? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
|
||||
: ClassDecl->hasTrivialMoveAssignment());
|
||||
|
||||
// Note that we have added this copy-assignment operator.
|
||||
++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
|
||||
|
||||
Scope *S = getScopeForContext(ClassDecl);
|
||||
CheckImplicitSpecialMemberDeclaration(S, MoveAssignment);
|
||||
|
||||
if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) {
|
||||
ClassDecl->setImplicitMoveAssignmentIsDeleted();
|
||||
SetDeclDeleted(MoveAssignment, ClassLoc);
|
||||
}
|
||||
|
||||
// Note that we have added this copy-assignment operator.
|
||||
++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
|
||||
|
||||
if (Scope *S = getScopeForContext(ClassDecl))
|
||||
if (S)
|
||||
PushOnScopeChains(MoveAssignment, S, false);
|
||||
ClassDecl->addDecl(MoveAssignment);
|
||||
|
||||
|
@ -10979,13 +11010,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
|
|||
? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
|
||||
: ClassDecl->hasTrivialCopyConstructor());
|
||||
|
||||
if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
|
||||
SetDeclDeleted(CopyConstructor, ClassLoc);
|
||||
|
||||
// Note that we have declared this constructor.
|
||||
++ASTContext::NumImplicitCopyConstructorsDeclared;
|
||||
|
||||
if (Scope *S = getScopeForContext(ClassDecl))
|
||||
Scope *S = getScopeForContext(ClassDecl);
|
||||
CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);
|
||||
|
||||
if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
|
||||
SetDeclDeleted(CopyConstructor, ClassLoc);
|
||||
|
||||
if (S)
|
||||
PushOnScopeChains(CopyConstructor, S, false);
|
||||
ClassDecl->addDecl(CopyConstructor);
|
||||
|
||||
|
@ -11156,15 +11190,18 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
|
|||
? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
|
||||
: ClassDecl->hasTrivialMoveConstructor());
|
||||
|
||||
// Note that we have declared this constructor.
|
||||
++ASTContext::NumImplicitMoveConstructorsDeclared;
|
||||
|
||||
Scope *S = getScopeForContext(ClassDecl);
|
||||
CheckImplicitSpecialMemberDeclaration(S, MoveConstructor);
|
||||
|
||||
if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) {
|
||||
ClassDecl->setImplicitMoveConstructorIsDeleted();
|
||||
SetDeclDeleted(MoveConstructor, ClassLoc);
|
||||
}
|
||||
|
||||
// Note that we have declared this constructor.
|
||||
++ASTContext::NumImplicitMoveConstructorsDeclared;
|
||||
|
||||
if (Scope *S = getScopeForContext(ClassDecl))
|
||||
if (S)
|
||||
PushOnScopeChains(MoveConstructor, S, false);
|
||||
ClassDecl->addDecl(MoveConstructor);
|
||||
|
||||
|
|
|
@ -1466,6 +1466,8 @@ void ASTDeclReader::ReadCXXDefinitionData(
|
|||
Data.HasInClassInitializer = Record[Idx++];
|
||||
Data.HasUninitializedReferenceMember = Record[Idx++];
|
||||
Data.HasUninitializedFields = Record[Idx++];
|
||||
Data.HasInheritedConstructor = Record[Idx++];
|
||||
Data.HasInheritedAssignment = Record[Idx++];
|
||||
Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++];
|
||||
Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++];
|
||||
Data.NeedOverloadResolutionForDestructor = Record[Idx++];
|
||||
|
@ -1593,6 +1595,8 @@ void ASTDeclReader::MergeDefinitionData(
|
|||
MATCH_FIELD(HasInClassInitializer)
|
||||
MATCH_FIELD(HasUninitializedReferenceMember)
|
||||
MATCH_FIELD(HasUninitializedFields)
|
||||
MATCH_FIELD(HasInheritedConstructor)
|
||||
MATCH_FIELD(HasInheritedAssignment)
|
||||
MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
|
||||
MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
|
||||
MATCH_FIELD(NeedOverloadResolutionForDestructor)
|
||||
|
|
|
@ -5489,6 +5489,8 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
|
|||
Record->push_back(Data.HasInClassInitializer);
|
||||
Record->push_back(Data.HasUninitializedReferenceMember);
|
||||
Record->push_back(Data.HasUninitializedFields);
|
||||
Record->push_back(Data.HasInheritedConstructor);
|
||||
Record->push_back(Data.HasInheritedAssignment);
|
||||
Record->push_back(Data.NeedOverloadResolutionForMoveConstructor);
|
||||
Record->push_back(Data.NeedOverloadResolutionForMoveAssignment);
|
||||
Record->push_back(Data.NeedOverloadResolutionForDestructor);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
// C++03 [namespace.udecl]p12:
|
||||
|
@ -161,3 +163,33 @@ namespace test4 {
|
|||
d.bar<int>(3); // expected-error {{'bar' is a protected member}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace test5 {
|
||||
struct Derived;
|
||||
struct Base {
|
||||
void operator=(const Derived&);
|
||||
};
|
||||
struct Derived : Base {
|
||||
// Hidden by implicit derived class operator.
|
||||
using Base::operator=;
|
||||
};
|
||||
void f(Derived d) {
|
||||
d = d;
|
||||
}
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
namespace test6 {
|
||||
struct Derived;
|
||||
struct Base {
|
||||
void operator=(Derived&&);
|
||||
};
|
||||
struct Derived : Base {
|
||||
// Hidden by implicit derived class operator.
|
||||
using Base::operator=;
|
||||
};
|
||||
void f(Derived d) {
|
||||
d = Derived();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -60,13 +60,14 @@ struct A3_with_device_ctors {
|
|||
|
||||
struct B3_with_implicit_ctors : A3_with_device_ctors {
|
||||
};
|
||||
// expected-note@-2 2{{call to __device__ function from __host__ function}}
|
||||
// expected-note@-3 {{default constructor}}
|
||||
|
||||
// expected-note@-3 {{copy constructor of 'B3_with_implicit_ctors' is implicitly deleted}}
|
||||
|
||||
void hostfoo3() {
|
||||
B3_with_implicit_ctors b; // this is OK because the inferred default ctor
|
||||
// here is __host__
|
||||
B3_with_implicit_ctors b2 = b; // expected-error {{call to implicitly-deleted copy constructor}}
|
||||
B3_with_implicit_ctors b2 = b; // expected-error {{no matching constructor}}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
struct C {
|
||||
struct C { // expected-note 1+{{candidate}}
|
||||
virtual C() = 0; // expected-error{{constructor cannot be declared 'virtual'}}
|
||||
};
|
||||
|
||||
void f() {
|
||||
C c;
|
||||
C c; // expected-error {{no matching constructor}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue