summaryrefslogtreecommitdiffstats
path: root/lib/AST
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
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')
-rw-r--r--lib/AST/ASTDumper.cpp32
-rw-r--r--lib/AST/DeclBase.cpp1
-rw-r--r--lib/AST/DeclCXX.cpp109
-rw-r--r--lib/AST/Expr.cpp7
-rw-r--r--lib/AST/ExprClassification.cpp1
-rw-r--r--lib/AST/ExprConstant.cpp98
-rw-r--r--lib/AST/ItaniumMangle.cpp48
-rw-r--r--lib/AST/NestedNameSpecifier.cpp13
-rw-r--r--lib/AST/StmtPrinter.cpp5
-rw-r--r--lib/AST/StmtProfile.cpp6
10 files changed, 254 insertions, 66 deletions
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 60420c71fc..872ba356a9 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -474,6 +474,7 @@ namespace {
void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
void VisitUsingShadowDecl(const UsingShadowDecl *D);
+ void VisitConstructorUsingShadowDecl(const ConstructorUsingShadowDecl *D);
void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
void VisitAccessSpecDecl(const AccessSpecDecl *D);
void VisitFriendDecl(const FriendDecl *D);
@@ -713,6 +714,12 @@ void ASTDumper::dumpTypeAsChild(const Type *T) {
}
void ASTDumper::dumpBareDeclRef(const Decl *D) {
+ if (!D) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
{
ColorScope Color(*this, DeclKindNameColor);
OS << D->getDeclKindName();
@@ -1491,6 +1498,31 @@ void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
dumpTypeAsChild(TD->getTypeForDecl());
}
+void ASTDumper::VisitConstructorUsingShadowDecl(
+ const ConstructorUsingShadowDecl *D) {
+ if (D->constructsVirtualBase())
+ OS << " virtual";
+
+ dumpChild([=] {
+ OS << "target ";
+ dumpBareDeclRef(D->getTargetDecl());
+ });
+
+ dumpChild([=] {
+ OS << "nominated ";
+ dumpBareDeclRef(D->getNominatedBaseClass());
+ OS << ' ';
+ dumpBareDeclRef(D->getNominatedBaseClassShadowDecl());
+ });
+
+ dumpChild([=] {
+ OS << "constructed ";
+ dumpBareDeclRef(D->getConstructedBaseClass());
+ OS << ' ';
+ dumpBareDeclRef(D->getConstructedBaseClassShadowDecl());
+ });
+}
+
void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
switch (D->getLanguage()) {
case LinkageSpecDecl::lang_c: OS << " C"; break;
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index f68ca602c2..bfb7d02b29 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -594,6 +594,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Function:
case CXXMethod:
case CXXConstructor:
+ case ConstructorUsingShadow:
case CXXDestructor:
case CXXConversion:
case EnumConstant:
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) {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 5ef6d9d59f..bd4cf396bf 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -3008,6 +3008,13 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
break;
}
+ case CXXInheritedCtorInitExprClass: {
+ const auto *ICIE = cast<CXXInheritedCtorInitExpr>(this);
+ if (!ICIE->getConstructor()->isTrivial() && IncludePossibleEffects)
+ return true;
+ break;
+ }
+
case LambdaExprClass: {
const LambdaExpr *LE = cast<LambdaExpr>(this);
for (LambdaExpr::capture_iterator I = LE->capture_begin(),
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index a47b03c0af..642cdd1a95 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -360,6 +360,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// Some C++ expressions are always class temporaries.
case Expr::CXXConstructExprClass:
+ case Expr::CXXInheritedCtorInitExprClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::LambdaExprClass:
case Expr::CXXStdInitializerListExprClass:
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6771175ba6..e44cb1d23c 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -997,6 +997,16 @@ void EvalInfo::addCallStack(unsigned Limit) {
continue;
}
+ // Use a different note for an inheriting constructor, because from the
+ // user's perspective it's not really a function at all.
+ if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Frame->Callee)) {
+ if (CD->isInheritingConstructor()) {
+ addDiag(Frame->CallLoc, diag::note_constexpr_inherited_ctor_call_here)
+ << CD->getParent();
+ continue;
+ }
+ }
+
SmallVector<char, 128> Buffer;
llvm::raw_svector_ostream Out(Buffer);
describeCall(Frame, Out);
@@ -3845,11 +3855,25 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
if (Info.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
- // FIXME: If DiagDecl is an implicitly-declared special member function, we
- // should be much more explicit about why it's not constexpr.
- Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1)
- << DiagDecl->isConstexpr() << isa<CXXConstructorDecl>(DiagDecl)
- << DiagDecl;
+
+ // If this function is not constexpr because it is an inherited
+ // non-constexpr constructor, diagnose that directly.
+ auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
+ if (CD && CD->isInheritingConstructor()) {
+ auto *Inherited = CD->getInheritedConstructor().getConstructor();
+ if (!Inherited->isConstexpr())
+ DiagDecl = CD = Inherited;
+ }
+
+ // FIXME: If DiagDecl is an implicitly-declared special member function
+ // or an inheriting constructor, we should be much more explicit about why
+ // it's not constexpr.
+ if (CD && CD->isInheritingConstructor())
+ Info.Diag(CallLoc, diag::note_constexpr_invalid_inhctor, 1)
+ << CD->getInheritedConstructor().getConstructor()->getParent();
+ else
+ Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1)
+ << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
} else {
Info.Diag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
@@ -3945,14 +3969,11 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
}
/// Evaluate a constructor call.
-static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
- ArrayRef<const Expr*> Args,
+static bool HandleConstructorCall(const Expr *E, const LValue &This,
+ APValue *ArgValues,
const CXXConstructorDecl *Definition,
EvalInfo &Info, APValue &Result) {
- ArgVector ArgValues(Args.size());
- if (!EvaluateArgs(Args, ArgValues, Info))
- return false;
-
+ SourceLocation CallLoc = E->getExprLoc();
if (!Info.CheckCallLimit(CallLoc))
return false;
@@ -3962,14 +3983,14 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
return false;
}
- CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data());
+ CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
// FIXME: Creating an APValue just to hold a nonexistent return value is
// wasteful.
APValue RetVal;
StmtResult Ret = {RetVal, nullptr};
- // If it's a delegating constructor, just delegate.
+ // If it's a delegating constructor, delegate.
if (Definition->isDelegatingConstructor()) {
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
{
@@ -3993,8 +4014,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
(Definition->isTrivial() && hasFields(Definition->getParent())))) {
LValue RHS;
RHS.setFrom(Info.Ctx, ArgValues[0]);
- return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
- RHS, Result);
+ return handleLValueToRValueConversion(
+ Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(),
+ RHS, Result);
}
// Reserve space for the struct members.
@@ -4088,6 +4110,18 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
}
+static bool HandleConstructorCall(const Expr *E, const LValue &This,
+ ArrayRef<const Expr*> Args,
+ const CXXConstructorDecl *Definition,
+ EvalInfo &Info, APValue &Result) {
+ ArgVector ArgValues(Args.size());
+ if (!EvaluateArgs(Args, ArgValues, Info))
+ return false;
+
+ return HandleConstructorCall(E, This, ArgValues.data(), Definition,
+ Info, Result);
+}
+
//===----------------------------------------------------------------------===//
// Generic Evaluation
//===----------------------------------------------------------------------===//
@@ -5380,6 +5414,7 @@ namespace {
bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
return VisitCXXConstructExpr(E, E->getType());
}
+ bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
};
@@ -5631,7 +5666,29 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return false;
auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
- return HandleConstructorCall(E->getExprLoc(), This, Args,
+ return HandleConstructorCall(E, This, Args,
+ cast<CXXConstructorDecl>(Definition), Info,
+ Result);
+}
+
+bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr(
+ const CXXInheritedCtorInitExpr *E) {
+ if (!Info.CurrentCall) {
+ assert(Info.checkingPotentialConstantExpression());
+ return false;
+ }
+
+ const CXXConstructorDecl *FD = E->getConstructor();
+ if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl())
+ return false;
+
+ const FunctionDecl *Definition = nullptr;
+ auto Body = FD->getBody(Definition);
+
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body))
+ return false;
+
+ return HandleConstructorCall(E, This, Info.CurrentCall->Arguments,
cast<CXXConstructorDecl>(Definition), Info,
Result);
}
@@ -9305,6 +9362,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::TypoExprClass:
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
+ case Expr::CXXInheritedCtorInitExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::CXXBindTemporaryExprClass:
case Expr::ExprWithCleanupsClass:
@@ -9768,17 +9826,17 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
ArrayRef<const Expr*> Args;
- SourceLocation Loc = FD->getLocation();
-
APValue Scratch;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
// Evaluate the call as a constant initializer, to allow the construction
// of objects of non-literal types.
Info.setEvaluatingDecl(This.getLValueBase(), Scratch);
- HandleConstructorCall(Loc, This, Args, CD, Info, Scratch);
- } else
+ HandleConstructorCall(&VIE, This, Args, CD, Info, Scratch);
+ } else {
+ SourceLocation Loc = FD->getLocation();
HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr,
Args, FD->getBody(), Info, Scratch, nullptr);
+ }
return Diags.empty();
}
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index fcce9d2368..8d49c6f586 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -397,7 +397,7 @@ private:
void mangleCastExpression(const Expr *E, StringRef CastEncoding);
void mangleInitListElements(const InitListExpr *InitList);
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
- void mangleCXXCtorType(CXXCtorType T);
+ void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
void mangleCXXDtorType(CXXDtorType T);
void mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs,
@@ -502,6 +502,12 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
FunctionTypeDepth.pop(Saved);
}
+ // When mangling an inheriting constructor, the bare function type used is
+ // that of the inherited constructor.
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
+ if (auto Inherited = CD->getInheritedConstructor())
+ FD = Inherited.getConstructor();
+
// Whether the mangling of a function type includes the return type depends on
// the context and the nature of the function. The rules for deciding whether
// the return type is included are:
@@ -562,7 +568,7 @@ static bool isStdNamespace(const DeclContext *DC) {
static const TemplateDecl *
isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
TemplateArgs = FD->getTemplateSpecializationArgs();
return TD;
@@ -1048,16 +1054,31 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::ObjCMultiArgSelector:
llvm_unreachable("Can't mangle Objective-C selector names here!");
- case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXConstructorName: {
+ const CXXRecordDecl *InheritedFrom = nullptr;
+ const TemplateArgumentList *InheritedTemplateArgs = nullptr;
+ if (auto Inherited =
+ cast<CXXConstructorDecl>(ND)->getInheritedConstructor()) {
+ InheritedFrom = Inherited.getConstructor()->getParent();
+ InheritedTemplateArgs =
+ Inherited.getConstructor()->getTemplateSpecializationArgs();
+ }
+
if (ND == Structor)
// If the named decl is the C++ constructor we're mangling, use the type
// we were given.
- mangleCXXCtorType(static_cast<CXXCtorType>(StructorType));
+ mangleCXXCtorType(static_cast<CXXCtorType>(StructorType), InheritedFrom);
else
// Otherwise, use the complete constructor name. This is relevant if a
// class with a constructor is declared within a constructor.
- mangleCXXCtorType(Ctor_Complete);
+ mangleCXXCtorType(Ctor_Complete, InheritedFrom);
+
+ // FIXME: The template arguments are part of the enclosing prefix or
+ // nested-name, but it's more convenient to mangle them here.
+ if (InheritedTemplateArgs)
+ mangleTemplateArgs(*InheritedTemplateArgs);
break;
+ }
case DeclarationName::CXXDestructorName:
if (ND == Structor)
@@ -2909,6 +2930,7 @@ recurse:
case Expr::MSPropertySubscriptExprClass:
case Expr::TypoExprClass: // This should no longer exist in the AST by now.
case Expr::OMPArraySectionExprClass:
+ case Expr::CXXInheritedCtorInitExprClass:
llvm_unreachable("unexpected statement kind");
// FIXME: invent manglings for all these.
@@ -3688,25 +3710,33 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) {
Out << '_';
}
-void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
+void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
+ const CXXRecordDecl *InheritedFrom) {
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
+ // ::= CI1 <type> # complete inheriting constructor
+ // ::= CI2 <type> # base inheriting constructor
//
// In addition, C5 is a comdat name with C1 and C2 in it.
+ Out << 'C';
+ if (InheritedFrom)
+ Out << 'I';
switch (T) {
case Ctor_Complete:
- Out << "C1";
+ Out << '1';
break;
case Ctor_Base:
- Out << "C2";
+ Out << '2';
break;
case Ctor_Comdat:
- Out << "C5";
+ Out << '5';
break;
case Ctor_DefaultClosure:
case Ctor_CopyingClosure:
llvm_unreachable("closure constructors don't exist for the Itanium ABI!");
}
+ if (InheritedFrom)
+ mangleName(InheritedFrom);
}
void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index ede38626c8..2f38db40d9 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -171,10 +171,19 @@ NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const {
/// \brief Retrieve the record declaration stored in this nested name specifier.
CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const {
- if (Prefix.getInt() == StoredDecl)
+ switch (Prefix.getInt()) {
+ case StoredIdentifier:
+ return nullptr;
+
+ case StoredDecl:
return dyn_cast<CXXRecordDecl>(static_cast<NamedDecl *>(Specifier));
- return nullptr;
+ case StoredTypeSpec:
+ case StoredTypeSpecWithTemplate:
+ return getAsType()->getAsCXXRecordDecl();
+ }
+
+ llvm_unreachable("Invalid NNS Kind!");
}
/// \brief Whether this nested name specifier refers to a dependent
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index a05aef9f2e..9363d169ad 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -2188,6 +2188,11 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
OS << "}";
}
+void StmtPrinter::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) {
+ // Parens are printed by the surrounding context.
+ OS << "<forwarded>";
+}
+
void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
PrintExpr(E->getSubExpr());
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 579e7e8994..c66a077996 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -1287,6 +1287,12 @@ void StmtProfiler::VisitCXXConstructExpr(const CXXConstructExpr *S) {
ID.AddBoolean(S->isElidable());
}
+void StmtProfiler::VisitCXXInheritedCtorInitExpr(
+ const CXXInheritedCtorInitExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getConstructor());
+}
+
void StmtProfiler::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
VisitExplicitCastExpr(S);
}