Skip to content

Commit 5179eb7

Browse files
committed
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 llvm-svn: 274049
1 parent a5c7adc commit 5179eb7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+2754
-931
lines changed

clang/include/clang/AST/ASTMutationListener.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace clang {
1717
class Attr;
1818
class ClassTemplateDecl;
1919
class ClassTemplateSpecializationDecl;
20+
class ConstructorUsingShadowDecl;
2021
class CXXDestructorDecl;
2122
class CXXRecordDecl;
2223
class Decl;

clang/include/clang/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ class NamedDecl : public Decl {
387387
NamedDecl *getUnderlyingDecl() {
388388
// Fast-path the common case.
389389
if (this->getKind() != UsingShadow &&
390+
this->getKind() != ConstructorUsingShadow &&
390391
this->getKind() != ObjCCompatibleAlias &&
391392
this->getKind() != NamespaceAlias)
392393
return this;

clang/include/clang/AST/DeclCXX.h

Lines changed: 176 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace clang {
2929

3030
class ClassTemplateDecl;
3131
class ClassTemplateSpecializationDecl;
32+
class ConstructorUsingShadowDecl;
3233
class CXXBasePath;
3334
class CXXBasePaths;
3435
class CXXConstructorDecl;
@@ -1298,7 +1299,7 @@ class CXXRecordDecl : public RecordDecl {
12981299
}
12991300

13001301
/// \brief Determine whether this class has a using-declaration that names
1301-
/// a base class constructor.
1302+
/// a user-declared base class constructor.
13021303
bool hasInheritedConstructor() const {
13031304
return data().HasInheritedConstructor;
13041305
}
@@ -2153,6 +2154,23 @@ class CXXCtorInitializer final
21532154
friend TrailingObjects;
21542155
};
21552156

2157+
/// Description of a constructor that was inherited from a base class.
2158+
class InheritedConstructor {
2159+
ConstructorUsingShadowDecl *Shadow;
2160+
CXXConstructorDecl *BaseCtor;
2161+
2162+
public:
2163+
InheritedConstructor() : Shadow(), BaseCtor() {}
2164+
InheritedConstructor(ConstructorUsingShadowDecl *Shadow,
2165+
CXXConstructorDecl *BaseCtor)
2166+
: Shadow(Shadow), BaseCtor(BaseCtor) {}
2167+
2168+
explicit operator bool() const { return Shadow; }
2169+
2170+
ConstructorUsingShadowDecl *getShadowDecl() const { return Shadow; }
2171+
CXXConstructorDecl *getConstructor() const { return BaseCtor; }
2172+
};
2173+
21562174
/// \brief Represents a C++ constructor within a class.
21572175
///
21582176
/// For example:
@@ -2163,41 +2181,51 @@ class CXXCtorInitializer final
21632181
/// explicit X(int); // represented by a CXXConstructorDecl.
21642182
/// };
21652183
/// \endcode
2166-
class CXXConstructorDecl : public CXXMethodDecl {
2184+
class CXXConstructorDecl final
2185+
: public CXXMethodDecl,
2186+
private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor> {
21672187
void anchor() override;
21682188

21692189
/// \name Support for base and member initializers.
21702190
/// \{
21712191
/// \brief The arguments used to initialize the base or member.
21722192
LazyCXXCtorInitializersPtr CtorInitializers;
2173-
unsigned NumCtorInitializers : 31;
2193+
unsigned NumCtorInitializers : 30;
21742194
/// \}
21752195

21762196
/// \brief Whether this constructor declaration has the \c explicit keyword
21772197
/// specified.
21782198
unsigned IsExplicitSpecified : 1;
21792199

2200+
/// \brief Whether this constructor declaration is an implicitly-declared
2201+
/// inheriting constructor.
2202+
unsigned IsInheritingConstructor : 1;
2203+
21802204
CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
21812205
const DeclarationNameInfo &NameInfo,
21822206
QualType T, TypeSourceInfo *TInfo,
21832207
bool isExplicitSpecified, bool isInline,
2184-
bool isImplicitlyDeclared, bool isConstexpr)
2208+
bool isImplicitlyDeclared, bool isConstexpr,
2209+
InheritedConstructor Inherited)
21852210
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
21862211
SC_None, isInline, isConstexpr, SourceLocation()),
21872212
CtorInitializers(nullptr), NumCtorInitializers(0),
2188-
IsExplicitSpecified(isExplicitSpecified) {
2213+
IsExplicitSpecified(isExplicitSpecified),
2214+
IsInheritingConstructor((bool)Inherited) {
21892215
setImplicit(isImplicitlyDeclared);
2216+
if (Inherited)
2217+
*getTrailingObjects<InheritedConstructor>() = Inherited;
21902218
}
21912219

21922220
public:
2193-
static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID);
2194-
static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
2195-
SourceLocation StartLoc,
2196-
const DeclarationNameInfo &NameInfo,
2197-
QualType T, TypeSourceInfo *TInfo,
2198-
bool isExplicit,
2199-
bool isInline, bool isImplicitlyDeclared,
2200-
bool isConstexpr);
2221+
static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID,
2222+
bool InheritsConstructor);
2223+
static CXXConstructorDecl *
2224+
Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
2225+
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
2226+
bool isExplicit, bool isInline, bool isImplicitlyDeclared,
2227+
bool isConstexpr,
2228+
InheritedConstructor Inherited = InheritedConstructor());
22012229

