summaryrefslogtreecommitdiffstats
path: root/clang/lib
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
commit5179eb78210a2ad01a18c37b75048ccfe78414ac (patch)
tree194b7981ca2f1dc43a513f016c1374bf1b31aabb /clang/lib
parenta5c7adcb38e89cd23ed3cbbc813d2da2546a9161 (diff)
downloadbcm5719-llvm-5179eb78210a2ad01a18c37b75048ccfe78414ac.tar.gz
bcm5719-llvm-5179eb78210a2ad01a18c37b75048ccfe78414ac.zip
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
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTDumper.cpp32
-rw-r--r--clang/lib/AST/DeclBase.cpp1
-rw-r--r--clang/lib/AST/DeclCXX.cpp109
-rw-r--r--clang/lib/AST/Expr.cpp7
-rw-r--r--clang/lib/AST/ExprClassification.cpp1
-rw-r--r--clang/lib/AST/ExprConstant.cpp98
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp48
-rw-r--r--clang/lib/AST/NestedNameSpecifier.cpp13
-rw-r--r--clang/lib/AST/StmtPrinter.cpp5
-rw-r--r--clang/lib/AST/StmtProfile.cpp6
-rw-r--r--clang/lib/CodeGen/CGCall.cpp24
-rw-r--r--clang/lib/CodeGen/CGClass.cpp216
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp9
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp59
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h83
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp9
-rw-r--r--clang/lib/CodeGen/CodeGenTypes.h5
-rw-r--r--clang/lib/Sema/SemaAccess.cpp26
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp748
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp4
-rw-r--r--clang/lib/Sema/SemaExpr.cpp15
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp5
-rw-r--r--clang/lib/Sema/SemaInit.cpp34
-rw-r--r--clang/lib/Sema/SemaLookup.cpp52
-rw-r--r--clang/lib/Sema/SemaOverload.cpp107
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp58
-rw-r--r--clang/lib/Sema/TreeTransform.h36
-rw-r--r--clang/lib/Serialization/ASTCommon.cpp1
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp38
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp12
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp23
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp9
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp1
35 files changed, 1204 insertions, 692 deletions
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 60420c71fc5..872ba356a9b 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/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/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index f68ca602c29..bfb7d02b295 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/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/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 2a1fac8509e..de06ecb4ca1 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/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/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 5ef6d9d59fa..bd4cf396bfc 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/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/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index a47b03c0afb..642cdd1a959 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/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/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6771175ba6d..e44cb1d23cf 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/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/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index fcce9d23686..8d49c6f586b 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/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/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp
index ede38626c8b..2f38db40d9a 100644
--- a/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/clang/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/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index a05aef9f2ef..9363d169ad0 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/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/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 579e7e89944..c66a077996a 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/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);
}
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index c562602d96b..d683b899022 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -244,6 +244,15 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
return arrangeFreeFunctionType(prototype, MD);
}
+bool CodeGenTypes::inheritingCtorHasParams(
+ const InheritedConstructor &Inherited, CXXCtorType Type) {
+ // Parameters are unnecessary if we're constructing a base class subobject
+ // and the inherited constructor lives in a virtual base.
+ return Type == Ctor_Complete ||
+ !Inherited.getShadowDecl()->constructsVirtualBase() ||
+ !Target.getCXXABI().hasConstructorVariants();
+ }
+
const CGFunctionInfo &
CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
StructorType Type) {
@@ -252,9 +261,16 @@ CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
SmallVector<FunctionProtoType::ExtParameterInfo, 16> paramInfos;
argTypes.push_back(GetThisType(Context, MD->getParent()));
+ bool PassParams = true;
+
GlobalDecl GD;
if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
GD = GlobalDecl(CD, toCXXCtorType(Type));
+
+ // A base class inheriting constructor doesn't get forwarded arguments
+ // needed to construct a virtual base (or base class thereof).
+ if (auto Inherited = CD->getInheritedConstructor())
+ PassParams = inheritingCtorHasParams(Inherited, toCXXCtorType(Type));
} else {
auto *DD = dyn_cast<CXXDestructorDecl>(MD);
GD = GlobalDecl(DD, toCXXDtorType(Type));
@@ -263,12 +279,14 @@ CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
CanQual<FunctionProtoType> FTP = GetFormalType(MD);
// Add the formal parameters.
- appendParameterTypes(*this, argTypes, paramInfos, FTP, MD);
+ if (PassParams)
+ appendParameterTypes(*this, argTypes, paramInfos, FTP, MD);
TheCXXABI.buildStructorSignature(MD, Type, argTypes);
RequiredArgs required =
- (MD->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All);
+ (PassParams && MD->isVariadic() ? RequiredArgs(argTypes.size())
+ : RequiredArgs::All);
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
CanQualType resultType = TheCXXABI.HasThisReturn(GD)
@@ -3186,10 +3204,10 @@ void CodeGenFunction::EmitCallArgs(
size_t CallArgsStart = Args.size();
for (int I = ArgTypes.size() - 1; I >= 0; --I) {
CallExpr::const_arg_iterator Arg = ArgRange.begin() + I;
+ MaybeEmitImplicitObjectSize(I, *Arg);
EmitCallArg(Args, *Arg, ArgTypes[I]);
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], (*Arg)->getExprLoc(),
CalleeDecl, ParamsToSkip + I);
- MaybeEmitImplicitObjectSize(I, *Arg);
}
// Un-reverse the arguments we just evaluated so they match up with the LLVM
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 56e24840c82..7ed891f426a 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2048,6 +2048,62 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
bool ForVirtualBase,
bool Delegating, Address This,
const CXXConstructExpr *E) {
+ CallArgList Args;
+
+ // Push the this ptr.
+ Args.add(RValue::get(This.getPointer()), D->getThisType(getContext()));
+
+ // If this is a trivial constructor, emit a memcpy now before we lose
+ // the alignment information on the argument.
+ // FIXME: It would be better to preserve alignment information into CallArg.
+ if (isMemcpyEquivalentSpecialMember(D)) {
+ assert(E->getNumArgs() == 1 && "unexpected argcount for trivial ctor");
+
+ const Expr *Arg = E->getArg(0);
+ QualType SrcTy = Arg->getType();
+ Address Src = EmitLValue(Arg).getAddress();
+ QualType DestTy = getContext().getTypeDeclType(D->getParent());
+ EmitAggregateCopyCtor(This, Src, DestTy, SrcTy);
+ return;
+ }
+
+ // Add the rest of the user-supplied arguments.
+ const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
+ EmitCallArgs(Args, FPT, E->arguments(), E->getConstructor());
+
+ EmitCXXConstructorCall(D, Type, ForVirtualBase, Delegating, This, Args);
+}
+
+static bool canEmitDelegateCallArgs(CodeGenFunction &CGF,
+ const CXXConstructorDecl *Ctor,
+ CXXCtorType Type, CallArgList &Args) {
+ // We can't forward a variadic call.
+ if (Ctor->isVariadic())
+ return false;
+
+ if (CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ // If the parameters are callee-cleanup, it's not safe to forward.
+ for (auto *P : Ctor->parameters())
+ if (P->getType().isDestructedType())
+ return false;
+
+ // Likewise if they're inalloca.
+ const CGFunctionInfo &Info =
+ CGF.CGM.getTypes().arrangeCXXConstructorCall(Args, Ctor, Type, 0);
+ if (Info.usesInAlloca())
+ return false;
+ }
+
+ // Anything else should be OK.
+ return true;
+}
+
+void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ bool ForVirtualBase,
+ bool Delegating,
+ Address This,
+ CallArgList &Args) {
const CXXRecordDecl *ClassDecl = D->getParent();
// C++11 [class.mfct.non-static]p2:
@@ -2058,7 +2114,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
This.getPointer(), getContext().getRecordType(ClassDecl));
if (D->isTrivial() && D->isDefaultConstructor()) {
- assert(E->getNumArgs() == 0 && "trivial default ctor with args");
+ assert(Args.size() == 1 && "trivial default ctor with args");
return;
}
@@ -2066,24 +2122,24 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
// union copy constructor, we must emit a memcpy, because the AST does not
// model that copy.
if (isMemcpyEquivalentSpecialMember(D)) {
- assert(E->getNumArgs() == 1 && "unexpected argcount for trivial ctor");
+ assert(Args.size() == 2 && "unexpected argcount for trivial ctor");
- const Expr *Arg = E->getArg(0);
- QualType SrcTy = Arg->getType();
- Address Src = EmitLValue(Arg).getAddress();
+ QualType SrcTy = D->getParamDecl(0)->getType().getNonReferenceType();
+ Address Src(Args[1].RV.getScalarVal(), getNaturalTypeAlignment(SrcTy));
QualType DestTy = getContext().getTypeDeclType(ClassDecl);
EmitAggregateCopyCtor(This, Src, DestTy, SrcTy);
return;
}
- CallArgList Args;
-
- // Push the this ptr.
- Args.add(RValue::get(This.getPointer()), D->getThisType(getContext()));
-
- // Add the rest of the user-supplied arguments.
- const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
- EmitCallArgs(Args, FPT, E->arguments(), E->getConstructor());
+ // Check whether we can actually emit the constructor before trying to do so.
+ if (auto Inherited = D->getInheritedConstructor()) {
+ if (getTypes().inheritingCtorHasParams(Inherited, Type) &&
+ !canEmitDelegateCallArgs(*this, D, Type, Args)) {
+ EmitInlinedInheritingCXXConstructorCall(D, Type, ForVirtualBase,
+ Delegating, Args);
+ return;
+ }
+ }
// Insert any ABI-specific implicit constructor arguments.
unsigned ExtraArgs = CGM.getCXXABI().addImplicitConstructorArgs(
@@ -2113,6 +2169,95 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
EmitVTableAssumptionLoads(ClassDecl, This);
}
+void CodeGenFunction::EmitInheritedCXXConstructorCall(
+ const CXXConstructorDecl *D, bool ForVirtualBase, Address This,
+ bool InheritedFromVBase, const CXXInheritedCtorInitExpr *E) {
+ CallArgList Args;
+ CallArg ThisArg(RValue::get(This.getPointer()), D->getThisType(getContext()),
+ /*NeedsCopy=*/false);
+
+ // Forward the parameters.
+ if (InheritedFromVBase &&
+ CGM.getTarget().getCXXABI().hasConstructorVariants()) {
+ // Nothing to do; this construction is not responsible for constructing
+ // the base class containing the inherited constructor.
+ // FIXME: Can we just pass undef's for the remaining arguments if we don't
+ // have constructor variants?
+ Args.push_back(ThisArg);
+ } else if (!CXXInheritedCtorInitExprArgs.empty()) {
+ // The inheriting constructor was inlined; just inject its arguments.
+ assert(CXXInheritedCtorInitExprArgs.size() >= D->getNumParams() &&
+ "wrong number of parameters for inherited constructor call");
+ Args = CXXInheritedCtorInitExprArgs;
+ Args[0] = ThisArg;
+ } else {
+ // The inheriting constructor was not inlined. Emit delegating arguments.
+ Args.push_back(ThisArg);
+ const auto *OuterCtor = cast<CXXConstructorDecl>(CurCodeDecl);
+ assert(OuterCtor->getNumParams() == D->getNumParams());
+ assert(!OuterCtor->isVariadic() && "should have been inlined");
+
+ for (const auto *Param : OuterCtor->parameters()) {
+ assert(getContext().hasSameUnqualifiedType(
+ OuterCtor->getParamDecl(Param->getFunctionScopeIndex())->getType(),
+ Param->getType()));
+ EmitDelegateCallArg(Args, Param, E->getLocation());
+
+ // Forward __attribute__(pass_object_size).
+ if (Param->hasAttr<PassObjectSizeAttr>()) {
+ auto *POSParam = SizeArguments[Param];
+ assert(POSParam && "missing pass_object_size value for forwarding");
+ EmitDelegateCallArg(Args, POSParam, E->getLocation());
+ }
+ }
+ }
+
+ EmitCXXConstructorCall(D, Ctor_Base, ForVirtualBase, /*Delegating*/false,
+ This, Args);
+}
+
+void CodeGenFunction::EmitInlinedInheritingCXXConstructorCall(
+ const CXXConstructorDecl *Ctor, CXXCtorType CtorType, bool ForVirtualBase,
+ bool Delegating, CallArgList &Args) {
+ InlinedInheritingConstructorScope Scope(*this, GlobalDecl(Ctor, CtorType));
+
+ // Save the arguments to be passed to the inherited constructor.
+ CXXInheritedCtorInitExprArgs = Args;
+
+ FunctionArgList Params;
+ QualType RetType = BuildFunctionArgList(CurGD, Params);
+ FnRetTy = RetType;
+
+ // Insert any ABI-specific implicit constructor arguments.
+ CGM.getCXXABI().addImplicitConstructorArgs(*this, Ctor, CtorType,
+ ForVirtualBase, Delegating, Args);
+
+ // Emit a simplified prolog. We only need to emit the implicit params.
+ assert(Args.size() >= Params.size() && "too few arguments for call");
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ if (I < Params.size() && isa<ImplicitParamDecl>(Params[I])) {
+ const RValue &RV = Args[I].RV;
+ assert(!RV.isComplex() && "complex indirect params not supported");
+ ParamValue Val = RV.isScalar()
+ ? ParamValue::forDirect(RV.getScalarVal())
+ : ParamValue::forIndirect(RV.getAggregateAddress());
+ EmitParmDecl(*Params[I], Val, I + 1);
+ }
+ }
+
+ // Create a return value slot if the ABI implementation wants one.
+ // FIXME: This is dumb, we should ask the ABI not to try to set the return
+ // value instead.
+ if (!RetType->isVoidType())
+ ReturnValue = CreateIRTemp(RetType, "retval.inhctor");
+
+ CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
+ CXXThisValue = CXXABIThisValue;
+
+ // Directly emit the constructor initializers.
+ EmitCtorPrologue(Ctor, CtorType, Params);
+}
+
void CodeGenFunction::EmitVTableAssumptionLoad(const VPtr &Vptr, Address This) {
llvm::Value *VTableGlobal =
CGM.getCXXABI().getVTableAddressPoint(Vptr.Base, Vptr.VTableClass);
@@ -2145,19 +2290,6 @@ void
CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
Address This, Address Src,
const CXXConstructExpr *E) {
- if (isMemcpyEquivalentSpecialMember(D)) {
- assert(E->getNumArgs() == 1 && "unexpected argcount for trivial ctor");
- assert(D->isCopyOrMoveConstructor() &&
- "trivial 1-arg ctor not a copy/move ctor");
- EmitAggregateCopyCtor(This, Src,
- getContext().getTypeDeclType(D->getParent()),
- (*E->arg_begin())->getType());
- return;
- }
- llvm::Value *Callee = CGM.getAddrOfCXXStructor(D, StructorType::Complete);
- assert(D->isInstance() &&
- "Trying to emit a member call expr on a static method!");
-
const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
CallArgList Args;
@@ -2175,8 +2307,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
EmitCallArgs(Args, FPT, drop_begin(E->arguments(), 1), E->getConstructor(),
/*ParamsToSkip*/ 1);
- EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, RequiredArgs::All),
- Callee, ReturnValueSlot(), Args, D);
+ EmitCXXConstructorCall(D, Ctor_Complete, false, false, This, Args);
}
void
@@ -2190,21 +2321,17 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
assert(I != E && "no parameters to constructor");
// this
- DelegateArgs.add(RValue::get(LoadCXXThis()), (*I)->getType());
+ Address This = LoadCXXThisAddress();
+ DelegateArgs.add(RValue::get(This.getPointer()), (*I)->getType());
++I;
- // vtt
- if (llvm::Value *VTT = GetVTTParameter(GlobalDecl(Ctor, CtorType),
- /*ForVirtualBase=*/false,
- /*Delegating=*/true)) {
- QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
- DelegateArgs.add(RValue::get(VTT), VoidPP);
-
- if (CGM.getCXXABI().NeedsVTTParameter(CurGD)) {
- assert(I != E && "cannot skip vtt parameter, already done with args");
- assert((*I)->getType() == VoidPP && "skipping parameter not of vtt type");
- ++I;
- }
+ // FIXME: The location of the VTT parameter in the parameter list is
+ // specific to the Itanium ABI and shouldn't be hardcoded here.
+ if (CGM.getCXXABI().NeedsVTTParameter(CurGD)) {
+ assert(I != E && "cannot skip vtt parameter, already done with args");
+ assert((*I)->getType()->isPointerType() &&
+ "skipping parameter not of vtt type");
+ ++I;
}
// Explicit arguments.
@@ -2214,11 +2341,8 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param, Loc);
}
- llvm::Value *Callee =
- CGM.getAddrOfCXXStructor(Ctor, getFromCtorType(CtorType));
- EmitCall(CGM.getTypes()
- .arrangeCXXStructorDeclaration(Ctor, getFromCtorType(CtorType)),
- Callee, ReturnValueSlot(), DelegateArgs, Ctor);
+ EmitCXXConstructorCall(Ctor, CtorType, /*ForVirtualBase=*/false,
+ /*Delegating=*/true, This, DelegateArgs);
}
namespace {
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 83730597939..508720f5b9a 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -85,6 +85,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Captured:
case Decl::ClassScopeFunctionSpecialization:
case Decl::UsingShadow:
+ case Decl::ConstructorUsingShadow:
case Decl::ObjCTypeParam:
llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Function: // void X();
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 42aa94575a7..6d18843591f 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -175,6 +175,7 @@ public:
}
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
void VisitCXXConstructExpr(const CXXConstructExpr *E);
+ void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
void VisitLambdaExpr(LambdaExpr *E);
void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E);
void VisitExprWithCleanups(ExprWithCleanups *E);
@@ -998,6 +999,14 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
CGF.EmitCXXConstructExpr(E, Slot);
}
+void AggExprEmitter::VisitCXXInheritedCtorInitExpr(
+ const CXXInheritedCtorInitExpr *E) {
+ AggValueSlot Slot = EnsureSlot(E->getType());
+ CGF.EmitInheritedCXXConstructorCall(
+ E->getConstructor(), E->constructsVBase(), Slot.getAddress(),
+ E->inheritedFromVBase(), E);
+}
+
void
AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
AggValueSlot Slot = EnsureSlot(E->getType());
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index e914d793559..a0158d8b4b2 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -928,18 +928,11 @@ static void TryMarkNoThrow(llvm::Function *F) {
F->setDoesNotThrow();
}
-void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
- const CGFunctionInfo &FnInfo) {
+QualType CodeGenFunction::BuildFunctionArgList(GlobalDecl GD,
+ FunctionArgList &Args) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
-
- // Check if we should generate debug info for this function.
- if (FD->hasAttr<NoDebugAttr>())
- DebugInfo = nullptr; // disable debug info indefinitely for this function
-
- FunctionArgList Args;
QualType ResTy = FD->getReturnType();
- CurGD = GD;
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
if (MD && MD->isInstance()) {
if (CGM.getCXXABI().HasThisReturn(GD))
@@ -949,22 +942,48 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
CGM.getCXXABI().buildThisParam(*this, Args);
}
- for (auto *Param : FD->parameters()) {
- Args.push_back(Param);
- if (!Param->hasAttr<PassObjectSizeAttr>())
- continue;
-
- IdentifierInfo *NoID = nullptr;
- auto *Implicit = ImplicitParamDecl::Create(
- getContext(), Param->getDeclContext(), Param->getLocation(), NoID,
- getContext().getSizeType());
- SizeArguments[Param] = Implicit;
- Args.push_back(Implicit);
+ // The base version of an inheriting constructor whose constructed base is a
+ // virtual base is not passed any arguments (because it doesn't actually call
+ // the inherited constructor).
+ bool PassedParams = true;
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+ if (auto Inherited = CD->getInheritedConstructor())
+ PassedParams =
+ getTypes().inheritingCtorHasParams(Inherited, GD.getCtorType());
+
+ if (PassedParams) {
+ for (auto *Param : FD->parameters()) {
+ Args.push_back(Param);
+ if (!Param->hasAttr<PassObjectSizeAttr>())
+ continue;
+
+ IdentifierInfo *NoID = nullptr;
+ auto *Implicit = ImplicitParamDecl::Create(
+ getContext(), Param->getDeclContext(), Param->getLocation(), NoID,
+ getContext().getSizeType());
+ SizeArguments[Param] = Implicit;
+ Args.push_back(Implicit);
+ }
}
if (MD && (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)))
CGM.getCXXABI().addImplicitStructorParams(*this, ResTy, Args);
+ return ResTy;
+}
+
+void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo) {
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+ CurGD = GD;
+
+ FunctionArgList Args;
+ QualType ResTy = BuildFunctionArgList(GD, Args);
+
+ // Check if we should generate debug info for this function.
+ if (FD->hasAttr<NoDebugAttr>())
+ DebugInfo = nullptr; // disable debug info indefinitely for this function
+
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
CurEHLocation = BodyRange.getEnd();
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 4748e6b47dc..441cee54fc1 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1065,6 +1065,61 @@ public:
CharUnits OldCXXThisAlignment;
};
+ class InlinedInheritingConstructorScope {
+ public:
+ InlinedInheritingConstructorScope(CodeGenFunction &CGF, GlobalDecl GD)
+ : CGF(CGF), OldCurGD(CGF.CurGD), OldCurFuncDecl(CGF.CurFuncDecl),
+ OldCurCodeDecl(CGF.CurCodeDecl),
+ OldCXXABIThisDecl(CGF.CXXABIThisDecl),
+ OldCXXABIThisValue(CGF.CXXABIThisValue),
+ OldCXXThisValue(CGF.CXXThisValue),
+ OldCXXABIThisAlignment(CGF.CXXABIThisAlignment),
+ OldCXXThisAlignment(CGF.CXXThisAlignment),
+ OldReturnValue(CGF.ReturnValue), OldFnRetTy(CGF.FnRetTy),
+ OldCXXInheritedCtorInitExprArgs(
+ std::move(CGF.CXXInheritedCtorInitExprArgs)) {
+ CGF.CurGD = GD;
+ CGF.CurFuncDecl = CGF.CurCodeDecl =
+ cast<CXXConstructorDecl>(GD.getDecl());
+ CGF.CXXABIThisDecl = nullptr;
+ CGF.CXXABIThisValue = nullptr;
+ CGF.CXXThisValue = nullptr;
+ CGF.CXXABIThisAlignment = CharUnits();
+ CGF.CXXThisAlignment = CharUnits();
+ CGF.ReturnValue = Address::invalid();
+ CGF.FnRetTy = QualType();
+ CGF.CXXInheritedCtorInitExprArgs.clear();
+ }
+ ~InlinedInheritingConstructorScope() {
+ CGF.CurGD = OldCurGD;
+ CGF.CurFuncDecl = OldCurFuncDecl;
+ CGF.CurCodeDecl = OldCurCodeDecl;
+ CGF.CXXABIThisDecl = OldCXXABIThisDecl;
+ CGF.CXXABIThisValue = OldCXXABIThisValue;
+ CGF.CXXThisValue = OldCXXThisValue;
+ CGF.CXXABIThisAlignment = OldCXXABIThisAlignment;
+ CGF.CXXThisAlignment = OldCXXThisAlignment;
+ CGF.ReturnValue = OldReturnValue;
+ CGF.FnRetTy = OldFnRetTy;
+ CGF.CXXInheritedCtorInitExprArgs =
+ std::move(OldCXXInheritedCtorInitExprArgs);
+ }
+
+ private:
+ CodeGenFunction &CGF;
+ GlobalDecl OldCurGD;
+ const Decl *OldCurFuncDecl;
+ const Decl *OldCurCodeDecl;
+ ImplicitParamDecl *OldCXXABIThisDecl;
+ llvm::Value *OldCXXABIThisValue;
+ llvm::Value *OldCXXThisValue;
+ CharUnits OldCXXABIThisAlignment;
+ CharUnits OldCXXThisAlignment;
+ Address OldReturnValue;
+ QualType OldFnRetTy;
+ CallArgList OldCXXInheritedCtorInitExprArgs;
+ };
+
private:
/// CXXThisDecl - When generating code for a C++ member function,
/// this will hold the implicit 'this' declaration.
@@ -1078,6 +1133,10 @@ private:
/// this expression.
Address CXXDefaultInitExprThis = Address::invalid();
+ /// The values of function arguments to use when evaluating
+ /// CXXInheritedCtorInitExprs within this context.
+ CallArgList CXXInheritedCtorInitExprArgs;
+
/// CXXStructorImplicitParamDecl - When generating code for a constructor or
/// destructor, this will hold the implicit argument (e.g. VTT).
ImplicitParamDecl *CXXStructorImplicitParamDecl;
@@ -1301,6 +1360,8 @@ public:
const BlockByrefInfo &getBlockByrefInfo(const VarDecl *var);
+ QualType BuildFunctionArgList(GlobalDecl GD, FunctionArgList &Args);
+
void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo);
/// \brief Emit code for the start of a function.
@@ -1874,10 +1935,32 @@ public:
void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
const FunctionArgList &Args);
+ /// Emit a call to an inheriting constructor (that is, one that invokes a
+ /// constructor inherited from a base class) by inlining its definition. This
+ /// is necessary if the ABI does not support forwarding the arguments to the
+ /// base class constructor (because they're variadic or similar).
+ void EmitInlinedInheritingCXXConstructorCall(const CXXConstructorDecl *Ctor,
+ CXXCtorType CtorType,
+ bool ForVirtualBase,
+ bool Delegating,
+ CallArgList &Args);
+
+ /// Emit a call to a constructor inherited from a base class, passing the
+ /// current constructor's arguments along unmodified (without even making
+ /// a copy).
+ void EmitInheritedCXXConstructorCall(const CXXConstructorDecl *D,
+ bool ForVirtualBase, Address This,
+ bool InheritedFromVBase,
+ const CXXInheritedCtorInitExpr *E);
+
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
bool ForVirtualBase, bool Delegating,
Address This, const CXXConstructExpr *E);
+ void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
+ Address This, CallArgList &Args);
+
/// Emit assumption load for all bases. Requires to be be called only on
/// most-derived class and not under construction of the object.
void EmitVTableAssumptionLoads(const CXXRecordDecl *ClassDecl, Address This);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index ac00bf85cd3..bbec03842cb 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -765,6 +765,15 @@ CodeGenModule::getFunctionLinkage(GlobalDecl GD) {
: llvm::GlobalValue::LinkOnceODRLinkage;
}
+ if (isa<CXXConstructorDecl>(D) &&
+ cast<CXXConstructorDecl>(D)->isInheritingConstructor() &&
+ Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // Our approach to inheriting constructors is fundamentally different from
+ // that used by the MS ABI, so keep our inheriting constructor thunks
+ // internal rather than trying to pick an unambiguous mangling for them.
+ return llvm::GlobalValue::InternalLinkage;
+ }
+
return getLLVMLinkageForDeclarator(D, Linkage, /*isConstantVariable=*/false);
}
diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h
index c77790100a8..affa3344103 100644
--- a/clang/lib/CodeGen/CodeGenTypes.h
+++ b/clang/lib/CodeGen/CodeGenTypes.h
@@ -205,6 +205,11 @@ public:
bool isFuncTypeConvertible(const FunctionType *FT);
bool isFuncParamTypeConvertible(QualType Ty);
+ /// Determine if a C++ inheriting constructor should have parameters matching
+ /// those of its inherited constructor.
+ bool inheritingCtorHasParams(const InheritedConstructor &Inherited,
+ CXXCtorType Type);
+
/// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable,
/// given a CXXMethodDecl. If the method to has an incomplete return type,
/// and/or incomplete argument types, this will return the opaque type.
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index d9eec8ebc62..98a918bd7d6 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1610,10 +1610,10 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
+ DeclAccessPair Found,
const InitializedEntity &Entity,
- AccessSpecifier Access,
bool IsCopyBindingRefToTemp) {
- if (!getLangOpts().AccessControl || Access == AS_public)
+ if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
return AR_accessible;
PartialDiagnostic PD(PDiag());
@@ -1647,17 +1647,17 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
}
- return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD);
+ return CheckConstructorAccess(UseLoc, Constructor, Found, Entity, PD);
}
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
+ DeclAccessPair Found,
const InitializedEntity &Entity,
- AccessSpecifier Access,
const PartialDiagnostic &PD) {
if (!getLangOpts().AccessControl ||
- Access == AS_public)
+ Found.getAccess() == AS_public)
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
@@ -1670,15 +1670,23 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
// in aggregate initialization. It's not clear whether the object class
// should be the base class or the derived class in that case.
CXXRecordDecl *ObjectClass;
- if (Entity.getKind() == InitializedEntity::EK_Base && !Entity.getParent()) {
+ if ((Entity.getKind() == InitializedEntity::EK_Base ||
+ Entity.getKind() == InitializedEntity::EK_Delegating) &&
+ !Entity.getParent()) {
ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent();
+ } else if (auto *Shadow =
+ dyn_cast<ConstructorUsingShadowDecl>(Found.getDecl())) {
+ // If we're using an inheriting constructor to construct an object,
+ // the object class is the derived class, not the base class.
+ ObjectClass = Shadow->getParent();
} else {
ObjectClass = NamingClass;
}
- AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
- DeclAccessPair::make(Constructor, Access),
- Context.getTypeDeclType(ObjectClass));
+ AccessTarget AccessEntity(
+ Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Constructor, Found.getAccess()),
+ Context.getTypeDeclType(ObjectClass));
AccessEntity.setDiag(PD);
return CheckAccess(*this, UseLoc, AccessEntity);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index b0f3356e1c7..a5d636e95eb 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -3356,34 +3356,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ExprResult BaseInit;
switch (ImplicitInitKind) {
- case IIK_Inherit: {
- const CXXRecordDecl *Inherited =
- Constructor->getInheritedConstructor()->getParent();
- const CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl();
- if (Base && Inherited->getCanonicalDecl() == Base->getCanonicalDecl()) {
- // C++11 [class.inhctor]p8:
- // Each expression in the expression-list is of the form
- // static_cast<T&&>(p), where p is the name of the corresponding
- // constructor parameter and T is the declared type of p.
- SmallVector<Expr*, 16> Args;
- for (unsigned I = 0, E = Constructor->getNumParams(); I != E; ++I) {
- ParmVarDecl *PD = Constructor->getParamDecl(I);
- ExprResult ArgExpr =
- SemaRef.BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(),
- VK_LValue, SourceLocation());
- if (ArgExpr.isInvalid())
- return true;
- Args.push_back(CastForMoving(SemaRef, ArgExpr.get(), PD->getType()));
- }
-
- InitializationKind InitKind = InitializationKind::CreateDirect(
- Constructor->getLocation(), SourceLocation(), SourceLocation());
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, Args);
- BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args);
- break;
- }
- }
- // Fall through.
+ case IIK_Inherit:
case IIK_Default: {
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
@@ -3694,12 +3667,12 @@ struct BaseAndFieldInfo {
BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits)
: S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) {
bool Generated = Ctor->isImplicit() || Ctor->isDefaulted();
- if (Generated && Ctor->isCopyConstructor())
+ if (Ctor->getInheritedConstructor())
+ IIK = IIK_Inherit;
+ else if (Generated && Ctor->isCopyConstructor())
IIK = IIK_Copy;
else if (Generated && Ctor->isMoveConstructor())
IIK = IIK_Move;
- else if (Ctor->getInheritedConstructor())
- IIK = IIK_Inherit;
else
IIK = IIK_Default;
}
@@ -5065,15 +5038,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
Diag(Record->getLocation(), diag::warn_cxx_ms_struct);
}
- // Declare inheriting constructors. We do this eagerly here because:
- // - The standard requires an eager diagnostic for conflicting inheriting
- // constructors from different classes.
- // - The lazy declaration of the other implicit constructors is so as to not
- // waste space and performance on classes that are not meant to be
- // instantiated (e.g. meta-functions). This doesn't apply to classes that
- // have inheriting constructors.
- DeclareInheritingConstructors(Record);
-
checkClassLevelDLLAttribute(Record);
}
@@ -5107,11 +5071,110 @@ static Sema::SpecialMemberOverloadResult *lookupCallFromSpecialMember(
LHSQuals & Qualifiers::Volatile);
}
+namespace {
+struct InheritedConstructorInfo {
+ Sema &S;
+ SourceLocation UseLoc;
+ ConstructorUsingShadowDecl *Shadow;
+
+ /// A mapping from the base classes through which the constructor was
+ /// inherited to the using shadow declaration in that base class (or a null
+ /// pointer if the constructor was declared in that base class).
+ llvm::DenseMap<CXXRecordDecl *, ConstructorUsingShadowDecl *>
+ InheritedFromBases;
+
+ InheritedConstructorInfo(Sema &S, SourceLocation UseLoc,
+ ConstructorUsingShadowDecl *Shadow)
+ : S(S), UseLoc(UseLoc), Shadow(Shadow) {
+ bool DiagnosedMultipleConstructedBases = false;
+ CXXRecordDecl *ConstructedBase = nullptr;
+ UsingDecl *ConstructedBaseUsing = nullptr;
+
+ // Find the set of such base class subobjects and check that there's a
+ // unique constructed subobject.
+ for (auto *D : Shadow->redecls()) {
+ auto *DShadow = cast<ConstructorUsingShadowDecl>(D);
+ auto *DNominatedBase = DShadow->getNominatedBaseClass();
+ auto *DConstructedBase = DShadow->getConstructedBaseClass();
+
+ InheritedFromBases.insert(
+ std::make_pair(DNominatedBase->getCanonicalDecl(),
+ DShadow->getNominatedBaseClassShadowDecl()));
+ if (DShadow->constructsVirtualBase())
+ InheritedFromBases.insert(
+ std::make_pair(DConstructedBase->getCanonicalDecl(),
+ DShadow->getConstructedBaseClassShadowDecl()));
+ else
+ assert(DNominatedBase == DConstructedBase);
+
+ // [class.inhctor.init]p2:
+ // If the constructor was inherited from multiple base class subobjects
+ // of type B, the program is ill-formed.
+ if (!ConstructedBase) {
+ ConstructedBase = DConstructedBase;
+ ConstructedBaseUsing = D->getUsingDecl();
+ } else if (ConstructedBase != DConstructedBase &&
+ !Shadow->isInvalidDecl()) {
+ if (!DiagnosedMultipleConstructedBases) {
+ S.Diag(UseLoc, diag::err_ambiguous_inherited_constructor)
+ << Shadow->getTargetDecl();
+ S.Diag(ConstructedBaseUsing->getLocation(),
+ diag::note_ambiguous_inherited_constructor_using)
+ << ConstructedBase;
+ DiagnosedMultipleConstructedBases = true;
+ }
+ S.Diag(D->getUsingDecl()->getLocation(),
+ diag::note_ambiguous_inherited_constructor_using)
+ << DConstructedBase;
+ }
+ }
+
+ if (DiagnosedMultipleConstructedBases)
+ Shadow->setInvalidDecl();
+ }
+
+ /// Find the constructor to use for inherited construction of a base class,
+ /// and whether that base class constructor inherits the constructor from a
+ /// virtual base class (in which case it won't actually invoke it).
+ std::pair<CXXConstructorDecl *, bool>
+ findConstructorForBase(CXXRecordDecl *Base, CXXConstructorDecl *Ctor) const {
+ auto It = InheritedFromBases.find(Base->getCanonicalDecl());
+ if (It == InheritedFromBases.end())
+ return std::make_pair(nullptr, false);
+
+ // This is an intermediary class.
+ if (It->second)
+ return std::make_pair(
+ S.findInheritingConstructor(UseLoc, Ctor, It->second),
+ It->second->constructsVirtualBase());
+
+ // This is the base class from which the constructor was inherited.
+ return std::make_pair(Ctor, false);
+ }
+};
+}
+
/// Is the special member function which would be selected to perform the
/// specified operation on the specified class type a constexpr constructor?
-static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
- Sema::CXXSpecialMember CSM,
- unsigned Quals, bool ConstRHS) {
+static bool
+specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
+ Sema::CXXSpecialMember CSM, unsigned Quals,
+ bool ConstRHS,
+ CXXConstructorDecl *InheritedCtor = nullptr,
+ InheritedConstructorInfo *Inherited = nullptr) {
+ // If we're inheriting a constructor, see if we need to call it for this base
+ // class.
+ if (InheritedCtor) {
+ assert(CSM == Sema::CXXDefaultConstructor);
+ auto BaseCtor =
+ Inherited->findConstructorForBase(ClassDecl, InheritedCtor).first;
+ if (BaseCtor)
+ return BaseCtor->isConstexpr();
+ }
+
+ if (CSM == Sema::CXXDefaultConstructor)
+ return ClassDecl->hasConstexprDefaultConstructor();
+
Sema::SpecialMemberOverloadResult *SMOR =
lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS);
if (!SMOR || !SMOR->getMethod())
@@ -5123,9 +5186,10 @@ static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
/// Determine whether the specified special member function would be constexpr
/// if it were implicitly defined.
-static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
- Sema::CXXSpecialMember CSM,
- bool ConstArg) {
+static bool defaultedSpecialMemberIsConstexpr(
+ Sema &S, CXXRecordDecl *ClassDecl, Sema::CXXSpecialMember CSM,
+ bool ConstArg, CXXConstructorDecl *InheritedCtor = nullptr,
+ InheritedConstructorInfo *Inherited = nullptr) {
if (!S.getLangOpts().CPlusPlus11)
return false;
@@ -5134,6 +5198,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
bool Ctor = true;
switch (CSM) {
case Sema::CXXDefaultConstructor:
+ if (Inherited)
+ break;
// Since default constructor lookup is essentially trivial (and cannot
// involve, for instance, template instantiation), we compute whether a
// defaulted default constructor is constexpr directly within CXXRecordDecl.
@@ -5168,7 +5234,10 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
// will be initialized (if the constructor isn't deleted), we just don't know
// which one.
if (Ctor && ClassDecl->isUnion())
- return true;
+ return CSM == Sema::CXXDefaultConstructor
+ ? ClassDecl->hasInClassInitializer() ||
+ !ClassDecl->hasVariantMembers()
+ : true;
// -- the class shall not have any virtual base classes;
if (Ctor && ClassDecl->getNumVBases())
@@ -5188,7 +5257,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
if (!BaseType) continue;
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg))
+ if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg,
+ InheritedCtor, Inherited))
return false;
}
@@ -5202,6 +5272,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
for (const auto *F : ClassDecl->fields()) {
if (F->isInvalidDecl())
continue;
+ if (CSM == Sema::CXXDefaultConstructor && F->hasInClassInitializer())
+ continue;
QualType BaseType = S.Context.getBaseElementType(F->getType());
if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -5209,6 +5281,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
BaseType.getCVRQualifiers(),
ConstArg && !F->isMutable()))
return false;
+ } else if (CSM == Sema::CXXDefaultConstructor) {
+ return false;
}
}
@@ -5236,7 +5310,8 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
}
assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
"only special members have implicit exception specs");
- return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
+ return S.ComputeInheritingCtorExceptionSpec(Loc,
+ cast<CXXConstructorDecl>(MD));
}
static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
@@ -6501,14 +6576,12 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
- if (!ClassDecl->hasUserDeclaredConstructor())
+ if (ClassDecl->needsImplicitDefaultConstructor()) {
++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->hasInheritedConstructor())
+ DeclareImplicitDefaultConstructor(ClassDecl);
+ }
if (ClassDecl->needsImplicitCopyConstructor()) {
++ASTContext::NumImplicitCopyConstructors;
@@ -7928,12 +8001,21 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
return true;
}
+/// Determine whether a direct base class is a virtual base class.
+static bool isVirtualDirectBase(CXXRecordDecl *Derived, CXXRecordDecl *Base) {
+ if (!Derived->getNumVBases())
+ return false;
+ for (auto &B : Derived->bases())
+ if (B.getType()->getAsCXXRecordDecl() == Base)
+ return B.isVirtual();
+ llvm_unreachable("not a direct base class");
+}
+
/// Builds a shadow declaration corresponding to a 'using' declaration.
UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
UsingDecl *UD,
NamedDecl *Orig,
UsingShadowDecl *PrevDecl) {
-
// If we resolved to another shadow declaration, just coalesce them.
NamedDecl *Target = Orig;
if (isa<UsingShadowDecl>(Target)) {
@@ -7941,9 +8023,21 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration");
}
- UsingShadowDecl *Shadow
- = UsingShadowDecl::Create(Context, CurContext,
- UD->getLocation(), UD, Target);
+ NamedDecl *NonTemplateTarget = Target;
+ if (auto *TargetTD = dyn_cast<TemplateDecl>(Target))
+ NonTemplateTarget = TargetTD->getTemplatedDecl();
+
+ UsingShadowDecl *Shadow;
+ if (isa<CXXConstructorDecl>(NonTemplateTarget)) {
+ bool IsVirtualBase =
+ isVirtualDirectBase(cast<CXXRecordDecl>(CurContext),
+ UD->getQualifier()->getAsRecordDecl());
+ Shadow = ConstructorUsingShadowDecl::Create(
+ Context, CurContext, UD->getLocation(), UD, Orig, IsVirtualBase);
+ } else {
+ Shadow = UsingShadowDecl::Create(Context, CurContext, UD->getLocation(), UD,
+ Target);
+ }
UD->addShadowDecl(Shadow);
Shadow->setAccess(UD->getAccess());
@@ -8128,8 +8222,17 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return nullptr;
}
+ // For an inheriting constructor declaration, the name of the using
+ // declaration is the name of a constructor in this class, not in the
+ // base class.
+ DeclarationNameInfo UsingName = NameInfo;
+ if (UsingName.getName().getNameKind() == DeclarationName::CXXConstructorName)
+ if (auto *RD = dyn_cast<CXXRecordDecl>(CurContext))
+ UsingName.setName(Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Context.getRecordType(RD))));
+
// Do the redeclaration lookup in the current scope.
- LookupResult Previous(*this, NameInfo, LookupUsingDeclName,
+ LookupResult Previous(*this, UsingName, LookupUsingDeclName,
ForRedeclaration);
Previous.setHideTags(false);
if (S) {
@@ -8186,8 +8289,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
auto Build = [&](bool Invalid) {
UsingDecl *UD =
- UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, NameInfo,
- HasTypenameKeyword);
+ UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc,
+ UsingName, HasTypenameKeyword);
UD->setAccess(AS);
CurContext->addDecl(UD);
UD->setInvalidDecl(Invalid);
@@ -8242,6 +8345,9 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// If we corrected to an inheriting constructor, handle it as one.
auto *RD = dyn_cast<CXXRecordDecl>(ND);
if (RD && RD->isInjectedClassName()) {
+ // The parent of the injected class name is the class itself.
+ RD = cast<CXXRecordDecl>(RD->getParent());
+
// Fix up the information we'll use to build the using declaration.
if (Corrected.WillReplaceSpecifier()) {
NestedNameSpecifierLocBuilder Builder;
@@ -8250,14 +8356,19 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
QualifierLoc = Builder.getWithLocInContext(Context);
}
- NameInfo.setName(Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(RD))));
- NameInfo.setNamedTypeInfo(nullptr);
+ // In this case, the name we introduce is the name of a derived class
+ // constructor.
+ auto *CurClass = cast<CXXRecordDecl>(CurContext);
+ UsingName.setName(Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Context.getRecordType(CurClass))));
+ UsingName.setNamedTypeInfo(nullptr);
for (auto *Ctor : LookupConstructors(RD))
R.addDecl(Ctor);
+ R.resolveKind();
} else {
- // FIXME: Pick up all the declarations if we found an overloaded function.
- NameInfo.setName(ND->getDeclName());
+ // FIXME: Pick up all the declarations if we found an overloaded
+ // function.
+ UsingName.setName(ND->getDeclName());
R.addDecl(ND);
}
} else {
@@ -8310,17 +8421,16 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
UsingDecl *UD = BuildValid();
- // The normal rules do not apply to inheriting constructor declarations.
- if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
+ // Some additional rules apply to inheriting constructors.
+ if (UsingName.getName().getNameKind() ==
+ DeclarationName::CXXConstructorName) {
// Suppress access diagnostics; the access check is instead performed at the
// point of use for an inheriting constructor.
R.suppressDiagnostics();
- CheckInheritingConstructorUsingDecl(UD);
- return UD;
+ if (CheckInheritingConstructorUsingDecl(UD))
+ return UD;
}
- // Otherwise, look up the target name.
-
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
UsingShadowDecl *PrevDecl = nullptr;
if (!CheckUsingShadowDecl(UD, *I, Previous, PrevDecl))
@@ -8895,7 +9005,8 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
}
Sema::ImplicitExceptionSpecification
-Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
+Sema::ComputeInheritingCtorExceptionSpec(SourceLocation Loc,
+ CXXConstructorDecl *CD) {
CXXRecordDecl *ClassDecl = CD->getParent();
// C++ [except.spec]p14:
@@ -8904,36 +9015,26 @@ Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
if (ClassDecl->isInvalidDecl())
return ExceptSpec;
- // Inherited constructor.
- const CXXConstructorDecl *InheritedCD = CD->getInheritedConstructor();
- const CXXRecordDecl *InheritedDecl = InheritedCD->getParent();
- // FIXME: Copying or moving the parameters could add extra exceptions to the
- // set, as could the default arguments for the inherited constructor. This
- // will be addressed when we implement the resolution of core issue 1351.
- ExceptSpec.CalledDecl(CD->getLocStart(), InheritedCD);
+ auto Inherited = CD->getInheritedConstructor();
+ InheritedConstructorInfo ICI(*this, Loc, Inherited.getShadowDecl());
- // Direct base-class constructors.
- for (const auto &B : ClassDecl->bases()) {
- if (B.isVirtual()) // Handled below.
- continue;
-
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (BaseClassDecl == InheritedDecl)
+ // Direct and virtual base-class constructors.
+ for (bool VBase : {false, true}) {
+ for (CXXBaseSpecifier &B :
+ VBase ? ClassDecl->vbases() : ClassDecl->bases()) {
+ // Don't visit direct vbases twice.
+ if (B.isVirtual() != VBase)
continue;
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
- if (Constructor)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
- // Virtual base-class constructors.
- for (const auto &B : ClassDecl->vbases()) {
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (BaseClassDecl == InheritedDecl)
+ CXXRecordDecl *BaseClass = B.getType()->getAsCXXRecordDecl();
+ if (!BaseClass)
continue;
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+
+ CXXConstructorDecl *Constructor =
+ ICI.findConstructorForBase(BaseClass, Inherited.getConstructor())
+ .first;
+ if (!Constructor)
+ Constructor = LookupDefaultConstructor(BaseClass);
if (Constructor)
ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
@@ -9111,325 +9212,156 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
CheckDelayedMemberExceptionSpecs();
}
-namespace {
-/// Information on inheriting constructors to declare.
-class InheritingConstructorInfo {
-public:
- InheritingConstructorInfo(Sema &SemaRef, CXXRecordDecl *Derived)
- : SemaRef(SemaRef), Derived(Derived) {
- // Mark the constructors that we already have in the derived class.
- //
- // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...]
- // unless there is a user-declared constructor with the same signature in
- // the class where the using-declaration appears.
- visitAll(Derived, &InheritingConstructorInfo::noteDeclaredInDerived);
- }
-
- void inheritAll(CXXRecordDecl *RD) {
- visitAll(RD, &InheritingConstructorInfo::inherit);
- }
-
-private:
- /// Information about an inheriting constructor.
- struct InheritingConstructor {
- InheritingConstructor()
- : DeclaredInDerived(false), BaseCtor(nullptr), DerivedCtor(nullptr) {}
-
- /// If \c true, a constructor with this signature is already declared
- /// in the derived class.
- bool DeclaredInDerived;
-
- /// The constructor which is inherited.
- const CXXConstructorDecl *BaseCtor;
-
- /// The derived constructor we declared.
- CXXConstructorDecl *DerivedCtor;
- };
-
- /// Inheriting constructors with a given canonical type. There can be at
- /// most one such non-template constructor, and any number of templated
- /// constructors.
- struct InheritingConstructorsForType {
- InheritingConstructor NonTemplate;
- SmallVector<std::pair<TemplateParameterList *, InheritingConstructor>, 4>
- Templates;
-
- InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) {
- if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) {
- TemplateParameterList *ParamList = FTD->getTemplateParameters();
- for (unsigned I = 0, N = Templates.size(); I != N; ++I)
- if (S.TemplateParameterListsAreEqual(ParamList, Templates[I].first,
- false, S.TPL_TemplateMatch))
- return Templates[I].second;
- Templates.push_back(std::make_pair(ParamList, InheritingConstructor()));
- return Templates.back().second;
- }
-
- return NonTemplate;
- }
- };
-
- /// Get or create the inheriting constructor record for a constructor.
- InheritingConstructor &getEntry(const CXXConstructorDecl *Ctor,
- QualType CtorType) {
- return Map[CtorType.getCanonicalType()->castAs<FunctionProtoType>()]
- .getEntry(SemaRef, Ctor);
- }
-
- typedef void (InheritingConstructorInfo::*VisitFn)(const CXXConstructorDecl*);
+/// Find or create the fake constructor we synthesize to model constructing an
+/// object of a derived class via a constructor of a base class.
+CXXConstructorDecl *
+Sema::findInheritingConstructor(SourceLocation Loc,
+ CXXConstructorDecl *BaseCtor,
+ ConstructorUsingShadowDecl *Shadow) {
+ CXXRecordDecl *Derived = Shadow->getParent();
+ SourceLocation UsingLoc = Shadow->getLocation();
+
+ // FIXME: Add a new kind of DeclarationName for an inherited constructor.
+ // For now we use the name of the base class constructor as a member of the
+ // derived class to indicate a (fake) inherited constructor name.
+ DeclarationName Name = BaseCtor->getDeclName();
+
+ // Check to see if we already have a fake constructor for this inherited
+ // constructor call.
+ for (NamedDecl *Ctor : Derived->lookup(Name))
+ if (declaresSameEntity(cast<CXXConstructorDecl>(Ctor)
+ ->getInheritedConstructor()
+ .getConstructor(),
+ BaseCtor))
+ return cast<CXXConstructorDecl>(Ctor);
+
+ DeclarationNameInfo NameInfo(Name, UsingLoc);
+ TypeSourceInfo *TInfo =
+ Context.getTrivialTypeSourceInfo(BaseCtor->getType(), UsingLoc);
+ FunctionProtoTypeLoc ProtoLoc =
+ TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>();
+
+ // Check the inherited constructor is valid and find the list of base classes
+ // from which it was inherited.
+ InheritedConstructorInfo ICI(*this, Loc, Shadow);
+
+ bool Constexpr =
+ BaseCtor->isConstexpr() &&
+ defaultedSpecialMemberIsConstexpr(*this, Derived, CXXDefaultConstructor,
+ false, BaseCtor, &ICI);
+
+ CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
+ Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
+ BaseCtor->isExplicit(), /*Inline=*/true,
+ /*ImplicitlyDeclared=*/true, Constexpr,
+ InheritedConstructor(Shadow, BaseCtor));
+ if (Shadow->isInvalidDecl())
+ DerivedCtor->setInvalidDecl();
+
+ // Build an unevaluated exception specification for this fake constructor.
+ const FunctionProtoType *FPT = TInfo->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = DerivedCtor;
+ DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
- /// Process all constructors for a class.
- void visitAll(const CXXRecordDecl *RD, VisitFn Callback) {
- for (const auto *Ctor : RD->ctors())
- (this->*Callback)(Ctor);
- for (CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
- I(RD->decls_begin()), E(RD->decls_end());
- I != E; ++I) {
- const FunctionDecl *FD = (*I)->getTemplatedDecl();
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
- (this->*Callback)(CD);
- }
- }
+ // Build the parameter declarations.
+ SmallVector<ParmVarDecl *, 16> ParamDecls;
+ for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) {
+ TypeSourceInfo *TInfo =
+ Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc);
+ ParmVarDecl *PD = ParmVarDecl::Create(
+ Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr,
+ FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr);
+ PD->setScopeInfo(0, I);
+ PD->setImplicit();
+ // Ensure attributes are propagated onto parameters (this matters for
+ // format, pass_object_size, ...).
+ mergeDeclAttributes(PD, BaseCtor->getParamDecl(I));
+ ParamDecls.push_back(PD);
+ ProtoLoc.setParam(I, PD);
+ }
+
+ // Set up the new constructor.
+ assert(!BaseCtor->isDeleted() && "should not use deleted constructor");
+ DerivedCtor->setAccess(BaseCtor->getAccess());
+ DerivedCtor->setParams(ParamDecls);
+ Derived->addDecl(DerivedCtor);
+ return DerivedCtor;
+}
- /// Note that a constructor (or constructor template) was declared in Derived.
- void noteDeclaredInDerived(const CXXConstructorDecl *Ctor) {
- getEntry(Ctor, Ctor->getType()).DeclaredInDerived = true;
- }
+void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
+ CXXConstructorDecl *Constructor) {
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
+ assert(Constructor->getInheritedConstructor() &&
+ !Constructor->doesThisDeclarationHaveABody() &&
+ !Constructor->isDeleted());
+ if (Constructor->isInvalidDecl())
+ return;
- /// Inherit a single constructor.
- void inherit(const CXXConstructorDecl *Ctor) {
- const FunctionProtoType *CtorType =
- Ctor->getType()->castAs<FunctionProtoType>();
- ArrayRef<QualType> ArgTypes = CtorType->getParamTypes();
- FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo();
+ ConstructorUsingShadowDecl *Shadow =
+ Constructor->getInheritedConstructor().getShadowDecl();
+ CXXConstructorDecl *InheritedCtor =
+ Constructor->getInheritedConstructor().getConstructor();
- SourceLocation UsingLoc = getUsingLoc(Ctor->getParent());
+ // [class.inhctor.init]p1:
+ // initialization proceeds as if a defaulted default constructor is used to
+ // initialize the D object and each base class subobject from which the
+ // constructor was inherited
- // Core issue (no number yet): the ellipsis is always discarded.
- if (EPI.Variadic) {
- SemaRef.Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis);
- SemaRef.Diag(Ctor->getLocation(),
- diag::note_using_decl_constructor_ellipsis);
- EPI.Variadic = false;
- }
+ InheritedConstructorInfo ICI(*this, CurrentLocation, Shadow);
+ CXXRecordDecl *RD = Shadow->getParent();
+ SourceLocation InitLoc = Shadow->getLocation();
- // Declare a constructor for each number of parameters.
- //
- // C++11 [class.inhctor]p1:
- // The candidate set of inherited constructors from the class X named in
- // the using-declaration consists of [... modulo defects ...] for each
- // constructor or constructor template of X, the set of constructors or
- // constructor templates that results from omitting any ellipsis parameter
- // specification and successively omitting parameters with a default
- // argument from the end of the parameter-type-list
- unsigned MinParams = minParamsToInherit(Ctor);
- unsigned Params = Ctor->getNumParams();
- if (Params >= MinParams) {
- do
- declareCtor(UsingLoc, Ctor,
- SemaRef.Context.getFunctionType(
- Ctor->getReturnType(), ArgTypes.slice(0, Params), EPI));
- while (Params > MinParams &&
- Ctor->getParamDecl(--Params)->hasDefaultArg());
- }
- }
-
- /// Find the using-declaration which specified that we should inherit the
- /// constructors of \p Base.
- SourceLocation getUsingLoc(const CXXRecordDecl *Base) {
- // No fancy lookup required; just look for the base constructor name
- // directly within the derived class.
- ASTContext &Context = SemaRef.Context;
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(Base)));
- DeclContext::lookup_result Decls = Derived->lookup(Name);
- return Decls.empty() ? Derived->getLocation() : Decls[0]->getLocation();
- }
-
- unsigned minParamsToInherit(const CXXConstructorDecl *Ctor) {
- // C++11 [class.inhctor]p3:
- // [F]or each constructor template in the candidate set of inherited
- // constructors, a constructor template is implicitly declared
- if (Ctor->getDescribedFunctionTemplate())
- return 0;
-
- // For each non-template constructor in the candidate set of inherited
- // constructors other than a constructor having no parameters or a
- // copy/move constructor having a single parameter, a constructor is
- // implicitly declared [...]
- if (Ctor->getNumParams() == 0)
- return 1;
- if (Ctor->isCopyOrMoveConstructor())
- return 2;
-
- // Per discussion on core reflector, never inherit a constructor which
- // would become a default, copy, or move constructor of Derived either.
- const ParmVarDecl *PD = Ctor->getParamDecl(0);
- const ReferenceType *RT = PD->getType()->getAs<ReferenceType>();
- return (RT && RT->getPointeeCXXRecordDecl() == Derived) ? 2 : 1;
- }
-
- /// Declare a single inheriting constructor, inheriting the specified
- /// constructor, with the given type.
- void declareCtor(SourceLocation UsingLoc, const CXXConstructorDecl *BaseCtor,
- QualType DerivedType) {
- InheritingConstructor &Entry = getEntry(BaseCtor, DerivedType);
-
- // C++11 [class.inhctor]p3:
- // ... a constructor is implicitly declared with the same constructor
- // characteristics unless there is a user-declared constructor with
- // the same signature in the class where the using-declaration appears
- if (Entry.DeclaredInDerived)
- return;
+ // Initializations are performed "as if by a defaulted default constructor",
+ // so enter the appropriate scope.
+ SynthesizedFunctionScope Scope(*this, Constructor);
+ DiagnosticErrorTrap Trap(Diags);
- // C++11 [class.inhctor]p7:
- // If two using-declarations declare inheriting constructors with the
- // same signature, the program is ill-formed
- if (Entry.DerivedCtor) {
- if (BaseCtor->getParent() != Entry.BaseCtor->getParent()) {
- // Only diagnose this once per constructor.
- if (Entry.DerivedCtor->isInvalidDecl())
- return;
- Entry.DerivedCtor->setInvalidDecl();
-
- SemaRef.Diag(UsingLoc, diag::err_using_decl_constructor_conflict);
- SemaRef.Diag(BaseCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_current_ctor);
- SemaRef.Diag(Entry.BaseCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_previous_ctor);
- SemaRef.Diag(Entry.DerivedCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_previous_using);
- } else {
- // Core issue (no number): if the same inheriting constructor is
- // produced by multiple base class constructors from the same base
- // class, the inheriting constructor is defined as deleted.
- SemaRef.SetDeclDeleted(Entry.DerivedCtor, UsingLoc);
- }
+ // Build explicit initializers for all base classes from which the
+ // constructor was inherited.
+ SmallVector<CXXCtorInitializer*, 8> Inits;
+ for (bool VBase : {false, true}) {
+ for (CXXBaseSpecifier &B : VBase ? RD->vbases() : RD->bases()) {
+ if (B.isVirtual() != VBase)
+ continue;
- return;
- }
+ auto *BaseRD = B.getType()->getAsCXXRecordDecl();
+ if (!BaseRD)
+ continue;
- ASTContext &Context = SemaRef.Context;
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(Derived)));
- DeclarationNameInfo NameInfo(Name, UsingLoc);
+ auto BaseCtor = ICI.findConstructorForBase(BaseRD, InheritedCtor);
+ if (!BaseCtor.first)
+ continue;
- TemplateParameterList *TemplateParams = nullptr;
- if (const FunctionTemplateDecl *FTD =
- BaseCtor->getDescribedFunctionTemplate()) {
- TemplateParams = FTD->getTemplateParameters();
- // We're reusing template parameters from a different DeclContext. This
- // is questionable at best, but works out because the template depth in
- // both places is guaranteed to be 0.
- // FIXME: Rebuild the template parameters in the new context, and
- // transform the function type to refer to them.
- }
+ MarkFunctionReferenced(CurrentLocation, BaseCtor.first);
+ ExprResult Init = new (Context) CXXInheritedCtorInitExpr(
+ InitLoc, B.getType(), BaseCtor.first, VBase, BaseCtor.second);
- // Build type source info pointing at the using-declaration. This is
- // required by template instantiation.
- TypeSourceInfo *TInfo =
- Context.getTrivialTypeSourceInfo(DerivedType, UsingLoc);
- FunctionProtoTypeLoc ProtoLoc =
- TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>();
-
- CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
- Context, Derived, UsingLoc, NameInfo, DerivedType,
- TInfo, BaseCtor->isExplicit(), /*Inline=*/true,
- /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr());
-
- // Build an unevaluated exception specification for this constructor.
- const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>();
- FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- EPI.ExceptionSpec.Type = EST_Unevaluated;
- EPI.ExceptionSpec.SourceDecl = DerivedCtor;
- DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(),
- FPT->getParamTypes(), EPI));
-
- // Build the parameter declarations.
- SmallVector<ParmVarDecl *, 16> ParamDecls;
- for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) {
- TypeSourceInfo *TInfo =
- Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc);
- ParmVarDecl *PD = ParmVarDecl::Create(
- Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr,
- FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr);
- PD->setScopeInfo(0, I);
- PD->setImplicit();
- ParamDecls.push_back(PD);
- ProtoLoc.setParam(I, PD);
- }
-
- // Set up the new constructor.
- DerivedCtor->setAccess(BaseCtor->getAccess());
- DerivedCtor->setParams(ParamDecls);
- DerivedCtor->setInheritedConstructor(BaseCtor);
- if (BaseCtor->isDeleted())
- SemaRef.SetDeclDeleted(DerivedCtor, UsingLoc);
-
- // If this is a constructor template, build the template declaration.
- if (TemplateParams) {
- FunctionTemplateDecl *DerivedTemplate =
- FunctionTemplateDecl::Create(SemaRef.Context, Derived, UsingLoc, Name,
- TemplateParams, DerivedCtor);
- DerivedTemplate->setAccess(BaseCtor->getAccess());
- DerivedCtor->setDescribedFunctionTemplate(DerivedTemplate);
- Derived->addDecl(DerivedTemplate);
- } else {
- Derived->addDecl(DerivedCtor);
+ auto *TInfo = Context.getTrivialTypeSourceInfo(B.getType(), InitLoc);
+ Inits.push_back(new (Context) CXXCtorInitializer(
+ Context, TInfo, VBase, InitLoc, Init.get(), InitLoc,
+ SourceLocation()));
}
-
- Entry.BaseCtor = BaseCtor;
- Entry.DerivedCtor = DerivedCtor;
}
- Sema &SemaRef;
- CXXRecordDecl *Derived;
- typedef llvm::DenseMap<const Type *, InheritingConstructorsForType> MapType;
- MapType Map;
-};
-}
-
-void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
- // Defer declaring the inheriting constructors until the class is
- // instantiated.
- if (ClassDecl->isDependentContext())
- return;
-
- // Find base classes from which we might inherit constructors.
- SmallVector<CXXRecordDecl*, 4> InheritedBases;
- for (const auto &BaseIt : ClassDecl->bases())
- if (BaseIt.getInheritConstructors())
- InheritedBases.push_back(BaseIt.getType()->getAsCXXRecordDecl());
+ // We now proceed as if for a defaulted default constructor, with the relevant
+ // initializers replaced.
- // Go no further if we're not inheriting any constructors.
- if (InheritedBases.empty())
- return;
-
- // Declare the inherited constructors.
- InheritingConstructorInfo ICI(*this, ClassDecl);
- for (unsigned I = 0, N = InheritedBases.size(); I != N; ++I)
- ICI.inheritAll(InheritedBases[I]);
-}
-
-void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *Constructor) {
- CXXRecordDecl *ClassDecl = Constructor->getParent();
- assert(Constructor->getInheritedConstructor() &&
- !Constructor->doesThisDeclarationHaveABody() &&
- !Constructor->isDeleted());
-
- SynthesizedFunctionScope Scope(*this, Constructor);
- DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_inhctor_synthesized_at)
- << Context.getTagDeclType(ClassDecl);
+ bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits);
+ if (HadError || Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD;
Constructor->setInvalidDecl();
return;
}
- SourceLocation Loc = Constructor->getLocation();
- Constructor->setBody(new (Context) CompoundStmt(Loc));
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Constructor->getType()->castAs<FunctionProtoType>());
+
+ Constructor->setBody(new (Context) CompoundStmt(InitLoc));
Constructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -9437,8 +9369,9 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
}
-}
+ DiagnoseUninitializedFields(*this, Constructor);
+}
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
@@ -11481,10 +11414,11 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// with the same cv-unqualified type, the copy/move operation
// can be omitted by constructing the temporary object
// directly into the target of the omitted copy/move
- if (ConstructKind == CXXConstructExpr::CK_Complete &&
+ if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor &&
Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) {
Expr *SubExpr = ExprArgs[0];
- Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent());
+ Elidable = SubExpr->isTemporaryObject(
+ Context, cast<CXXRecordDecl>(FoundDecl->getDeclContext()));
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType,
@@ -11507,6 +11441,9 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
+ if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl))
+ Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
+
return BuildCXXConstructExpr(
ConstructLoc, DeclInitType, Constructor, Elidable, ExprArgs,
HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization,
@@ -11526,7 +11463,12 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
+ assert(declaresSameEntity(
+ Constructor->getParent(),
+ DeclInitType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) &&
+ "given constructor for wrong type");
MarkFunctionReferenced(ConstructLoc, Constructor);
+
return CXXConstructExpr::Create(
Context, DeclInitType, ConstructLoc, Constructor, Elidable,
ExprArgs, HadMultipleCandidates, IsListInitialization,
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index b7bed6de2d7..61ea87aa9d3 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1001,6 +1001,10 @@ CanThrowResult Sema::canThrow(const Expr *E) {
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
}
+ case Expr::CXXInheritedCtorInitExprClass:
+ return canCalleeThrow(*this, E,
+ cast<CXXInheritedCtorInitExpr>(E)->getConstructor());
+
case Expr::LambdaExprClass: {
const LambdaExpr *Lambda = cast<LambdaExpr>(E);
CanThrowResult CT = CT_Cannot;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 05aa18c6338..de65efca2e6 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -221,21 +221,6 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
return;
}
- if (CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Decl)) {
- if (CXXConstructorDecl *BaseCD =
- const_cast<CXXConstructorDecl*>(CD->getInheritedConstructor())) {
- Diag(Decl->getLocation(), diag::note_inherited_deleted_here);
- if (BaseCD->isDeleted()) {
- NoteDeletedFunction(BaseCD);
- } else {
- // FIXME: An explanation of why exactly it can't be inherited
- // would be nice.
- Diag(BaseCD->getLocation(), diag::note_cannot_inherit);
- }
- return;
- }
- }
-
Diag(Decl->getLocation(), diag::note_availability_specified_here)
<< Decl << true;
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ac87ae5ecd3..ea1de0c6428 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3186,9 +3186,8 @@ static ExprResult BuildCXXCastArgument(Sema &S,
if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs))
return ExprError();
- S.CheckConstructorAccess(CastLoc, Constructor,
- InitializedEntity::InitializeTemporary(Ty),
- Constructor->getAccess());
+ S.CheckConstructorAccess(CastLoc, Constructor, FoundDecl,
+ InitializedEntity::InitializeTemporary(Ty));
if (S.DiagnoseUseOfDecl(Method, CastLoc))
return ExprError();
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 1d793e330cf..1ed2d40ba18 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5519,8 +5519,8 @@ static ExprResult CopyObject(Sema &S,
SmallVector<Expr*, 8> ConstructorArgs;
CurInit.get(); // Ownership transferred into MultiExprArg, below.
- S.CheckConstructorAccess(Loc, Constructor, Entity,
- Best->FoundDecl.getAccess(), IsExtraneousCopy);
+ S.CheckConstructorAccess(Loc, Constructor, Best->FoundDecl, Entity,
+ IsExtraneousCopy);
if (IsExtraneousCopy) {
// If this is a totally extraneous copy for C++03 reference
@@ -5603,7 +5603,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
switch (OR) {
case OR_Success:
S.CheckConstructorAccess(Loc, cast<CXXConstructorDecl>(Best->Function),
- Entity, Best->FoundDecl.getAccess(), Diag);
+ Best->FoundDecl, Entity, Diag);
// FIXME: Check default arguments as far as that's possible.
break;
@@ -5729,7 +5729,6 @@ PerformConstructorInitialization(Sema &S,
if (isExplicitTemporary(Entity, Kind, NumArgs)) {
// An explicitly-constructed temporary, e.g., X(1, 2).
- S.MarkFunctionReferenced(Loc, Constructor);
if (S.DiagnoseUseOfDecl(Constructor, Loc))
return ExprError();
@@ -5741,6 +5740,11 @@ PerformConstructorInitialization(Sema &S,
? SourceRange(LBraceLoc, RBraceLoc)
: Kind.getParenRange();
+ if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(
+ Step.Function.FoundDecl.getDecl()))
+ Constructor = S.findInheritingConstructor(Loc, Constructor, Shadow);
+ S.MarkFunctionReferenced(Loc, Constructor);
+
CurInit = new (S.Context) CXXTemporaryObjectExpr(
S.Context, Constructor, TSInfo,
ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
@@ -5795,8 +5799,7 @@ PerformConstructorInitialization(Sema &S,
return ExprError();
// Only check access if all of that succeeded.
- S.CheckConstructorAccess(Loc, Constructor, Entity,
- Step.Function.FoundDecl.getAccess());
+ S.CheckConstructorAccess(Loc, Constructor, Step.Function.FoundDecl, Entity);
if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc))
return ExprError();
@@ -6529,8 +6532,8 @@ InitializationSequence::Perform(Sema &S,
if (CurInit.isInvalid())
return ExprError();
- S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity,
- FoundFn.getAccess());
+ S.CheckConstructorAccess(Kind.getLocation(), Constructor, FoundFn,
+ Entity);
if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()))
return ExprError();
@@ -7296,13 +7299,16 @@ bool InitializationSequence::Diagnose(Sema &S,
// initialize this base/member.
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(S.CurContext);
+ const CXXRecordDecl *InheritedFrom = nullptr;
+ if (auto Inherited = Constructor->getInheritedConstructor())
+ InheritedFrom = Inherited.getShadowDecl()->getNominatedBaseClass();
if (Entity.getKind() == InitializedEntity::EK_Base) {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
- << (Constructor->getInheritedConstructor() ? 2 :
- Constructor->isImplicit() ? 1 : 0)
+ << (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*base=*/0
- << Entity.getType();
+ << Entity.getType()
+ << InheritedFrom;
RecordDecl *BaseDecl
= Entity.getBaseSpecifier()->getType()->getAs<RecordType>()
@@ -7311,11 +7317,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< S.Context.getTagDeclType(BaseDecl);
} else {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
- << (Constructor->getInheritedConstructor() ? 2 :
- Constructor->isImplicit() ? 1 : 0)
+ << (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*member=*/1
- << Entity.getName();
+ << Entity.getName()
+ << InheritedFrom;
S.Diag(Entity.getDecl()->getLocation(),
diag::note_member_declared_at);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 9d0cf106ef7..f25d3161ae4 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2943,42 +2943,38 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// from an external source and invalidate lookup_result.
SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end());
- for (auto *Cand : Candidates) {
- if (Cand->isInvalidDecl())
+ for (NamedDecl *CandDecl : Candidates) {
+ if (CandDecl->isInvalidDecl())
continue;
- if (UsingShadowDecl *U = dyn_cast<UsingShadowDecl>(Cand)) {
- // FIXME: [namespace.udecl]p15 says that we should only consider a
- // using declaration here if it does not match a declaration in the
- // derived class. We do not implement this correctly in other cases
- // either.
- Cand = U->getTargetDecl();
-
- if (Cand->isInvalidDecl())
- continue;
- }
-
- if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand)) {
+ DeclAccessPair Cand = DeclAccessPair::make(CandDecl, AS_public);
+ auto CtorInfo = getConstructorInfo(Cand);
+ if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
- AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy,
- Classification, llvm::makeArrayRef(&Arg, NumArgs),
- OCS, true);
- else
- AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public),
+ AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
+ llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ else if (CtorInfo)
+ AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ else
+ AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
+ true);
} else if (FunctionTemplateDecl *Tmpl =
- dyn_cast<FunctionTemplateDecl>(Cand)) {
+ dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
- AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- RD, nullptr, ThisTy, Classification,
- llvm::makeArrayRef(&Arg, NumArgs),
- OCS, true);
+ AddMethodTemplateCandidate(
+ Tmpl, Cand, RD, nullptr, ThisTy, Classification,
+ llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ else if (CtorInfo)
+ AddTemplateOverloadCandidate(
+ CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
+ llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
else
- AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- nullptr, llvm::makeArrayRef(&Arg, NumArgs),
- OCS, true);
+ AddTemplateOverloadCandidate(
+ Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
} else {
- assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl");
+ assert(isa<UsingDecl>(Cand.getDecl()) &&
+ "illegal Kind of operator = Decl");
}
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 4ddbfed9dd7..a9a78244baf 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -3055,7 +3055,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
bool AllowExplicit) {
for (auto *D : S.LookupConstructors(To)) {
auto Info = getConstructorInfo(D);
- if (!Info.Constructor)
+ if (!Info)
continue;
bool Usable = !Info.Constructor->isInvalidDecl() &&
@@ -3174,7 +3174,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
for (auto *D : S.LookupConstructors(ToRecordDecl)) {
auto Info = getConstructorInfo(D);
- if (!Info.Constructor)
+ if (!Info)
continue;
bool Usable = !Info.Constructor->isInvalidDecl();
@@ -8646,6 +8646,25 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
+ // FIXME: Work around a defect in the C++17 inheriting constructor wording.
+ // A derived-class constructor beats an (inherited) base class constructor.
+ bool Cand1IsInherited =
+ dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl());
+ bool Cand2IsInherited =
+ dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand2.FoundDecl.getDecl());
+ if (Cand1IsInherited != Cand2IsInherited)
+ return Cand2IsInherited;
+ else if (Cand1IsInherited) {
+ assert(Cand2IsInherited);
+ auto *Cand1Class = cast<CXXRecordDecl>(Cand1.Function->getDeclContext());
+ auto *Cand2Class = cast<CXXRecordDecl>(Cand2.Function->getDeclContext());
+ if (Cand1Class->isDerivedFrom(Cand2Class))
+ return true;
+ if (Cand2Class->isDerivedFrom(Cand1Class))
+ return false;
+ // Inherited from sibling base classes: still ambiguous.
+ }
+
// Check for enable_if value-based overload resolution.
if (Cand1.Function && Cand2.Function) {
Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function);
@@ -8837,7 +8856,8 @@ enum OverloadCandidateKind {
oc_implicit_move_constructor,
oc_implicit_copy_assignment,
oc_implicit_move_assignment,
- oc_implicit_inherited_constructor
+ oc_inherited_constructor,
+ oc_inherited_constructor_template
};
OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
@@ -8853,11 +8873,13 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
}
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) {
- if (!Ctor->isImplicit())
- return isTemplate ? oc_constructor_template : oc_constructor;
-
- if (Ctor->getInheritedConstructor())
- return oc_implicit_inherited_constructor;
+ if (!Ctor->isImplicit()) {
+ if (isa<ConstructorUsingShadowDecl>(Found))
+ return isTemplate ? oc_inherited_constructor_template
+ : oc_inherited_constructor;
+ else
+ return isTemplate ? oc_constructor_template : oc_constructor;
+ }
if (Ctor->isDefaultConstructor())
return oc_implicit_default_constructor;
@@ -8889,14 +8911,13 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
return isTemplate ? oc_function_template : oc_function;
}
-void MaybeEmitInheritedConstructorNote(Sema &S, Decl *Fn) {
- const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn);
- if (!Ctor) return;
-
- Ctor = Ctor->getInheritedConstructor();
- if (!Ctor) return;
-
- S.Diag(Ctor->getLocation(), diag::note_ovl_candidate_inherited_constructor);
+void MaybeEmitInheritedConstructorNote(Sema &S, Decl *FoundDecl) {
+ // FIXME: It'd be nice to only emit a note once per using-decl per overload
+ // set.
+ if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl))
+ S.Diag(FoundDecl->getLocation(),
+ diag::note_ovl_candidate_inherited_constructor)
+ << Shadow->getNominatedBaseClass();
}
} // end anonymous namespace
@@ -8982,7 +9003,7 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
HandleFunctionTypeMismatch(PD, Fn->getType(), DestType);
Diag(Fn->getLocation(), PD);
- MaybeEmitInheritedConstructorNote(*this, Fn);
+ MaybeEmitInheritedConstructorNote(*this, Found);
}
// Notes the location of all overload candidates designated through
@@ -9070,7 +9091,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< ToTy << Name << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9101,7 +9122,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< FromTy
<< FromQs.getAddressSpace() << ToQs.getAddressSpace()
<< (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9112,7 +9133,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< FromTy
<< FromQs.getObjCLifetime() << ToQs.getObjCLifetime()
<< (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9123,7 +9144,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< FromTy
<< FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr()
<< (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9132,7 +9153,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << FromQs.hasUnaligned() << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9150,7 +9171,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << (CVR - 1) << I+1;
}
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9161,7 +9182,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << ToTy << (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9179,7 +9200,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< FromTy << ToTy << (unsigned) isObjectArgument << I+1
<< (unsigned) (Cand->Fix.Kind);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9218,7 +9239,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< (unsigned) isObjectArgument << I + 1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
}
@@ -9230,7 +9251,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< (BaseToDerivedConversion - 1)
<< FromTy << ToTy << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9243,7 +9264,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << ToTy << (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
}
@@ -9265,7 +9286,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
FDiag << *HI;
S.Diag(Fn->getLocation(), FDiag);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
}
/// Additional arity mismatch diagnosis specific to a function overload
@@ -9341,7 +9362,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
<< (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != nullptr)
<< mode << modeCount << NumFormalArgs;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Found);
}
/// Arity mismatch diagnosis specific to a function overload candidate.
@@ -9377,7 +9398,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_incomplete_deduction)
<< ParamD->getDeclName();
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
@@ -9402,7 +9423,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_underqualified)
<< ParamD->getDeclName() << Arg << NonCanonParam;
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
@@ -9421,7 +9442,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
diag::note_ovl_candidate_inconsistent_deduction)
<< which << ParamD->getDeclName() << *DeductionFailure.getFirstArg()
<< *DeductionFailure.getSecondArg();
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
@@ -9444,7 +9465,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
<< (index + 1);
}
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
case Sema::TDK_TooManyArguments:
@@ -9455,7 +9476,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
case Sema::TDK_InstantiationDepth:
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_instantiation_depth);
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
case Sema::TDK_SubstitutionFailure: {
@@ -9493,7 +9514,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_substitution_failure)
<< TemplateArgString << SFINAEArgString << R;
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
@@ -9565,7 +9586,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
// note_ovl_candidate_bad_deduction, which is uselessly vague.
case Sema::TDK_MiscellaneousDeductionFailure:
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_bad_deduction);
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
}
@@ -9676,7 +9697,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
<< FnKind << FnDesc
<< (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9698,7 +9719,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_illegal_constructor: {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor)
<< (Fn->getPrimaryTemplate() ? 1 : 0);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9764,7 +9785,6 @@ static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand)
<< FnType;
- MaybeEmitInheritedConstructorNote(S, Cand->Surrogate);
}
static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
@@ -10531,9 +10551,10 @@ private:
UnresolvedSetIterator Result = S.getMostSpecialized(
MatchesCopy.begin(), MatchesCopy.end(), FailedCandidates,
SourceExpr->getLocStart(), S.PDiag(),
- S.PDiag(diag::err_addr_ovl_ambiguous) << Matches[0]
- .second->getDeclName(),
- S.PDiag(diag::note_ovl_candidate) << (unsigned)oc_function_template,
+ S.PDiag(diag::err_addr_ovl_ambiguous)
+ << Matches[0].second->getDeclName(),
+ S.PDiag(diag::note_ovl_candidate)
+ << (unsigned)oc_function_template,
Complain, TargetFunctionType);
if (Result != MatchesCopy.end()) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index dbb8c6e0c6e..29cd7a70dec 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1843,36 +1843,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Constructor->isExplicit(),
Constructor->isInlineSpecified(),
false, Constructor->isConstexpr());
-
- // Claim that the instantiation of a constructor or constructor template
- // inherits the same constructor that the template does.
- if (CXXConstructorDecl *Inh = const_cast<CXXConstructorDecl *>(
- Constructor->getInheritedConstructor())) {
- // If we're instantiating a specialization of a function template, our
- // "inherited constructor" will actually itself be a function template.
- // Instantiate a declaration of it, too.
- if (FunctionTemplate) {
- assert(!TemplateParams && Inh->getDescribedFunctionTemplate() &&
- !Inh->getParent()->isDependentContext() &&
- "inheriting constructor template in dependent context?");
- Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(),
- Inh);
- if (Inst.isInvalid())
- return nullptr;
- Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext());
- LocalInstantiationScope LocalScope(SemaRef);
-
- // Use the same template arguments that we deduced for the inheriting
- // constructor. There's no way they could be deduced differently.
- MultiLevelTemplateArgumentList InheritedArgs;
- InheritedArgs.addOuterTemplateArguments(TemplateArgs.getInnermost());
- Inh = cast_or_null<CXXConstructorDecl>(
- SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs));
- if (!Inh)
- return nullptr;
- }
- cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh);
- }
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
@@ -2398,9 +2368,14 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
if (!QualifierLoc)
return nullptr;
- // The name info is non-dependent, so no transformation
- // is required.
+ // For an inheriting constructor declaration, the name of the using
+ // declaration is the name of a constructor in this class, not in the
+ // base class.
DeclarationNameInfo NameInfo = D->getNameInfo();
+ if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName)
+ if (auto *RD = dyn_cast<CXXRecordDecl>(SemaRef.CurContext))
+ NameInfo.setName(SemaRef.Context.DeclarationNames.getCXXConstructorName(
+ SemaRef.Context.getCanonicalType(SemaRef.Context.getRecordType(RD))));
// We only need to do redeclaration lookups if we're in a class
// scope (in fact, it's not really even possible in non-class
@@ -2443,18 +2418,23 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
if (NewUD->isInvalidDecl())
return NewUD;
- if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
+ if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName)
SemaRef.CheckInheritingConstructorUsingDecl(NewUD);
- return NewUD;
- }
bool isFunctionScope = Owner->isFunctionOrMethod();
// Process the shadow decls.
for (auto *Shadow : D->shadows()) {
+ // FIXME: UsingShadowDecl doesn't preserve its immediate target, so
+ // reconstruct it in the case where it matters.
+ NamedDecl *OldTarget = Shadow->getTargetDecl();
+ if (auto *CUSD = dyn_cast<ConstructorUsingShadowDecl>(Shadow))
+ if (auto *BaseShadow = CUSD->getNominatedBaseClassShadowDecl())
+ OldTarget = BaseShadow;
+
NamedDecl *InstTarget =
cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl(
- Shadow->getLocation(), Shadow->getTargetDecl(), TemplateArgs));
+ Shadow->getLocation(), OldTarget, TemplateArgs));
if (!InstTarget)
return nullptr;
@@ -2485,6 +2465,12 @@ Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) {
return nullptr;
}
+Decl *TemplateDeclInstantiator::VisitConstructorUsingShadowDecl(
+ ConstructorUsingShadowDecl *D) {
+ // Ignore these; we handle them in bulk when processing the UsingDecl.
+ return nullptr;
+}
+
Decl * TemplateDeclInstantiator
::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
NestedNameSpecifierLoc QualifierLoc
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c1cf9ada71e..fbfc078e988 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2690,6 +2690,16 @@ public:
ParenRange);
}
+ /// \brief Build a new implicit construction via inherited constructor
+ /// expression.
+ ExprResult RebuildCXXInheritedCtorInitExpr(QualType T, SourceLocation Loc,
+ CXXConstructorDecl *Constructor,
+ bool ConstructsVBase,
+ bool InheritedFromVBase) {
+ return new (getSema().Context) CXXInheritedCtorInitExpr(
+ Loc, T, Constructor, ConstructsVBase, InheritedFromVBase);
+ }
+
/// \brief Build a new object-construction expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -9937,6 +9947,32 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
E->getParenOrBraceRange());
}
+template<typename Derived>
+ExprResult TreeTransform<Derived>::TransformCXXInheritedCtorInitExpr(
+ CXXInheritedCtorInitExpr *E) {
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return ExprError();
+
+ CXXConstructorDecl *Constructor = cast_or_null<CXXConstructorDecl>(
+ getDerived().TransformDecl(E->getLocStart(), E->getConstructor()));
+ if (!Constructor)
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ Constructor == E->getConstructor()) {
+ // Mark the constructor as referenced.
+ // FIXME: Instantiation-specific
+ SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
+ return E;
+ }
+
+ return getDerived().RebuildCXXInheritedCtorInitExpr(
+ T, E->getLocation(), Constructor,
+ E->constructsVBase(), E->inheritedFromVBase());
+}
+
/// \brief Transform a C++ temporary-binding expression.
///
/// Since CXXBindTemporaryExpr nodes are implicitly generated, we just
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index 792fac99e58..22ead2b57c7 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -258,6 +258,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::CXXDestructor:
case Decl::CXXConversion:
case Decl::UsingShadow:
+ case Decl::ConstructorUsingShadow:
case Decl::Var:
case Decl::FunctionTemplate:
case Decl::ClassTemplate:
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index f993cf48a70..6fc3a6a1539 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -324,6 +324,7 @@ namespace clang {
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
void VisitImportDecl(ImportDecl *D);
@@ -1421,6 +1422,16 @@ void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
mergeRedeclarable(D, Redecl);
}
+void ASTDeclReader::VisitConstructorUsingShadowDecl(
+ ConstructorUsingShadowDecl *D) {
+ VisitUsingShadowDecl(D);
+ D->NominatedBaseClassShadowDecl =
+ ReadDeclAs<ConstructorUsingShadowDecl>(Record, Idx);
+ D->ConstructedBaseClassShadowDecl =
+ ReadDeclAs<ConstructorUsingShadowDecl>(Record, Idx);
+ D->IsVirtual = Record[Idx++];
+}
+
void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
VisitNamedDecl(D);
D->UsingLoc = ReadSourceLocation(Record, Idx);
@@ -1768,11 +1779,17 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
}
void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ // We need the inherited constructor information to merge the declaration,
+ // so we have to read it before we call VisitCXXMethodDecl.
+ if (D->isInheritingConstructor()) {
+ auto *Shadow = ReadDeclAs<ConstructorUsingShadowDecl>(Record, Idx);
+ auto *Ctor = ReadDeclAs<CXXConstructorDecl>(Record, Idx);
+ *D->getTrailingObjects<InheritedConstructor>() =
+ InheritedConstructor(Shadow, Ctor);
+ }
+
VisitCXXMethodDecl(D);
- if (auto *CD = ReadDeclAs<CXXConstructorDecl>(Record, Idx))
- if (D->isCanonicalDecl())
- D->setInheritedConstructor(CD->getCanonicalDecl());
D->IsExplicitSpecified = Record[Idx++];
}
@@ -2663,6 +2680,13 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
// functions, etc.
if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
FunctionDecl *FuncY = cast<FunctionDecl>(Y);
+ if (CXXConstructorDecl *CtorX = dyn_cast<CXXConstructorDecl>(X)) {
+ CXXConstructorDecl *CtorY = cast<CXXConstructorDecl>(Y);
+ if (CtorX->getInheritedConstructor() &&
+ !isSameEntity(CtorX->getInheritedConstructor().getConstructor(),
+ CtorY->getInheritedConstructor().getConstructor()))
+ return false;
+ }
return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) &&
FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
}
@@ -3240,6 +3264,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_USING_SHADOW:
D = UsingShadowDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_CONSTRUCTOR_USING_SHADOW:
+ D = ConstructorUsingShadowDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_USING_DIRECTIVE:
D = UsingDirectiveDecl::CreateDeserialized(Context, ID);
break;
@@ -3256,7 +3283,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
D = CXXMethodDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_CONSTRUCTOR:
- D = CXXConstructorDecl::CreateDeserialized(Context, ID);
+ D = CXXConstructorDecl::CreateDeserialized(Context, ID, false);
+ break;
+ case DECL_CXX_INHERITED_CONSTRUCTOR:
+ D = CXXConstructorDecl::CreateDeserialized(Context, ID, true);
break;
case DECL_CXX_DESTRUCTOR:
D = CXXDestructorDecl::CreateDeserialized(Context, ID);
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 69b7d972436..f5db0319298 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1250,6 +1250,14 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
E->ParenOrBraceRange = ReadSourceRange(Record, Idx);
}
+void ASTStmtReader::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) {
+ VisitExpr(E);
+ E->Constructor = ReadDeclAs<CXXConstructorDecl>(Record, Idx);
+ E->Loc = ReadSourceLocation(Record, Idx);
+ E->ConstructsVirtualBase = Record[Idx++];
+ E->InheritedFromVirtualBase = Record[Idx++];
+}
+
void ASTStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
VisitCXXConstructExpr(E);
E->Type = GetTypeSourceInfo(Record, Idx);
@@ -3407,6 +3415,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) CXXConstructExpr(Empty);
break;
+ case EXPR_CXX_INHERITED_CTOR_INIT:
+ S = new (Context) CXXInheritedCtorInitExpr(Empty);
+ break;
+
case EXPR_CXX_TEMPORARY_OBJECT:
S = new (Context) CXXTemporaryObjectExpr(Empty);
break;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 30b4a3ebe2e..4fa016cc896 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1104,6 +1104,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_CXX_RECORD);
RECORD(DECL_CXX_METHOD);
RECORD(DECL_CXX_CONSTRUCTOR);
+ RECORD(DECL_CXX_INHERITED_CONSTRUCTOR);
RECORD(DECL_CXX_DESTRUCTOR);
RECORD(DECL_CXX_CONVERSION);
RECORD(DECL_ACCESS_SPEC);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 04a2d6bd8c8..0940dd27d41 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -107,6 +107,7 @@ namespace clang {
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
void VisitImportDecl(ImportDecl *D);
@@ -1126,6 +1127,15 @@ void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
Code = serialization::DECL_USING_SHADOW;
}
+void ASTDeclWriter::VisitConstructorUsingShadowDecl(
+ ConstructorUsingShadowDecl *D) {
+ VisitUsingShadowDecl(D);
+ Record.AddDeclRef(D->NominatedBaseClassShadowDecl);
+ Record.AddDeclRef(D->ConstructedBaseClassShadowDecl);
+ Record.push_back(D->IsVirtual);
+ Code = serialization::DECL_CONSTRUCTOR_USING_SHADOW;
+}
+
void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
VisitNamedDecl(D);
Record.AddSourceLocation(D->getUsingLoc());
@@ -1211,12 +1221,21 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
}
void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ if (auto Inherited = D->getInheritedConstructor()) {
+ Record.AddDeclRef(Inherited.getShadowDecl());
+ Record.AddDeclRef(Inherited.getConstructor());
+ Code = serialization::DECL_CXX_INHERITED_CONSTRUCTOR;
+ } else {
+ Code = serialization::DECL_CXX_CONSTRUCTOR;
+ }
+
VisitCXXMethodDecl(D);
- Record.AddDeclRef(D->getInheritedConstructor());
Record.push_back(D->IsExplicitSpecified);
- Code = serialization::DECL_CXX_CONSTRUCTOR;
+ Code = D->isInheritingConstructor()
+ ? serialization::DECL_CXX_INHERITED_CONSTRUCTOR
+ : serialization::DECL_CXX_CONSTRUCTOR;
}
void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 333a70fe619..2170936b548 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1218,6 +1218,15 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Code = serialization::EXPR_CXX_CONSTRUCT;
}
+void ASTStmtWriter::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) {
+ VisitExpr(E);
+ Record.AddDeclRef(E->getConstructor());
+ Record.AddSourceLocation(E->getLocation());
+ Record.push_back(E->constructsVBase());
+ Record.push_back(E->inheritedFromVBase());
+ Code = serialization::EXPR_CXX_INHERITED_CTOR_INIT;
+}
+
void ASTStmtWriter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
VisitCXXConstructExpr(E);
Record.AddTypeSourceInfo(E->getTypeSourceInfo());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index e4ba1be4ba5..a7fbdb5a37c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -755,6 +755,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// C++ and ARC stuff we don't support yet.
case Expr::ObjCIndirectCopyRestoreExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
+ case Stmt::CXXInheritedCtorInitExprClass:
case Stmt::CXXTryStmtClass:
case Stmt::CXXTypeidExprClass:
case Stmt::CXXUuidofExprClass:
OpenPOWER on IntegriCloud