diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-06-28 19:03:57 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-06-28 19:03:57 +0000 |
commit | 5be817d9f91482faa3e16103ac2d456d06369168 (patch) | |
tree | 1c9a1279ea0bbe75aea756b7437ab79c17a24eda /lib/AST/DeclCXX.cpp | |
parent | c982075071e9130f5312885c05fe1f9b3c5233d5 (diff) |
P0136R1, DR1573, DR1645, DR1715, DR1736, DR1903, DR1941, DR1959, DR1991:
Replace inheriting constructors implementation with new approach, voted into
C++ last year as a DR against C++11.
Instead of synthesizing a set of derived class constructors for each inherited
base class constructor, we make the constructors of the base class visible to
constructor lookup in the derived class, using the normal rules for
using-declarations.
For constructors, UsingShadowDecl now has a ConstructorUsingShadowDecl derived
class that tracks the requisite additional information. We create shadow
constructors (not found by name lookup) in the derived class to model the
actual initialization, and have a new expression node,
CXXInheritedCtorInitExpr, to model the initialization of a base class from such
a constructor. (This initialization is special because it performs real perfect
forwarding of arguments.)
In cases where argument forwarding is not possible (for inalloca calls,
variadic calls, and calls with callee parameter cleanup), the shadow inheriting
constructor is not emitted and instead we directly emit the initialization code
into the caller of the inherited constructor.
Note that this new model is not perfectly compatible with the old model in some
corner cases. In particular:
* if B inherits a private constructor from A, and C uses that constructor to
construct a B, then we previously required that A befriends B and B
befriends C, but the new rules require A to befriend C directly, and
* if a derived class has its own constructors (and so its implicit default
constructor is suppressed), it may still inherit a default constructor from
a base class
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@274049 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/DeclCXX.cpp')
-rw-r--r-- | lib/AST/DeclCXX.cpp | 109 |
1 files changed, 74 insertions, 35 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 2a1fac8509..de06ecb4ca 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -448,6 +448,15 @@ void CXXRecordDecl::addedMember(Decl *D) { FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); if (FunTmpl) D = FunTmpl->getTemplatedDecl(); + + // FIXME: Pass NamedDecl* to addedMember? + Decl *DUnderlying = D; + if (auto *ND = dyn_cast<NamedDecl>(DUnderlying)) { + DUnderlying = ND->getUnderlyingDecl(); + if (FunctionTemplateDecl *UnderlyingFunTmpl = + dyn_cast<FunctionTemplateDecl>(DUnderlying)) + DUnderlying = UnderlyingFunTmpl->getTemplatedDecl(); + } if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { if (Method->isVirtual()) { @@ -503,15 +512,10 @@ void CXXRecordDecl::addedMember(Decl *D) { data().PlainOldData = false; } - // Technically, "user-provided" is only defined for special member - // functions, but the intent of the standard is clearly that it should apply - // to all functions. - bool UserProvided = Constructor->isUserProvided(); - if (Constructor->isDefaultConstructor()) { SMKind |= SMF_DefaultConstructor; - if (UserProvided) + if (Constructor->isUserProvided()) data().UserProvidedDefaultConstructor = true; if (Constructor->isConstexpr()) data().HasConstexprDefaultConstructor = true; @@ -529,9 +533,17 @@ void CXXRecordDecl::addedMember(Decl *D) { } else if (Constructor->isMoveConstructor()) SMKind |= SMF_MoveConstructor; } + } + // Handle constructors, including those inherited from base classes. + if (CXXConstructorDecl *Constructor = + dyn_cast<CXXConstructorDecl>(DUnderlying)) { // Record if we see any constexpr constructors which are neither copy // nor move constructors. + // C++1z [basic.types]p10: + // [...] has at least one constexpr constructor or constructor template + // (possibly inherited from a base class) that is not a copy or move + // constructor [...] if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) data().HasConstexprNonCopyMoveConstructor = true; @@ -541,8 +553,12 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++11 [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-provided // constructors [...]. + // C++11 [dcl.init.aggr]p1: + // An aggregate is an array or a class with no user-provided + // constructors (including those inherited from a base class) [...]. if (getASTContext().getLangOpts().CPlusPlus11 - ? UserProvided : !Constructor->isImplicit()) + ? Constructor->isUserProvided() + : !Constructor->isImplicit()) data().Aggregate = false; } @@ -1784,11 +1800,15 @@ SourceRange CXXCtorInitializer::getSourceRange() const { void CXXConstructorDecl::anchor() { } -CXXConstructorDecl * -CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) CXXConstructorDecl(C, nullptr, SourceLocation(), - DeclarationNameInfo(), QualType(), - nullptr, false, false, false, false); +CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, + unsigned ID, + bool Inherited) { + unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited); + auto *Result = new (C, ID, Extra) CXXConstructorDecl( + C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, + false, false, false, false, InheritedConstructor()); + Result->IsInheritingConstructor = Inherited; + return Result; } CXXConstructorDecl * @@ -1797,13 +1817,16 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, - bool isImplicitlyDeclared, bool isConstexpr) { + bool isImplicitlyDeclared, bool isConstexpr, + InheritedConstructor Inherited) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C, RD) CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, - isExplicit, isInline, - isImplicitlyDeclared, isConstexpr); + unsigned Extra = + additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0); + return new (C, RD, Extra) CXXConstructorDecl( + C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline, + isImplicitlyDeclared, isConstexpr, Inherited); } CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const { @@ -1918,23 +1941,6 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const { return true; } -const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const { - // Hack: we store the inherited constructor in the overridden method table - method_iterator It = getASTContext().overridden_methods_begin(this); - if (It == getASTContext().overridden_methods_end(this)) - return nullptr; - - return cast<CXXConstructorDecl>(*It); -} - -void -CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){ - // Hack: we store the inherited constructor in the overridden method table - assert(getASTContext().overridden_methods_size(this) == 0 && - "Base ctor already set."); - getASTContext().addOverriddenMethod(this, BaseCtor); -} - void CXXDestructorDecl::anchor() { } CXXDestructorDecl * @@ -2130,10 +2136,24 @@ NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void UsingShadowDecl::anchor() { } +UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, + SourceLocation Loc, UsingDecl *Using, + NamedDecl *Target) + : NamedDecl(K, DC, Loc, Using ? Using->getDeclName() : DeclarationName()), + redeclarable_base(C), Underlying(Target), + UsingOrNextShadow(cast<NamedDecl>(Using)) { + if (Target) + IdentifierNamespace = Target->getIdentifierNamespace(); + setImplicit(); +} + +UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, EmptyShell Empty) + : NamedDecl(K, nullptr, SourceLocation(), DeclarationName()), + redeclarable_base(C), Underlying(), UsingOrNextShadow() {} + UsingShadowDecl * UsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) UsingShadowDecl(C, nullptr, SourceLocation(), - nullptr, nullptr); + return new (C, ID) UsingShadowDecl(UsingShadow, C, EmptyShell()); } UsingDecl *UsingShadowDecl::getUsingDecl() const { @@ -2144,6 +2164,25 @@ UsingDecl *UsingShadowDecl::getUsingDecl() const { return cast<UsingDecl>(Shadow->UsingOrNextShadow); } +void ConstructorUsingShadowDecl::anchor() { } + +ConstructorUsingShadowDecl * +ConstructorUsingShadowDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation Loc, UsingDecl *Using, + NamedDecl *Target, bool IsVirtual) { + return new (C, DC) ConstructorUsingShadowDecl(C, DC, Loc, Using, Target, + IsVirtual); +} + +ConstructorUsingShadowDecl * +ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + return new (C, ID) ConstructorUsingShadowDecl(C, EmptyShell()); +} + +CXXRecordDecl *ConstructorUsingShadowDecl::getNominatedBaseClass() const { + return getUsingDecl()->getQualifier()->getAsRecordDecl(); +} + void UsingDecl::anchor() { } void UsingDecl::addShadowDecl(UsingShadowDecl *S) { |