22022230
/// \brief Determine whether this constructor declaration has the
22032231
/// \c explicit keyword specified.
@@ -2344,11 +2372,15 @@ class CXXConstructorDecl : public CXXMethodDecl {
23442372
/// an object.
23452373
bool isSpecializationCopyingObject() const;
23462374

2347-
/// \brief Get the constructor that this inheriting constructor is based on.
2348-
const CXXConstructorDecl *getInheritedConstructor() const;
2375+
/// \brief Determine whether this is an implicit constructor synthesized to
2376+
/// model a call to a constructor inherited from a base class.
2377+
bool isInheritingConstructor() const { return IsInheritingConstructor; }
23492378

2350-
/// \brief Set the constructor that this inheriting constructor is based on.
2351-
void setInheritedConstructor(const CXXConstructorDecl *BaseCtor);
2379+
/// \brief Get the constructor that this inheriting constructor is based on.
2380+
InheritedConstructor getInheritedConstructor() const {
2381+
return IsInheritingConstructor ? *getTrailingObjects<InheritedConstructor>()
2382+
: InheritedConstructor();
2383+
}
23522384

23532385
CXXConstructorDecl *getCanonicalDecl() override {
23542386
return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl());
@@ -2363,6 +2395,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
23632395

23642396
friend class ASTDeclReader;
23652397
friend class ASTDeclWriter;
2398+
friend TrailingObjects;
23662399
};
23672400

23682401
/// \brief Represents a C++ destructor within a class.
@@ -2807,18 +2840,6 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
28072840
NamedDecl *UsingOrNextShadow;
28082841
friend class UsingDecl;
28092842

2810-
UsingShadowDecl(ASTContext &C, DeclContext *DC, SourceLocation Loc,
2811-
UsingDecl *Using, NamedDecl *Target)
2812-
: NamedDecl(UsingShadow, DC, Loc, DeclarationName()),
2813-
redeclarable_base(C), Underlying(Target),
2814-
UsingOrNextShadow(reinterpret_cast<NamedDecl *>(Using)) {
2815-
if (Target) {
2816-
setDeclName(Target->getDeclName());
2817-
IdentifierNamespace = Target->getIdentifierNamespace();
2818-
}
2819-
setImplicit();
2820-
}
2821-
28222843
typedef Redeclarable<UsingShadowDecl> redeclarable_base;
28232844
UsingShadowDecl *getNextRedeclarationImpl() override {
28242845
return getNextRedeclaration();
@@ -2830,11 +2851,16 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
28302851
return getMostRecentDecl();
28312852
}
28322853

2854+
protected:
2855+
UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, SourceLocation Loc,
2856+
UsingDecl *Using, NamedDecl *Target);
2857+
UsingShadowDecl(Kind K, ASTContext &C, EmptyShell);
2858+
28332859
public:
28342860
static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC,
28352861
SourceLocation Loc, UsingDecl *Using,
28362862
NamedDecl *Target) {
2837-
return new (C, DC) UsingShadowDecl(C, DC, Loc, Using, Target);
2863+
return new (C, DC) UsingShadowDecl(UsingShadow, C, DC, Loc, Using, Target);
28382864
}
28392865

28402866
static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2846,6 +2872,7 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
28462872
using redeclarable_base::redecls;
28472873
using redeclarable_base::getPreviousDecl;
28482874
using redeclarable_base::getMostRecentDecl;
2875+
using redeclarable_base::isFirstDecl;
28492876

