summaryrefslogtreecommitdiffstats
path: root/lib/AST/DeclCXX.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-06-28 19:03:57 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-06-28 19:03:57 +0000
commit5be817d9f91482faa3e16103ac2d456d06369168 (patch)
tree1c9a1279ea0bbe75aea756b7437ab79c17a24eda /lib/AST/DeclCXX.cpp
parentc982075071e9130f5312885c05fe1f9b3c5233d5 (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.cpp109
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) {