28502877
UsingShadowDecl *getCanonicalDecl() override {
28512878
return getFirstDecl();
@@ -2876,7 +2903,125 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> {
28762903
}
28772904

28782905
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
2879-
static bool classofKind(Kind K) { return K == Decl::UsingShadow; }
2906+
static bool classofKind(Kind K) {
2907+
return K == Decl::UsingShadow || K == Decl::ConstructorUsingShadow;
2908+
}
2909+
2910+
friend class ASTDeclReader;
2911+
friend class ASTDeclWriter;
2912+
};
2913+
2914+
/// \brief Represents a shadow constructor declaration introduced into a
2915+
/// class by a C++11 using-declaration that names a constructor.
2916+
///
2917+
/// For example:
2918+
/// \code
2919+
/// struct Base { Base(int); };
2920+
/// struct Derived {
2921+
/// using Base::Base; // creates a UsingDecl and a ConstructorUsingShadowDecl
2922+
/// };
2923+
/// \endcode
2924+
class ConstructorUsingShadowDecl final : public UsingShadowDecl {
2925+
void anchor() override;
2926+
2927+
/// \brief If this constructor using declaration inherted the constructor
2928+
/// from an indirect base class, this is the ConstructorUsingShadowDecl
2929+
/// in the named direct base class from which the declaration was inherited.
2930+
ConstructorUsingShadowDecl *NominatedBaseClassShadowDecl;
2931+
2932+
/// \brief If this constructor using declaration inherted the constructor
2933+
/// from an indirect base class, this is the ConstructorUsingShadowDecl
2934+
/// that will be used to construct the unique direct or virtual base class
2935+
/// that receives the constructor arguments.
2936+
ConstructorUsingShadowDecl *ConstructedBaseClassShadowDecl;
2937+
2938+
/// \brief \c true if the constructor ultimately named by this using shadow
2939+
/// declaration is within a virtual base class subobject of the class that
2940+
/// contains this declaration.
2941+
unsigned IsVirtual : 1;
2942+
2943+
ConstructorUsingShadowDecl(ASTContext &C, DeclContext *DC, SourceLocation Loc,
2944+
UsingDecl *Using, NamedDecl *Target,
2945+
bool TargetInVirtualBase)
2946+
: UsingShadowDecl(ConstructorUsingShadow, C, DC, Loc, Using,
2947+
Target->getUnderlyingDecl()),
2948+
NominatedBaseClassShadowDecl(
2949+
dyn_cast<ConstructorUsingShadowDecl>(Target)),
2950+
ConstructedBaseClassShadowDecl(NominatedBaseClassShadowDecl),
2951+
IsVirtual(TargetInVirtualBase) {
2952+
// If we found a constructor for a non-virtual base class, but it chains to
2953+
// a constructor for a virtual base, we should directly call the virtual
2954+
// base constructor instead.
2955+
// FIXME: This logic belongs in Sema.
2956+
if (!TargetInVirtualBase && NominatedBaseClassShadowDecl &&
2957+
NominatedBaseClassShadowDecl->constructsVirtualBase()) {
2958+
ConstructedBaseClassShadowDecl =
2959+
NominatedBaseClassShadowDecl->ConstructedBaseClassShadowDecl;
2960+
IsVirtual = true;
2961+
}
2962+
}
2963+
ConstructorUsingShadowDecl(ASTContext &C, EmptyShell Empty)
2964+
: UsingShadowDecl(ConstructorUsingShadow, C, Empty) {}
2965+
2966+
public:
2967+
static ConstructorUsingShadowDecl *Create(ASTContext &C, DeclContext *DC,
2968+
SourceLocation Loc,
2969+
UsingDecl *Using, NamedDecl *Target,
2970+
bool IsVirtual);
2971+
static ConstructorUsingShadowDecl *CreateDeserialized(ASTContext &C,
2972+
unsigned ID);
2973+
2974+
/// Returns the parent of this using shadow declaration, which
2975+
/// is the class in which this is declared.
2976+
//@{
2977+
const CXXRecordDecl *getParent() const {
2978+
return cast<CXXRecordDecl>(getDeclContext());
2979+
}
2980+
CXXRecordDecl *getParent() {
2981+
return cast<CXXRecordDecl>(getDeclContext());
2982+
}
2983+
//@}
2984+
2985+
/// \brief Get the inheriting constructor declaration for the direct base
2986+
/// class from which this using shadow declaration was inherited, if there is
2987+
/// one. This can be different for each redeclaration of the same shadow decl.
2988+
ConstructorUsingShadowDecl *getNominatedBaseClassShadowDecl() const {
2989+
return NominatedBaseClassShadowDecl;
2990+
}
2991+
2992+
/// \brief Get the inheriting constructor declaration for the base class
2993+
/// for which we don't have an explicit initializer, if there is one.
2994+
ConstructorUsingShadowDecl *getConstructedBaseClassShadowDecl() const {
2995+
return ConstructedBaseClassShadowDecl;
2996+
}
2997+
2998+
/// \brief Get the base class that was named in the using declaration. This
2999+
/// can be different for each redeclaration of this same shadow decl.
3000+
CXXRecordDecl *getNominatedBaseClass() const;
3001+
3002+
/// \brief Get the base class whose constructor or constructor shadow
3003+
/// declaration is passed the constructor arguments.
3004+
CXXRecordDecl *getConstructedBaseClass() const {
3005+
return cast<CXXRecordDecl>((ConstructedBaseClassShadowDecl
3006+
? ConstructedBaseClassShadowDecl
3007+
: getTargetDecl())
3008+
->getDeclContext());
3009+
}
3010+
3011+
/// \brief Returns \c true if the constructed base class is a virtual base
3012+
/// class subobject of this declaration's class.
3013+
bool constructsVirtualBase() const {
3014+
return IsVirtual;
3015+
}
3016+
3017+
/// \brief Get the constructor or constructor template in the derived class
3018+
/// correspnding to this using shadow declaration, if it has been implicitly
3019+
/// declared already.
3020+
CXXConstructorDecl *getConstructor() const;
3021+
void setConstructor(NamedDecl *Ctor);
3022+
3023+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
3024+
static bool classofKind(Kind K) { return K == ConstructorUsingShadow; }
28803025

28813026
friend class ASTDeclReader;
28823027
friend class ASTDeclWriter;

clang/include/clang/AST/ExprCXX.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,73 @@ class CXXConstructExpr : public Expr {
13181318
friend class ASTStmtReader;
13191319
};
13201320

1321+
/// \brief Represents a call to an inherited base class constructor from an
1322+
/// inheriting constructor. This call implicitly forwards the arguments from
1323+
/// the enclosing context (an inheriting constructor) to the specified inherited
1324+
/// base class constructor.
1325+
class CXXInheritedCtorInitExpr : public Expr {
1326+
private:
1327+
CXXConstructorDecl *Constructor;
1328+
1329+
/// The location of the using declaration.
1330+
SourceLocation Loc;
1331+
1332+
/// Whether this is the construction of a virtual base.
1333+
unsigned ConstructsVirtualBase : 1;
1334+
1335+
/// Whether the constructor is inherited from a virtual base class of the
1336+
/// class that we construct.
1337+
unsigned InheritedFromVirtualBase : 1;
1338+
1339+
public:
1340+
/// \brief Construct a C++ inheriting construction expression.
1341+
CXXInheritedCtorInitExpr(SourceLocation Loc, QualType T,
1342+
CXXConstructorDecl *Ctor, bool ConstructsVirtualBase,
1343+
bool InheritedFromVirtualBase)
1344+
: Expr(CXXInheritedCtorInitExprClass, T, VK_RValue, OK_Ordinary, false,
1345+
false, false, false),
1346+
Constructor(Ctor), Loc(Loc),
1347+
ConstructsVirtualBase(ConstructsVirtualBase),
1348+
InheritedFromVirtualBase(InheritedFromVirtualBase) {
1349+
assert(!T->isDependentType());
1350+
}
1351+
1352+
/// \brief Construct an empty C++ inheriting construction expression.
1353+
explicit CXXInheritedCtorInitExpr(EmptyShell Empty)
1354+
: Expr(CXXInheritedCtorInitExprClass, Empty), Constructor(nullptr),
1355+
ConstructsVirtualBase(false), InheritedFromVirtualBase(false) {}
1356+
1357+
/// \brief Get the constructor that this expression will call.
1358+
CXXConstructorDecl *getConstructor() const { return Constructor; }
1359+
1360+
/// \brief Determine whether this constructor is actually constructing
1361+
/// a base class (rather than a complete object).
1362+
bool constructsVBase() const { return ConstructsVirtualBase; }
1363+
CXXConstructExpr::ConstructionKind getConstructionKind() const {
1364+
return ConstructsVirtualBase ? CXXConstructExpr::CK_VirtualBase
1365+
: CXXConstructExpr::CK_NonVirtualBase;
1366+
}
1367+
1368+
/// \brief Determine whether the inherited constructor is inherited from a
1369+
/// virtual base of the object we construct. If so, we are not responsible
1370+
/// for calling the inherited constructor (the complete object constructor
1371+
/// does that), and so we don't need to pass any arguments.
1372+
bool inheritedFromVBase() const { return InheritedFromVirtualBase; }
1373+
1374+
SourceLocation getLocation() const LLVM_READONLY { return Loc; }
1375+
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
1376+
SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
1377+
1378+
static bool classof(const Stmt *T) {
1379+
return T->getStmtClass() == CXXInheritedCtorInitExprClass;
1380+
}
1381+
child_range children() {
1382+
return child_range(child_iterator(), child_iterator());
1383+
}
1384+
1385+
friend class ASTStmtReader;
1386+
};
1387+
13211388
/// \brief Represents an explicit C++ type conversion that uses "functional"
13221389
/// notation (C++ [expr.type.conv]).
13231390
///

0 commit comments

Comments
 (0)