diff options
72 files changed, 2754 insertions, 931 deletions
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index 824fccceb2..e2d184d654 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -17,6 +17,7 @@ namespace clang { class Attr; class ClassTemplateDecl; class ClassTemplateSpecializationDecl; + class ConstructorUsingShadowDecl; class CXXDestructorDecl; class CXXRecordDecl; class Decl; diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 41f48e0ba7..7961c007dc 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -387,6 +387,7 @@ public: NamedDecl *getUnderlyingDecl() { // Fast-path the common case. if (this->getKind() != UsingShadow && + this->getKind() != ConstructorUsingShadow && this->getKind() != ObjCCompatibleAlias && this->getKind() != NamespaceAlias) return this; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 9c860f40e1..a8f00cb327 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -29,6 +29,7 @@ namespace clang { class ClassTemplateDecl; class ClassTemplateSpecializationDecl; +class ConstructorUsingShadowDecl; class CXXBasePath; class CXXBasePaths; class CXXConstructorDecl; @@ -1298,7 +1299,7 @@ public: } /// \brief Determine whether this class has a using-declaration that names - /// a base class constructor. + /// a user-declared base class constructor. bool hasInheritedConstructor() const { return data().HasInheritedConstructor; } @@ -2153,6 +2154,23 @@ public: friend TrailingObjects; }; +/// Description of a constructor that was inherited from a base class. +class InheritedConstructor { + ConstructorUsingShadowDecl *Shadow; + CXXConstructorDecl *BaseCtor; + +public: + InheritedConstructor() : Shadow(), BaseCtor() {} + InheritedConstructor(ConstructorUsingShadowDecl *Shadow, + CXXConstructorDecl *BaseCtor) + : Shadow(Shadow), BaseCtor(BaseCtor) {} + + explicit operator bool() const { return Shadow; } + + ConstructorUsingShadowDecl *getShadowDecl() const { return Shadow; } + CXXConstructorDecl *getConstructor() const { return BaseCtor; } +}; + /// \brief Represents a C++ constructor within a class. /// /// For example: @@ -2163,41 +2181,51 @@ public: /// explicit X(int); // represented by a CXXConstructorDecl. /// }; /// \endcode -class CXXConstructorDecl : public CXXMethodDecl { +class CXXConstructorDecl final + : public CXXMethodDecl, + private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor> { void anchor() override; /// \name Support for base and member initializers. /// \{ /// \brief The arguments used to initialize the base or member. LazyCXXCtorInitializersPtr CtorInitializers; - unsigned NumCtorInitializers : 31; + unsigned NumCtorInitializers : 30; /// \} /// \brief Whether this constructor declaration has the \c explicit keyword /// specified. unsigned IsExplicitSpecified : 1; + /// \brief Whether this constructor declaration is an implicitly-declared + /// inheriting constructor. + unsigned IsInheritingConstructor : 1; + CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicitSpecified, bool isInline, - bool isImplicitlyDeclared, bool isConstexpr) + bool isImplicitlyDeclared, bool isConstexpr, + InheritedConstructor Inherited) : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, SC_None, isInline, isConstexpr, SourceLocation()), CtorInitializers(nullptr), NumCtorInitializers(0), - IsExplicitSpecified(isExplicitSpecified) { + IsExplicitSpecified(isExplicitSpecified), + IsInheritingConstructor((bool)Inherited) { setImplicit(isImplicitlyDeclared); + if (Inherited) + *getTrailingObjects<InheritedConstructor>() = Inherited; } public: - static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID); - static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isExplicit, - bool isInline, bool isImplicitlyDeclared, - bool isConstexpr); + static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID, + bool InheritsConstructor); + static CXXConstructorDecl * + Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + bool isExplicit, bool isInline, bool isImplicitlyDeclared, + bool isConstexpr, + InheritedConstructor Inherited = InheritedConstructor()); /// \brief Determine whether this constructor declaration has the /// \c explicit keyword specified. @@ -2344,11 +2372,15 @@ public: /// an object. bool isSpecializationCopyingObject() const; - /// \brief Get the constructor that this inheriting constructor is based on. - const CXXConstructorDecl *getInheritedConstructor() const; + /// \brief Determine whether this is an implicit constructor synthesized to + /// model a call to a constructor inherited from a base class. + bool isInheritingConstructor() const { return IsInheritingConstructor; } - /// \brief Set the constructor that this inheriting constructor is based on. - void setInheritedConstructor(const CXXConstructorDecl *BaseCtor); + /// \brief Get the constructor that this inheriting constructor is based on. + InheritedConstructor getInheritedConstructor() const { + return IsInheritingConstructor ? *getTrailingObjects<InheritedConstructor>() + : InheritedConstructor(); + } CXXConstructorDecl *getCanonicalDecl() override { return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl()); @@ -2363,6 +2395,7 @@ public: friend class ASTDeclReader; friend class ASTDeclWriter; + friend TrailingObjects; }; /// \brief Represents a C++ destructor within a class. @@ -2807,18 +2840,6 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> { NamedDecl *UsingOrNextShadow; friend class UsingDecl; - UsingShadowDecl(ASTContext &C, DeclContext *DC, SourceLocation Loc, - UsingDecl *Using, NamedDecl *Target) - : NamedDecl(UsingShadow, DC, Loc, DeclarationName()), - redeclarable_base(C), Underlying(Target), - UsingOrNextShadow(reinterpret_cast<NamedDecl *>(Using)) { - if (Target) { - setDeclName(Target->getDeclName()); - IdentifierNamespace = Target->getIdentifierNamespace(); - } - setImplicit(); - } - typedef Redeclarable<UsingShadowDecl> redeclarable_base; UsingShadowDecl *getNextRedeclarationImpl() override { return getNextRedeclaration(); @@ -2830,11 +2851,16 @@ class UsingShadowDecl : public NamedDecl, public Redeclarable<UsingShadowDecl> { return getMostRecentDecl(); } +protected: + UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, SourceLocation Loc, + UsingDecl *Using, NamedDecl *Target); + UsingShadowDecl(Kind K, ASTContext &C, EmptyShell); + public: static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, UsingDecl *Using, NamedDecl *Target) { - return new (C, DC) UsingShadowDecl(C, DC, Loc, Using, Target); + return new (C, DC) UsingShadowDecl(UsingShadow, C, DC, Loc, Using, Target); } static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2846,6 +2872,7 @@ public: using redeclarable_base::redecls; using redeclarable_base::getPreviousDecl; using redeclarable_base::getMostRecentDecl; + using redeclarable_base::isFirstDecl; UsingShadowDecl *getCanonicalDecl() override { return getFirstDecl(); @@ -2876,7 +2903,125 @@ public: } static bool classof(const Decl *D) { return classofKind(D->getKind()); } - static bool classofKind(Kind K) { return K == Decl::UsingShadow; } + static bool classofKind(Kind K) { + return K == Decl::UsingShadow || K == Decl::ConstructorUsingShadow; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Represents a shadow constructor declaration introduced into a +/// class by a C++11 using-declaration that names a constructor. +/// +/// For example: +/// \code +/// struct Base { Base(int); }; +/// struct Derived { +/// using Base::Base; // creates a UsingDecl and a ConstructorUsingShadowDecl +/// }; +/// \endcode +class ConstructorUsingShadowDecl final : public UsingShadowDecl { + void anchor() override; + + /// \brief If this constructor using declaration inherted the constructor + /// from an indirect base class, this is the ConstructorUsingShadowDecl + /// in the named direct base class from which the declaration was inherited. + ConstructorUsingShadowDecl *NominatedBaseClassShadowDecl; + + /// \brief If this constructor using declaration inherted the constructor + /// from an indirect base class, this is the ConstructorUsingShadowDecl + /// that will be used to construct the unique direct or virtual base class + /// that receives the constructor arguments. + ConstructorUsingShadowDecl *ConstructedBaseClassShadowDecl; + + /// \brief \c true if the constructor ultimately named by this using shadow + /// declaration is within a virtual base class subobject of the class that + /// contains this declaration. + unsigned IsVirtual : 1; + + ConstructorUsingShadowDecl(ASTContext &C, DeclContext *DC, SourceLocation Loc, + UsingDecl *Using, NamedDecl *Target, + bool TargetInVirtualBase) + : UsingShadowDecl(ConstructorUsingShadow, C, DC, Loc, Using, + Target->getUnderlyingDecl()), + NominatedBaseClassShadowDecl( + dyn_cast<ConstructorUsingShadowDecl>(Target)), + ConstructedBaseClassShadowDecl(NominatedBaseClassShadowDecl), + IsVirtual(TargetInVirtualBase) { + // If we found a constructor for a non-virtual base class, but it chains to + // a constructor for a virtual base, we should directly call the virtual + // base constructor instead. + // FIXME: This logic belongs in Sema. + if (!TargetInVirtualBase && NominatedBaseClassShadowDecl && + NominatedBaseClassShadowDecl->constructsVirtualBase()) { + ConstructedBaseClassShadowDecl = + NominatedBaseClassShadowDecl->ConstructedBaseClassShadowDecl; + IsVirtual = true; + } + } + ConstructorUsingShadowDecl(ASTContext &C, EmptyShell Empty) + : UsingShadowDecl(ConstructorUsingShadow, C, Empty) {} + +public: + static ConstructorUsingShadowDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation Loc, + UsingDecl *Using, NamedDecl *Target, + bool IsVirtual); + static ConstructorUsingShadowDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + + /// Returns the parent of this using shadow declaration, which + /// is the class in which this is declared. + //@{ + const CXXRecordDecl *getParent() const { + return cast<CXXRecordDecl>(getDeclContext()); + } + CXXRecordDecl *getParent() { + return cast<CXXRecordDecl>(getDeclContext()); + } + //@} + + /// \brief Get the inheriting constructor declaration for the direct base + /// class from which this using shadow declaration was inherited, if there is + /// one. This can be different for each redeclaration of the same shadow decl. + ConstructorUsingShadowDecl *getNominatedBaseClassShadowDecl() const { + return NominatedBaseClassShadowDecl; + } + + /// \brief Get the inheriting constructor declaration for the base class + /// for which we don't have an explicit initializer, if there is one. + ConstructorUsingShadowDecl *getConstructedBaseClassShadowDecl() const { + return ConstructedBaseClassShadowDecl; + } + + /// \brief Get the base class that was named in the using declaration. This + /// can be different for each redeclaration of this same shadow decl. + CXXRecordDecl *getNominatedBaseClass() const; + + /// \brief Get the base class whose constructor or constructor shadow + /// declaration is passed the constructor arguments. + CXXRecordDecl *getConstructedBaseClass() const { + return cast<CXXRecordDecl>((ConstructedBaseClassShadowDecl + ? ConstructedBaseClassShadowDecl + : getTargetDecl()) + ->getDeclContext()); + } + + /// \brief Returns \c true if the constructed base class is a virtual base + /// class subobject of this declaration's class. + bool constructsVirtualBase() const { + return IsVirtual; + } + + /// \brief Get the constructor or constructor template in the derived class + /// correspnding to this using shadow declaration, if it has been implicitly + /// declared already. + CXXConstructorDecl *getConstructor() const; + void setConstructor(NamedDecl *Ctor); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ConstructorUsingShadow; } friend class ASTDeclReader; friend class ASTDeclWriter; diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 1f0536472b..8882620b34 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1318,6 +1318,73 @@ public: friend class ASTStmtReader; }; +/// \brief Represents a call to an inherited base class constructor from an +/// inheriting constructor. This call implicitly forwards the arguments from +/// the enclosing context (an inheriting constructor) to the specified inherited +/// base class constructor. +class CXXInheritedCtorInitExpr : public Expr { +private: + CXXConstructorDecl *Constructor; + + /// The location of the using declaration. + SourceLocation Loc; + + /// Whether this is the construction of a virtual base. + unsigned ConstructsVirtualBase : 1; + + /// Whether the constructor is inherited from a virtual base class of the + /// class that we construct. + unsigned InheritedFromVirtualBase : 1; + +public: + /// \brief Construct a C++ inheriting construction expression. + CXXInheritedCtorInitExpr(SourceLocation Loc, QualType T, + CXXConstructorDecl *Ctor, bool ConstructsVirtualBase, + bool InheritedFromVirtualBase) + : Expr(CXXInheritedCtorInitExprClass, T, VK_RValue, OK_Ordinary, false, + false, false, false), + Constructor(Ctor), Loc(Loc), + ConstructsVirtualBase(ConstructsVirtualBase), + InheritedFromVirtualBase(InheritedFromVirtualBase) { + assert(!T->isDependentType()); + } + + /// \brief Construct an empty C++ inheriting construction expression. + explicit CXXInheritedCtorInitExpr(EmptyShell Empty) + : Expr(CXXInheritedCtorInitExprClass, Empty), Constructor(nullptr), + ConstructsVirtualBase(false), InheritedFromVirtualBase(false) {} + + /// \brief Get the constructor that this expression will call. + CXXConstructorDecl *getConstructor() const { return Constructor; } + + /// \brief Determine whether this constructor is actually constructing + /// a base class (rather than a complete object). + bool constructsVBase() const { return ConstructsVirtualBase; } + CXXConstructExpr::ConstructionKind getConstructionKind() const { + return ConstructsVirtualBase ? CXXConstructExpr::CK_VirtualBase + : CXXConstructExpr::CK_NonVirtualBase; + } + + /// \brief Determine whether the inherited constructor is inherited from a + /// virtual base of the object we construct. If so, we are not responsible + /// for calling the inherited constructor (the complete object constructor + /// does that), and so we don't need to pass any arguments. + bool inheritedFromVBase() const { return InheritedFromVirtualBase; } + + SourceLocation getLocation() const LLVM_READONLY { return Loc; } + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXInheritedCtorInitExprClass; + } + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + friend class ASTStmtReader; +}; + /// \brief Represents an explicit C++ type conversion that uses "functional" /// notation (C++ [expr.type.conv]). /// diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 435df3ec3e..0fddfec8b2 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1466,6 +1466,8 @@ DEF_TRAVERSE_DECL(UsingDirectiveDecl, { DEF_TRAVERSE_DECL(UsingShadowDecl, {}) +DEF_TRAVERSE_DECL(ConstructorUsingShadowDecl, {}) + DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, { for (auto *I : D->varlists()) { TRY_TO(TraverseStmt(I)); @@ -2266,6 +2268,7 @@ DEF_TRAVERSE_STMT(CXXDefaultArgExpr, {}) DEF_TRAVERSE_STMT(CXXDefaultInitExpr, {}) DEF_TRAVERSE_STMT(CXXDeleteExpr, {}) DEF_TRAVERSE_STMT(ExprWithCleanups, {}) +DEF_TRAVERSE_STMT(CXXInheritedCtorInitExpr, {}) DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, {}) DEF_TRAVERSE_STMT(CXXStdInitializerListExpr, {}) DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index b42b33f98c..4f7bbc078d 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -66,6 +66,7 @@ def Named : Decl<1>; def BuiltinTemplate : DDecl<Template>; def Using : DDecl<Named>; def UsingShadow : DDecl<Named>; + def ConstructorUsingShadow : DDecl<UsingShadow>; def ObjCMethod : DDecl<Named>, DeclContext; def ObjCContainer : DDecl<Named, 1>, DeclContext; def ObjCCategory : DDecl<ObjCContainer>; diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index d2b0618600..03ed8aa745 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -26,6 +26,9 @@ def note_constexpr_lshift_discards : Note<"signed left shift discards bits">; def note_constexpr_invalid_function : Note< "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot " "be used in a constant expression">; +def note_constexpr_invalid_inhctor : Note< + "constructor inherited from base class %0 cannot be used in a " + "constant expression; derived class cannot be implicitly initialized">; def note_constexpr_no_return : Note< "control reached end of constexpr function">; def note_constexpr_virtual_call : Note< @@ -141,6 +144,8 @@ def note_constexpr_calls_suppressed : Note< "(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to " "see all)">; def note_constexpr_call_here : Note<"in call to '%0'">; +def note_constexpr_inherited_ctor_call_here : Note< + "in implicit initialization for inherited constructor of %0">; def note_constexpr_baa_insufficient_alignment : Note< "%select{alignment of|offset of the aligned pointer from}0 the base pointee " "object (%1 %plural{1:byte|:bytes}1) is %select{less than|not a multiple of}0 the " diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a4d39f4fbf..dcb4d70bc7 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -381,22 +381,12 @@ def err_using_decl_nested_name_specifier_is_not_base_class : Error< "using declaration refers into '%0', which is not a base class of %1">; def err_using_decl_constructor_not_in_direct_base : Error< "%0 is not a direct base of %1, cannot inherit constructors">; -def err_using_decl_constructor_conflict : Error< - "cannot inherit constructor, already inherited constructor with " - "the same signature">; -def note_using_decl_constructor_conflict_current_ctor : Note< - "conflicting constructor">; -def note_using_decl_constructor_conflict_previous_ctor : Note< - "previous constructor">; -def note_using_decl_constructor_conflict_previous_using : Note< - "previously inherited here">; -def warn_using_decl_constructor_ellipsis : Warning< - "inheriting constructor does not inherit ellipsis">, - InGroup<DiagGroup<"inherited-variadic-ctor">>; -def note_using_decl_constructor_ellipsis : Note< - "constructor declared with ellipsis here">; def err_using_decl_can_not_refer_to_class_member : Error< "using declaration cannot refer to class member">; +def err_ambiguous_inherited_constructor : Error< + "constructor of %0 inherited from multiple base class subobjects">; +def note_ambiguous_inherited_constructor_using : Note< + "inherited from base class %0 here">; def note_using_decl_class_member_workaround : Note< "use %select{an alias declaration|a typedef declaration|a reference|" "a const variable|a constexpr variable}0 instead">; @@ -415,7 +405,7 @@ def err_using_decl_template_id : Error< "using declaration cannot refer to a template specialization">; def note_using_decl_target : Note<"target of using declaration">; def note_using_decl_conflict : Note<"conflicting declaration">; -def err_using_decl_redeclaration : Error<"redeclaration of using decl">; +def err_using_decl_redeclaration : Error<"redeclaration of using declaration">; def err_using_decl_conflict : Error< "target of using declaration conflicts with declaration already in scope">; def err_using_decl_conflict_reverse : Error< @@ -1436,11 +1426,13 @@ def note_member_synthesized_at : Note< "assignment operator|move assignment operator|destructor}0 for %1 first " "required here">; def note_inhctor_synthesized_at : Note< - "inheriting constructor for %0 first required here">; + "inherited constructor for %0 first required here">; def err_missing_default_ctor : Error< - "%select{|implicit default |inheriting }0constructor for %1 must explicitly " - "initialize the %select{base class|member}2 %3 which does not have a default " - "constructor">; + "%select{constructor for %1 must explicitly initialize the|" + "implicit default constructor for %1 must explicitly initialize the|" + "cannot use constructor inherited from base class %4;}0 " + "%select{base class|member}2 %3 %select{which|which|of %1}0 " + "does not have a default constructor">; def note_due_to_dllexported_class : Note< "due to '%0' being dllexported%select{|; try compiling in C++11 mode}1">; @@ -3111,7 +3103,9 @@ def err_uninitialized_member_for_assign : Error< "non-static %select{reference|const}1 member %2 cannot use copy " "assignment operator">; def err_uninitialized_member_in_ctor : Error< - "%select{|implicit default |inheriting }0constructor for %1 must explicitly " + "%select{constructor for %1|" + "implicit default constructor for %1|" + "cannot use constructor inherited from %1:}0 must explicitly " "initialize the %select{reference|const}2 member %3">; def err_default_arg_makes_ctor_special : Error< "addition of default argument on redeclaration makes this constructor a " @@ -3160,7 +3154,8 @@ def note_ovl_candidate : Note<"candidate " "is the implicit move constructor|" "is the implicit copy assignment operator|" "is the implicit move assignment operator|" - "is an inherited constructor}0%1" + "inherited constructor|" + "inherited constructor }0%1" "%select{| has different class%diff{ (expected $ but has $)|}3,4" "| has different number of parameters (expected %3 but has %4)" "| has type mismatch at %ordinal3 parameter" @@ -3172,7 +3167,8 @@ def note_ovl_candidate : Note<"candidate " "%select{none|const|restrict|const and restrict|volatile|const and volatile" "|volatile and restrict|const, volatile, and restrict}4)}2">; -def note_ovl_candidate_inherited_constructor : Note<"inherited from here">; +def note_ovl_candidate_inherited_constructor : Note< + "constructor from base class %0 inherited here">; def note_ovl_candidate_illegal_constructor : Note< "candidate %select{constructor|template}0 ignored: " "instantiation %select{takes|would take}0 its own class type by value">; @@ -3232,7 +3228,8 @@ def note_ovl_candidate_arity : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0 %select{|template }1" + "inherited constructor|" + "inherited constructor}0 %select{|template }1" "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " "%plural{1:was|:were}4 provided">; @@ -3243,7 +3240,8 @@ def note_ovl_candidate_arity_one : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0 %select{|template }1not viable: " + "inherited constructor|" + "inherited constructor}0 %select{|template }1not viable: " "%select{requires at least|allows at most single|requires single}2 " "argument %3, but %plural{0:no|:%4}4 arguments were provided">; @@ -3255,7 +3253,8 @@ def note_ovl_candidate_deleted : Note< "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 has been " + "inherited constructor|" + "inherited constructor }0%1 has been " "%select{explicitly made unavailable|explicitly deleted|" "implicitly deleted}2">; @@ -3272,7 +3271,8 @@ def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 " + "inherited constructor|" + "inherited constructor }0%1 " "not viable: cannot convert argument of incomplete type " "%diff{$ to $|to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4" @@ -3288,7 +3288,8 @@ def note_ovl_candidate_bad_list_argument : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 " + "inherited constructor|" + "inherited constructor }0%1 " "not viable: cannot convert initializer list argument to %3">; def note_ovl_candidate_bad_overload : Note<"candidate " "%select{function|function|constructor|" @@ -3298,7 +3299,8 @@ def note_ovl_candidate_bad_overload : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1" + "inherited constructor|" + "inherited constructor }0%1" " not viable: no overload of %3 matching %2 for %ordinal4 argument">; def note_ovl_candidate_bad_conv : Note<"candidate " "%select{function|function|constructor|" @@ -3308,7 +3310,8 @@ def note_ovl_candidate_bad_conv : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1" + "inherited constructor|" + "inherited constructor }0%1" " not viable: no known conversion " "%diff{from $ to $|from argument type to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4" @@ -3324,7 +3327,8 @@ def note_ovl_candidate_bad_arc_conv : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1" + "inherited constructor|" + "inherited constructor }0%1" " not viable: cannot implicitly convert argument " "%diff{of type $ to $|type to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4 under ARC">; @@ -3336,7 +3340,8 @@ def note_ovl_candidate_bad_lvalue : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1" + "inherited constructor|" + "inherited constructor }0%1" " not viable: expects an l-value for " "%select{%ordinal3 argument|object argument}2">; def note_ovl_candidate_bad_addrspace : Note<"candidate " @@ -3347,7 +3352,8 @@ def note_ovl_candidate_bad_addrspace : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 not viable: " + "inherited constructor|" + "inherited constructor }0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) is in " "address space %3, but parameter must be in address space %4">; def note_ovl_candidate_bad_gc : Note<"candidate " @@ -3358,7 +3364,8 @@ def note_ovl_candidate_bad_gc : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 not viable: " + "inherited constructor|" + "inherited constructor }0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " "ownership, but parameter has %select{no|__weak|__strong}4 ownership">; def note_ovl_candidate_bad_ownership : Note<"candidate " @@ -3369,7 +3376,8 @@ def note_ovl_candidate_bad_ownership : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 not viable: " + "inherited constructor|" + "inherited constructor }0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has " "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" @@ -3377,7 +3385,7 @@ def note_ovl_candidate_bad_ownership : Note<"candidate " def note_ovl_candidate_bad_cvr_this : Note<"candidate " "%select{|function|||function|||||" "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|}0 not viable: " + "function (the implicit move assignment operator)||}0 not viable: " "'this' argument has type %2, but method is not marked " "%select{const|restrict|const or restrict|volatile|const or volatile|" "volatile or restrict|const, volatile, or restrict}3">; @@ -3389,7 +3397,8 @@ def note_ovl_candidate_bad_cvr : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 not viable: " + "inherited constructor|" + "inherited constructor }0%1 not viable: " "%ordinal4 argument (%2) would lose " "%select{const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}3 qualifier" @@ -3402,7 +3411,8 @@ def note_ovl_candidate_bad_unaligned : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 not viable: " + "inherited constructor|" + "inherited constructor }0%1 not viable: " "%ordinal4 argument (%2) would lose __unaligned qualifier">; def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " "%select{function|function|constructor|" @@ -3412,20 +3422,23 @@ def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1" - " not viable: cannot %select{convert from|convert from|bind}2 " + "inherited constructor|" + "inherited constructor }0%1 not viable: " + "cannot %select{convert from|convert from|bind}2 " "%select{base class pointer|superclass|base class object of type}2 %3 to " "%select{derived class pointer|subclass|derived class reference}2 %4 for " "%ordinal5 argument">; def note_ovl_candidate_bad_target : Note< "candidate %select{function|function|constructor|" - "function |function |constructor |" + "function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0 not viable: call to " + "inherited constructor|" + "inherited constructor}0 not viable: " + "call to " "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from" " %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">; def note_implicit_member_target_infer_collision : Note< @@ -4237,8 +4250,6 @@ def note_implicitly_deleted : Note< "explicitly defaulted function was implicitly deleted here">; def note_inherited_deleted_here : Note< "deleted constructor was inherited here">; -def note_cannot_inherit : Note< - "constructor cannot be inherited">; def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">, InGroup<Sentinel>; diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index ab148e19d1..0c1624fd22 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -126,6 +126,7 @@ def ArrayTypeTraitExpr : DStmt<Expr>; def ExpressionTraitExpr : DStmt<Expr>; def DependentScopeDeclRefExpr : DStmt<Expr>; def CXXConstructExpr : DStmt<Expr>; +def CXXInheritedCtorInitExpr : DStmt<Expr>; def CXXBindTemporaryExpr : DStmt<Expr>; def ExprWithCleanups : DStmt<Expr>; def CXXTemporaryObjectExpr : DStmt<CXXConstructExpr>; diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index d0c4db3120..d0f21cd71f 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -803,6 +803,7 @@ namespace clang { DeclAccessPair FoundDecl; CXXConstructorDecl *Constructor; FunctionTemplateDecl *ConstructorTmpl; + explicit operator bool() const { return Constructor; } }; // FIXME: Add an AddOverloadCandidate / AddTemplateOverloadCandidate overload // that takes one of these. @@ -818,7 +819,7 @@ namespace clang { Info.ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); if (Info.ConstructorTmpl) D = Info.ConstructorTmpl->getTemplatedDecl(); - Info.Constructor = cast<CXXConstructorDecl>(D); + Info.Constructor = dyn_cast<CXXConstructorDecl>(D); return Info; } } // end namespace clang diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 3bcac3c33c..456c1c96ee 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4256,6 +4256,13 @@ public: bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); + /// Given a derived-class using shadow declaration for a constructor and the + /// correspnding base class constructor, find or create the implicit + /// synthesized derived class constructor to use for this initialization. + CXXConstructorDecl * + findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *BaseCtor, + ConstructorUsingShadowDecl *DerivedShadow); + Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, bool HasUsingKeyword, @@ -4422,7 +4429,8 @@ public: /// \brief Determine what sort of exception specification an inheriting /// constructor of a class will have. ImplicitExceptionSpecification - ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD); + ComputeInheritingCtorExceptionSpec(SourceLocation Loc, + CXXConstructorDecl *CD); /// \brief Evaluate the implicit exception specification for a defaulted /// special member function. @@ -4491,12 +4499,6 @@ public: void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, CXXDestructorDecl *Destructor); - /// \brief Declare all inheriting constructors for the given class. - /// - /// \param ClassDecl The class declaration into which the inheriting - /// constructors will be added. - void DeclareInheritingConstructors(CXXRecordDecl *ClassDecl); - /// \brief Define the specified inheriting constructor. void DefineInheritingConstructor(SourceLocation UseLoc, CXXConstructorDecl *Constructor); @@ -5562,13 +5564,13 @@ public: bool Diagnose = true); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, + DeclAccessPair FoundDecl, const InitializedEntity &Entity, - AccessSpecifier Access, bool IsCopyBindingRefToTemp = false); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, + DeclAccessPair FoundDecl, const InitializedEntity &Entity, - AccessSpecifier Access, const PartialDiagnostic &PDiag); AccessResult CheckDestructorAccess(SourceLocation Loc, CXXDestructorDecl *Dtor, diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index e8d2b8c64a..4713721534 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1083,6 +1083,8 @@ namespace clang { DECL_USING, /// \brief A UsingShadowDecl record. DECL_USING_SHADOW, + /// \brief A ConstructorUsingShadowDecl record. + DECL_CONSTRUCTOR_USING_SHADOW, /// \brief A UsingDirecitveDecl record. DECL_USING_DIRECTIVE, /// \brief An UnresolvedUsingValueDecl record. @@ -1097,6 +1099,8 @@ namespace clang { DECL_CXX_METHOD, /// \brief A CXXConstructorDecl record. DECL_CXX_CONSTRUCTOR, + /// \brief A CXXConstructorDecl record for an inherited constructor. + DECL_CXX_INHERITED_CONSTRUCTOR, /// \brief A CXXDestructorDecl record. DECL_CXX_DESTRUCTOR, /// \brief A CXXConversionDecl record. @@ -1360,6 +1364,8 @@ namespace clang { EXPR_CXX_MEMBER_CALL, /// \brief A CXXConstructExpr record. EXPR_CXX_CONSTRUCT, + /// \brief A CXXInheritedCtorInitExpr record. + EXPR_CXX_INHERITED_CTOR_INIT, /// \brief A CXXTemporaryObjectExpr record. EXPR_CXX_TEMPORARY_OBJECT, /// \brief A CXXStaticCastExpr record. diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 60420c71fc..872ba356a9 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -474,6 +474,7 @@ namespace { void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); void VisitUsingShadowDecl(const UsingShadowDecl *D); + void VisitConstructorUsingShadowDecl(const ConstructorUsingShadowDecl *D); void VisitLinkageSpecDecl(const LinkageSpecDecl *D); void VisitAccessSpecDecl(const AccessSpecDecl *D); void VisitFriendDecl(const FriendDecl *D); @@ -713,6 +714,12 @@ void ASTDumper::dumpTypeAsChild(const Type *T) { } void ASTDumper::dumpBareDeclRef(const Decl *D) { + if (!D) { + ColorScope Color(*this, NullColor); + OS << "<<<NULL>>>"; + return; + } + { ColorScope Color(*this, DeclKindNameColor); OS << D->getDeclKindName(); @@ -1491,6 +1498,31 @@ void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) { dumpTypeAsChild(TD->getTypeForDecl()); } +void ASTDumper::VisitConstructorUsingShadowDecl( + const ConstructorUsingShadowDecl *D) { + if (D->constructsVirtualBase()) + OS << " virtual"; + + dumpChild([=] { + OS << "target "; + dumpBareDeclRef(D->getTargetDecl()); + }); + + dumpChild([=] { + OS << "nominated "; + dumpBareDeclRef(D->getNominatedBaseClass()); + OS << ' '; + dumpBareDeclRef(D->getNominatedBaseClassShadowDecl()); + }); + + dumpChild([=] { + OS << "constructed "; + dumpBareDeclRef(D->getConstructedBaseClass()); + OS << ' '; + dumpBareDeclRef(D->getConstructedBaseClassShadowDecl()); + }); +} + void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { switch (D->getLanguage()) { case LinkageSpecDecl::lang_c: OS << " C"; break; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index f68ca602c2..bfb7d02b29 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -594,6 +594,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Function: case CXXMethod: case CXXConstructor: + case ConstructorUsingShadow: case CXXDestructor: case CXXConversion: case EnumConstant: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 2a1fac8509..de06ecb4ca 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -448,6 +448,15 @@ void CXXRecordDecl::addedMember(Decl *D) { FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); if (FunTmpl) D = FunTmpl->getTemplatedDecl(); + + // FIXME: Pass NamedDecl* to addedMember? + Decl *DUnderlying = D; + if (auto *ND = dyn_cast<NamedDecl>(DUnderlying)) { + DUnderlying = ND->getUnderlyingDecl(); + if (FunctionTemplateDecl *UnderlyingFunTmpl = + dyn_cast<FunctionTemplateDecl>(DUnderlying)) + DUnderlying = UnderlyingFunTmpl->getTemplatedDecl(); + } if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { if (Method->isVirtual()) { @@ -503,15 +512,10 @@ void CXXRecordDecl::addedMember(Decl *D) { data().PlainOldData = false; } - // Technically, "user-provided" is only defined for special member - // functions, but the intent of the standard is clearly that it should apply - // to all functions. - bool UserProvided = Constructor->isUserProvided(); - if (Constructor->isDefaultConstructor()) { SMKind |= SMF_DefaultConstructor; - if (UserProvided) + if (Constructor->isUserProvided()) data().UserProvidedDefaultConstructor = true; if (Constructor->isConstexpr()) data().HasConstexprDefaultConstructor = true; @@ -529,9 +533,17 @@ void CXXRecordDecl::addedMember(Decl *D) { } else if (Constructor->isMoveConstructor()) SMKind |= SMF_MoveConstructor; } + } + // Handle constructors, including those inherited from base classes. + if (CXXConstructorDecl *Constructor = + dyn_cast<CXXConstructorDecl>(DUnderlying)) { // Record if we see any constexpr constructors which are neither copy // nor move constructors. + // C++1z [basic.types]p10: + // [...] has at least one constexpr constructor or constructor template + // (possibly inherited from a base class) that is not a copy or move + // constructor [...] if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) data().HasConstexprNonCopyMoveConstructor = true; @@ -541,8 +553,12 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++11 [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-provided // constructors [...]. + // C++11 [dcl.init.aggr]p1: + // An aggregate is an array or a class with no user-provided + // constructors (including those inherited from a base class) [...]. if (getASTContext().getLangOpts().CPlusPlus11 - ? UserProvided : !Constructor->isImplicit()) + ? Constructor->isUserProvided() + : !Constructor->isImplicit()) data().Aggregate = false; } @@ -1784,11 +1800,15 @@ SourceRange CXXCtorInitializer::getSourceRange() const { void CXXConstructorDecl::anchor() { } -CXXConstructorDecl * -CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) CXXConstructorDecl(C, nullptr, SourceLocation(), - DeclarationNameInfo(), QualType(), - nullptr, false, false, false, false); +CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, + unsigned ID, + bool Inherited) { + unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited); + auto *Result = new (C, ID, Extra) CXXConstructorDecl( + C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, + false, false, false, false, InheritedConstructor()); + Result->IsInheritingConstructor = Inherited; + return Result; } CXXConstructorDecl * @@ -1797,13 +1817,16 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, - bool isImplicitlyDeclared, bool isConstexpr) { + bool isImplicitlyDeclared, bool isConstexpr, + InheritedConstructor Inherited) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C, RD) CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, - isExplicit, isInline, - isImplicitlyDeclared, isConstexpr); + unsigned Extra = + additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0); + return new (C, RD, Extra) CXXConstructorDecl( + C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline, + isImplicitlyDeclared, isConstexpr, Inherited); } CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const { @@ -1918,23 +1941,6 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const { return true; } -const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const { - // Hack: we store the inherited constructor in the overridden method table - method_iterator It = getASTContext().overridden_methods_begin(this); - if (It == getASTContext().overridden_methods_end(this)) - return nullptr; - - return cast<CXXConstructorDecl>(*It); -} - -void -CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){ - // Hack: we store the inherited constructor in the overridden method table - assert(getASTContext().overridden_methods_size(this) == 0 && - "Base ctor already set."); - getASTContext().addOverriddenMethod(this, BaseCtor); -} - void CXXDestructorDecl::anchor() { } CXXDestructorDecl * @@ -2130,10 +2136,24 @@ NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void UsingShadowDecl::anchor() { } +UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, + SourceLocation Loc, UsingDecl *Using, + NamedDecl *Target) + : NamedDecl(K, DC, Loc, Using ? Using->getDeclName() : DeclarationName()), + redeclarable_base(C), Underlying(Target), + UsingOrNextShadow(cast<NamedDecl>(Using)) { + if (Target) + IdentifierNamespace = Target->getIdentifierNamespace(); + setImplicit(); +} + +UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, EmptyShell Empty) + : NamedDecl(K, nullptr, SourceLocation(), DeclarationName()), + redeclarable_base(C), Underlying(), UsingOrNextShadow() {} + UsingShadowDecl * UsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) UsingShadowDecl(C, nullptr, SourceLocation(), - nullptr, nullptr); + return new (C, ID) UsingShadowDecl(UsingShadow, C, EmptyShell()); } UsingDecl *UsingShadowDecl::getUsingDecl() const { @@ -2144,6 +2164,25 @@ UsingDecl *UsingShadowDecl::getUsingDecl() const { return cast<UsingDecl>(Shadow->UsingOrNextShadow); } +void ConstructorUsingShadowDecl::anchor() { } + +ConstructorUsingShadowDecl * +ConstructorUsingShadowDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation Loc, UsingDecl *Using, + NamedDecl *Target, bool IsVirtual) { + return new (C, DC) ConstructorUsingShadowDecl(C, DC, Loc, Using, Target, + IsVirtual); +} + +ConstructorUsingShadowDecl * +ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + return new (C, ID) ConstructorUsingShadowDecl(C, EmptyShell()); +} + +CXXRecordDecl *ConstructorUsingShadowDecl::getNominatedBaseClass() const { + return getUsingDecl()->getQualifier()->getAsRecordDecl(); +} + void UsingDecl::anchor() { } void UsingDecl::addShadowDecl(UsingShadowDecl *S) { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 5ef6d9d59f..bd4cf396bf 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -3008,6 +3008,13 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, break; } + case CXXInheritedCtorInitExprClass: { + const auto *ICIE = cast<CXXInheritedCtorInitExpr>(this); + if (!ICIE->getConstructor()->isTrivial() && IncludePossibleEffects) + return true; + break; + } + case LambdaExprClass: { const LambdaExpr *LE = cast<LambdaExpr>(this); for (LambdaExpr::capture_iterator I = LE->capture_begin(), diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index a47b03c0af..642cdd1a95 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -360,6 +360,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // Some C++ expressions are always class temporaries. case Expr::CXXConstructExprClass: + case Expr::CXXInheritedCtorInitExprClass: case Expr::CXXTemporaryObjectExprClass: case Expr::LambdaExprClass: case Expr::CXXStdInitializerListExprClass: diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 6771175ba6..e44cb1d23c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -997,6 +997,16 @@ void EvalInfo::addCallStack(unsigned Limit) { continue; } + // Use a different note for an inheriting constructor, because from the + // user's perspective it's not really a function at all. + if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Frame->Callee)) { + if (CD->isInheritingConstructor()) { + addDiag(Frame->CallLoc, diag::note_constexpr_inherited_ctor_call_here) + << CD->getParent(); + continue; + } + } + SmallVector<char, 128> Buffer; llvm::raw_svector_ostream Out(Buffer); describeCall(Frame, Out); @@ -3845,11 +3855,25 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, if (Info.getLangOpts().CPlusPlus11) { const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; - // FIXME: If DiagDecl is an implicitly-declared special member function, we - // should be much more explicit about why it's not constexpr. - Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1) - << DiagDecl->isConstexpr() << isa<CXXConstructorDecl>(DiagDecl) - << DiagDecl; + + // If this function is not constexpr because it is an inherited + // non-constexpr constructor, diagnose that directly. + auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl); + if (CD && CD->isInheritingConstructor()) { + auto *Inherited = CD->getInheritedConstructor().getConstructor(); + if (!Inherited->isConstexpr()) + DiagDecl = CD = Inherited; + } + + // FIXME: If DiagDecl is an implicitly-declared special member function + // or an inheriting constructor, we should be much more explicit about why + // it's not constexpr. + if (CD && CD->isInheritingConstructor()) + Info.Diag(CallLoc, diag::note_constexpr_invalid_inhctor, 1) + << CD->getInheritedConstructor().getConstructor()->getParent(); + else + Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1) + << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; Info.Note(DiagDecl->getLocation(), diag::note_declared_at); } else { Info.Diag(CallLoc, diag::note_invalid_subexpr_in_const_expr); @@ -3945,14 +3969,11 @@ static bool HandleFunctionCall(SourceLocation CallLoc, } /// Evaluate a constructor call. -static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, - ArrayRef<const Expr*> Args, +static bool HandleConstructorCall(const Expr *E, const LValue &This, + APValue *ArgValues, const CXXConstructorDecl *Definition, EvalInfo &Info, APValue &Result) { - ArgVector ArgValues(Args.size()); - if (!EvaluateArgs(Args, ArgValues, Info)) - return false; - + SourceLocation CallLoc = E->getExprLoc(); if (!Info.CheckCallLimit(CallLoc)) return false; @@ -3962,14 +3983,14 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, return false; } - CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data()); + CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is // wasteful. APValue RetVal; StmtResult Ret = {RetVal, nullptr}; - // If it's a delegating constructor, just delegate. + // If it's a delegating constructor, delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); { @@ -3993,8 +4014,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, (Definition->isTrivial() && hasFields(Definition->getParent())))) { LValue RHS; RHS.setFrom(Info.Ctx, ArgValues[0]); - return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), - RHS, Result); + return handleLValueToRValueConversion( + Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(), + RHS, Result); } // Reserve space for the struct members. @@ -4088,6 +4110,18 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed; } +static bool HandleConstructorCall(const Expr *E, const LValue &This, + ArrayRef<const Expr*> Args, + const CXXConstructorDecl *Definition, + EvalInfo &Info, APValue &Result) { + ArgVector ArgValues(Args.size()); + if (!EvaluateArgs(Args, ArgValues, Info)) + return false; + + return HandleConstructorCall(E, This, ArgValues.data(), Definition, + Info, Result); +} + //===----------------------------------------------------------------------===// // Generic Evaluation //===----------------------------------------------------------------------===// @@ -5380,6 +5414,7 @@ namespace { bool VisitCXXConstructExpr(const CXXConstructExpr *E) { return VisitCXXConstructExpr(E, E->getType()); } + bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T); bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); }; @@ -5631,7 +5666,29 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, return false; auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); - return HandleConstructorCall(E->getExprLoc(), This, Args, + return HandleConstructorCall(E, This, Args, + cast<CXXConstructorDecl>(Definition), Info, + Result); +} + +bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr( + const CXXInheritedCtorInitExpr *E) { + if (!Info.CurrentCall) { + assert(Info.checkingPotentialConstantExpression()); + return false; + } + + const CXXConstructorDecl *FD = E->getConstructor(); + if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) + return false; + + const FunctionDecl *Definition = nullptr; + auto Body = FD->getBody(Definition); + + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) + return false; + + return HandleConstructorCall(E, This, Info.CurrentCall->Arguments, cast<CXXConstructorDecl>(Definition), Info, Result); } @@ -9305,6 +9362,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::TypoExprClass: case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: + case Expr::CXXInheritedCtorInitExprClass: case Expr::CXXStdInitializerListExprClass: case Expr::CXXBindTemporaryExprClass: case Expr::ExprWithCleanupsClass: @@ -9768,17 +9826,17 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, ArrayRef<const Expr*> Args; - SourceLocation Loc = FD->getLocation(); - APValue Scratch; if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { // Evaluate the call as a constant initializer, to allow the construction // of objects of non-literal types. Info.setEvaluatingDecl(This.getLValueBase(), Scratch); - HandleConstructorCall(Loc, This, Args, CD, Info, Scratch); - } else + HandleConstructorCall(&VIE, This, Args, CD, Info, Scratch); + } else { + SourceLocation Loc = FD->getLocation(); HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr, Args, FD->getBody(), Info, Scratch, nullptr); + } return Diags.empty(); } diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index fcce9d2368..8d49c6f586 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -397,7 +397,7 @@ private: void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleInitListElements(const InitListExpr *InitList); void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); - void mangleCXXCtorType(CXXCtorType T); + void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom); void mangleCXXDtorType(CXXDtorType T); void mangleTemplateArgs(const TemplateArgumentLoc *TemplateArgs, @@ -502,6 +502,12 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { FunctionTypeDepth.pop(Saved); } + // When mangling an inheriting constructor, the bare function type used is + // that of the inherited constructor. + if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) + if (auto Inherited = CD->getInheritedConstructor()) + FD = Inherited.getConstructor(); + // Whether the mangling of a function type includes the return type depends on // the context and the nature of the function. The rules for deciding whether // the return type is included are: @@ -562,7 +568,7 @@ static bool isStdNamespace(const DeclContext *DC) { static const TemplateDecl * isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { // Check if we have a function template. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { TemplateArgs = FD->getTemplateSpecializationArgs(); return TD; @@ -1048,16 +1054,31 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, case DeclarationName::ObjCMultiArgSelector: llvm_unreachable("Can't mangle Objective-C selector names here!"); - case DeclarationName::CXXConstructorName: + case DeclarationName::CXXConstructorName: { + const CXXRecordDecl *InheritedFrom = nullptr; + const TemplateArgumentList *InheritedTemplateArgs = nullptr; + if (auto Inherited = + cast<CXXConstructorDecl>(ND)->getInheritedConstructor()) { + InheritedFrom = Inherited.getConstructor()->getParent(); + InheritedTemplateArgs = + Inherited.getConstructor()->getTemplateSpecializationArgs(); + } + if (ND == Structor) // If the named decl is the C++ constructor we're mangling, use the type // we were given. - mangleCXXCtorType(static_cast<CXXCtorType>(StructorType)); + mangleCXXCtorType(static_cast<CXXCtorType>(StructorType), InheritedFrom); else // Otherwise, use the complete constructor name. This is relevant if a // class with a constructor is declared within a constructor. - mangleCXXCtorType(Ctor_Complete); + mangleCXXCtorType(Ctor_Complete, InheritedFrom); + + // FIXME: The template arguments are part of the enclosing prefix or + // nested-name, but it's more convenient to mangle them here. + if (InheritedTemplateArgs) + mangleTemplateArgs(*InheritedTemplateArgs); break; + } case DeclarationName::CXXDestructorName: if (ND == Structor) @@ -2909,6 +2930,7 @@ recurse: case Expr::MSPropertySubscriptExprClass: case Expr::TypoExprClass: // This should no longer exist in the AST by now. case Expr::OMPArraySectionExprClass: + case Expr::CXXInheritedCtorInitExprClass: llvm_unreachable("unexpected statement kind"); // FIXME: invent manglings for all these. @@ -3688,25 +3710,33 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { Out << '_'; } -void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { +void CXXNameMangler::mangleCXXCtorType(CXXCtorType T, + const CXXRecordDecl *InheritedFrom) { // <ctor-dtor-name> ::= C1 # complete object constructor // ::= C2 # base object constructor + // ::= CI1 <type> # complete inheriting constructor + // ::= CI2 <type> # base inheriting constructor // // In addition, C5 is a comdat name with C1 and C2 in it. + Out << 'C'; + if (InheritedFrom) + Out << 'I'; switch (T) { case Ctor_Complete: - Out << "C1"; + Out << '1'; break; case Ctor_Base: - Out << "C2"; + Out << '2'; break; case Ctor_Comdat: - Out << "C5"; + Out << '5'; break; case Ctor_DefaultClosure: case Ctor_CopyingClosure: llvm_unreachable("closure constructors don't exist for the Itanium ABI!"); } + if (InheritedFrom) + mangleName(InheritedFrom); } void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index ede38626c8..2f38db40d9 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -171,10 +171,19 @@ NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { /// \brief Retrieve the record declaration stored in this nested name specifier. CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { - if (Prefix.getInt() == StoredDecl) + switch (Prefix.getInt()) { + case StoredIdentifier: + return nullptr; + + case StoredDecl: return dyn_cast<CXXRecordDecl>(static_cast<NamedDecl *>(Specifier)); - return nullptr; + case StoredTypeSpec: + case StoredTypeSpecWithTemplate: + return getAsType()->getAsCXXRecordDecl(); + } + + llvm_unreachable("Invalid NNS Kind!"); } /// \brief Whether this nested name specifier refers to a dependent diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index a05aef9f2e..9363d169ad 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -2188,6 +2188,11 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { OS << "}"; } +void StmtPrinter::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) { + // Parens are printed by the surrounding context. + OS << "<forwarded>"; +} + void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { PrintExpr(E->getSubExpr()); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 579e7e8994..c66a077996 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -1287,6 +1287,12 @@ void StmtProfiler::VisitCXXConstructExpr(const CXXConstructExpr *S) { ID.AddBoolean(S->isElidable()); } +void StmtProfiler::VisitCXXInheritedCtorInitExpr( + const CXXInheritedCtorInitExpr *S) { + VisitExpr(S); + VisitDecl(S->getConstructor()); +} + void StmtProfiler::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { VisitExplicitCastExpr(S); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index c562602d96..d683b89902 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/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/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 56e24840c8..7ed891f426 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/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/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 8373059793..508720f5b9 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/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/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 42aa94575a..6d18843591 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/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/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index e914d79355..a0158d8b4b 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/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/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 4748e6b47d..441cee54fc 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/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/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index ac00bf85cd..bbec03842c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/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/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index c77790100a..affa334410 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/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/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index d9eec8ebc6..98a918bd7d 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/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/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b0f3356e1c..a5d636e95e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/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/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index b7bed6de2d..61ea87aa9d 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/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/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 05aa18c633..de65efca2e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/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/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index ac87ae5ecd..ea1de0c642 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/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/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 1d793e330c..1ed2d40ba1 100644 --- a/lib/Sema/SemaInit.cpp +++ b/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/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 9d0cf106ef..f25d3161ae 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/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/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 4ddbfed9dd..a9a78244ba 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index dbb8c6e0c6..29cd7a70de 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/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/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index c1cf9ada71..fbfc078e98 100644 --- a/lib/Sema/TreeTransform.h +++ b/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/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 792fac99e5..22ead2b57c 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/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/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index f993cf48a7..6fc3a6a153 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/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/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 69b7d97243..f5db031929 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/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/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 30b4a3ebe2..4fa016cc89 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/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/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 04a2d6bd8c..0940dd27d4 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/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/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 333a70fe61..2170936b54 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/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/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index e4ba1be4ba..a7fbdb5a37 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/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: diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp index d1562d4cd1..f32b239765 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp @@ -53,16 +53,17 @@ namespace InhCtor { int n = b.T(); // expected-error {{'T' is a protected member of 'InhCtor::A'}} // expected-note@-15 {{declared protected here}} + // FIXME: EDG and GCC reject this too, but it's not clear why it would be + // ill-formed. template<typename T> struct S : T { - struct U : S { + struct U : S { // expected-note 6{{candidate}} using S::S; }; using T::T; }; - - S<A>::U ua(0); - S<B>::U ub(0); + S<A>::U ua(0); // expected-error {{no match}} + S<B>::U ub(0); // expected-error {{no match}} template<typename T> struct X : T { diff --git a/test/CXX/basic/basic.types/p10.cpp b/test/CXX/basic/basic.types/p10.cpp index 19258f80f5..31ef6b62ce 100644 --- a/test/CXX/basic/basic.types/p10.cpp +++ b/test/CXX/basic/basic.types/p10.cpp @@ -141,3 +141,45 @@ constexpr int arb(int n) { } constexpr long Overflow[ // expected-error {{constexpr variable cannot have non-literal type 'long const[(1 << 30) << 2]'}} (1 << 30) << 2]{}; // expected-warning {{requires 34 bits to represent}} + +namespace inherited_ctor { + struct A { constexpr A(int); }; + struct B : A { + B(); + using A::A; + }; + constexpr int f(B) { return 0; } // ok + + struct C { constexpr C(int); }; + struct D : C { // expected-note {{because}} + D(int); + using C::C; + }; + constexpr int f(D) { return 0; } // expected-error {{not a literal type}} + + // This one is a bit odd: F inherits E's default constructor, which is + // constexpr. Because F has a constructor of its own, it doesn't declare a + // default constructor hiding E's one. + struct E {}; + struct F : E { + F(int); + using E::E; + }; + constexpr int f(F) { return 0; } + + // FIXME: Is this really the right behavior? We presumably should be checking + // whether the inherited constructor would be a copy or move constructor for + // the derived class, not for the base class. + struct G { constexpr G(const G&); }; + struct H : G { // expected-note {{because}} + using G::G; + }; + constexpr int f(H) { return 0; } // expected-error {{not a literal type}} + + struct J; + struct I { constexpr I(const J&); }; + struct J : I { + using I::I; + }; + constexpr int f(J) { return 0; } +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp new file mode 100644 index 0000000000..3e04d5094a --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p15.cpp @@ -0,0 +1,81 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +struct B1 { // expected-note 2{{candidate}} + B1(int); // expected-note {{candidate}} +}; + +struct B2 { // expected-note 2{{candidate}} + B2(int); // expected-note {{candidate}} +}; + +struct D1 : B1, B2 { // expected-note 2{{candidate}} + using B1::B1; // expected-note 3{{inherited here}} + using B2::B2; // expected-note 3{{inherited here}} +}; +D1 d1(0); // expected-error {{ambiguous}} + +struct D2 : B1, B2 { + using B1::B1; + using B2::B2; + D2(int); +}; +D2 d2(0); // ok + + +// The emergent behavior of implicit special members is a bit odd when +// inheriting from multiple base classes. +namespace default_ctor { + struct C; + struct D; + + struct A { // expected-note 4{{candidate}} + A(); // expected-note {{candidate}} + + A(C &&); // expected-note {{candidate}} + C &operator=(C&&); // expected-note {{candidate}} + + A(D &&); // expected-note {{candidate}} + D &operator=(D&&); // expected-note {{candidate}} + }; + + struct B { // expected-note 4{{candidate}} + B(); // expected-note {{candidate}} + + B(C &&); // expected-note {{candidate}} + C &operator=(C&&); // expected-note {{candidate}} + + B(D &&); // expected-note {{candidate}} + D &operator=(D&&); // expected-note {{candidate}} + }; + + struct C : A, B { + using A::A; + using A::operator=; + using B::B; + using B::operator=; + }; + struct D : A, B { + using A::A; // expected-note 5{{inherited here}} + using A::operator=; + using B::B; // expected-note 5{{inherited here}} + using B::operator=; + + D(int); + D(const D&); // expected-note {{candidate}} + D &operator=(const D&); // expected-note {{candidate}} + }; + + C c; + void f(C c) { + C c2(static_cast<C&&>(c)); + c = static_cast<C&&>(c); + } + + // D does not declare D(), D(D&&), nor operator=(D&&), so the base class + // versions are inherited. + D d; // expected-error {{ambiguous}} + void f(D d) { + D d2(static_cast<D&&>(d)); // expected-error {{ambiguous}} + d = static_cast<D&&>(d); // expected-error {{ambiguous}} + } +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p18.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p18.cpp new file mode 100644 index 0000000000..b9fca4bd5b --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p18.cpp @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +struct Public {} public_; +struct Protected {} protected_; +struct Private {} private_; + +class A { +public: + A(Public); + void f(Public); + +protected: + A(Protected); // expected-note {{protected here}} + void f(Protected); + +private: + A(Private); // expected-note 4{{private here}} + void f(Private); // expected-note {{private here}} + + friend void Friend(); +}; + +class B : private A { + using A::A; // ok + using A::f; // expected-error {{private member}} + + void f() { + B a(public_); + B b(protected_); + B c(private_); // expected-error {{private}} + } + + B(Public p, int) : B(p) {} + B(Protected p, int) : B(p) {} + B(Private p, int) : B(p) {} // expected-error {{private}} +}; + +class C : public B { + C(Public p) : B(p) {} + // There is no access check on the conversion from derived to base here; + // protected constructors of A act like protected constructors of B. + C(Protected p) : B(p) {} + C(Private p) : B(p) {} // expected-error {{private}} +}; + +void Friend() { + // There is no access check on the conversion from derived to base here. + B a(public_); + B b(protected_); + B c(private_); +} + +void NonFriend() { + B a(public_); + B b(protected_); // expected-error {{protected}} + B c(private_); // expected-error {{private}} +} + +namespace ProtectedAccessFromMember { +namespace a { + struct ES { + private: + ES(const ES &) = delete; + protected: + ES(const char *); + }; +} +namespace b { + struct DES : a::ES { + DES *f(); + private: + using a::ES::ES; + }; +} +b::DES *b::DES::f() { return new b::DES("foo"); } + +} diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp index a43d9e019e..781a1a1824 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s // C++03 [namespace.udecl]p4: // A using-declaration used as a member-declaration shall refer to a @@ -206,8 +207,33 @@ namespace test4 { using Unrelated::foo; // expected-error {{not a base class}} using C::foo; // legal in C++03 using Subclass::foo; // legal in C++03 +#if __cplusplus >= 201103L + // expected-error@-3 {{refers to its own class}} + // expected-error@-3 {{refers into 'Subclass::', which is not a base class}} +#endif - int bar(); //expected-note {{target of using declaration}} + int bar(); +#if __cplusplus < 201103L + // expected-note@-2 {{target of using declaration}} +#endif using C::bar; // expected-error {{refers to its own class}} }; } + +namespace test5 { + struct B; + struct A { + A(const B&); + B &operator=(const B&); + }; + struct B : A { +#if __cplusplus >= 201103L + using A::A; +#endif + using A::operator=; + }; + void test(B b) { + B b2(b); + b2 = b; + } +} diff --git a/test/CXX/drs/dr15xx.cpp b/test/CXX/drs/dr15xx.cpp index 7472be72c2..71f2f719fb 100644 --- a/test/CXX/drs/dr15xx.cpp +++ b/test/CXX/drs/dr15xx.cpp @@ -22,6 +22,31 @@ namespace dr1560 { // dr1560: 3.5 const X &x = true ? get() : throw 0; } +namespace dr1573 { // dr1573: 3.9 +#if __cplusplus >= 201103L + // ellipsis is inherited (p0136r1 supersedes this part). + struct A { A(); A(int, char, ...); }; + struct B : A { using A::A; }; + B b(1, 'x', 4.0, "hello"); // ok + + // inherited constructor is effectively constexpr if the user-written constructor would be + struct C { C(); constexpr C(int) {} }; + struct D : C { using C::C; }; + constexpr D d = D(0); // ok + struct E : C { using C::C; A a; }; // expected-note {{non-literal type}} + constexpr E e = E(0); // expected-error {{non-literal type}} + // FIXME: This diagnostic is pretty bad; we should explain that the problem + // is that F::c would be initialized by a non-constexpr constructor. + struct F : C { using C::C; C c; }; // expected-note {{here}} + constexpr F f = F(0); // expected-error {{constant expression}} expected-note {{constructor inherited from base class 'C'}} + + // inherited constructor is effectively deleted if the user-written constructor would be + struct G { G(int); }; // expected-note {{declared here}} + struct H : G { using G::G; G g; }; // expected-error {{cannot use constructor inherited from base class 'G'; member 'g' of 'dr1573::H' does not have a default constructor}} expected-note {{declared here}} + H h(0); // expected-note {{first required here}} +#endif +} + #if __cplusplus >= 201103L namespace std { typedef decltype(sizeof(int)) size_t; diff --git a/test/CXX/drs/dr16xx.cpp b/test/CXX/drs/dr16xx.cpp index ddb7d16869..65467e35e4 100644 --- a/test/CXX/drs/dr16xx.cpp +++ b/test/CXX/drs/dr16xx.cpp @@ -18,8 +18,8 @@ namespace dr1684 { // dr1684: 3.6 #endif } +namespace dr1631 { // dr1631: 3.7 #if __cplusplus >= 201103L -namespace dr1631 { // dr1631: 3.7 c++11 // Incorrect overload resolution for single-element initializer-list struct A { int a[1]; }; @@ -41,5 +41,22 @@ namespace dr1631 { // dr1631: 3.7 c++11 f({0}, {{1}}); // expected-error{{call to 'f' is ambiguous}} } } -} // dr1631 #endif +} + +namespace dr1645 { // dr1645: 3.9 +#if __cplusplus >= 201103L + struct A { // expected-note 2{{candidate}} + constexpr A(int, float = 0); // expected-note 2{{candidate}} + explicit A(int, int = 0); // expected-note 2{{candidate}} + A(int, int, int = 0) = delete; // expected-note {{candidate}} + }; + + struct B : A { // expected-note 2{{candidate}} + using A::A; // expected-note 7{{inherited here}} + }; + + constexpr B a(0); // expected-error {{ambiguous}} + constexpr B b(0, 0); // expected-error {{ambiguous}} +#endif +} diff --git a/test/CXX/drs/dr17xx.cpp b/test/CXX/drs/dr17xx.cpp index 1ab8c40d39..a917412adc 100644 --- a/test/CXX/drs/dr17xx.cpp +++ b/test/CXX/drs/dr17xx.cpp @@ -3,19 +3,63 @@ // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +#if __cplusplus < 201103L // expected-no-diagnostics +#endif +namespace dr1715 { // dr1715: 3.9 +#if __cplusplus >= 201103L + struct B { + template<class T> B(T, typename T::Q); + }; + + class S { + using Q = int; + template<class T> friend B::B(T, typename T::Q); + }; + + struct D : B { + using B::B; + }; + struct E : B { // expected-note 2{{candidate}} + template<class T> E(T t, typename T::Q q) : B(t, q) {} // expected-note {{'Q' is a private member}} + }; + + B b(S(), 1); + D d(S(), 2); + E e(S(), 3); // expected-error {{no match}} +#endif +} + +namespace dr1736 { // dr1736: 3.9 +#if __cplusplus >= 201103L +struct S { + template <class T> S(T t) { + struct L : S { + using S::S; + }; + typename T::type value; // expected-error {{no member}} + L l(value); // expected-note {{instantiation of}} + } +}; +struct Q { typedef int type; } q; +S s(q); // expected-note {{instantiation of}} +#endif +} + +namespace dr1756 { // dr1756: 3.7 #if __cplusplus >= 201103L -namespace dr1756 { // dr1756: 3.7 c++11 // Direct-list-initialization of a non-class object int a{0}; struct X { operator int(); } x; int b{x}; -} // dr1756 +#endif +} -namespace dr1758 { // dr1758: 3.7 c++11 +namespace dr1758 { // dr1758: 3.7 +#if __cplusplus >= 201103L // Explicit conversion in copy/move list initialization struct X { X(); }; @@ -30,5 +74,5 @@ namespace dr1758 { // dr1758: 3.7 c++11 operator A() { return A(); } } b; A a{b}; -} // dr1758 #endif +} diff --git a/test/CXX/drs/dr19xx.cpp b/test/CXX/drs/dr19xx.cpp index 368e7b3416..5b626dd808 100644 --- a/test/CXX/drs/dr19xx.cpp +++ b/test/CXX/drs/dr19xx.cpp @@ -39,6 +39,31 @@ namespace dr1902 { // dr1902: 3.7 #endif } +namespace dr1903 { + namespace A { + struct a {}; + int a; + namespace B { + int b; + } + using namespace B; + namespace { + int c; + } + namespace D { + int d; + } + using D::d; + } + namespace X { + using A::a; + using A::b; + using A::c; + using A::d; + struct a *p; + } +} + namespace dr1909 { // dr1909: yes struct A { template<typename T> struct A {}; // expected-error {{member 'A' has the same name as its class}} @@ -54,22 +79,52 @@ namespace dr1909 { // dr1909: yes }; } -#if __cplusplus >= 201103L namespace dr1940 { // dr1940: yes +#if __cplusplus >= 201103L static union { static_assert(true, ""); // ok static_assert(false, ""); // expected-error {{static_assert failed}} }; -} #endif +} +namespace dr1941 { // dr1941: 3.9 #if __cplusplus >= 201402L +template<typename X> +struct base { + template<typename T> + base(T a, T b, decltype(void(*T()), 0) = 0) { + while (a != b) (void)*a++; + } + + template<typename T> + base(T a, X x, decltype(void(T(0) * 1), 0) = 0) { + for (T n = 0; n != a; ++n) (void)X(x); + } +}; + +struct derived : base<int> { + using base::base; +}; + +struct iter { + iter operator++(int); + int operator*(); + friend bool operator!=(iter, iter); +} it, end; + +derived d1(it, end); +derived d2(42, 9); +#endif +} + namespace dr1947 { // dr1947: yes +#if __cplusplus >= 201402L unsigned o = 0'01; // ok unsigned b = 0b'01; // expected-error {{invalid digit 'b' in octal constant}} unsigned x = 0x'01; // expected-error {{invalid suffix 'x'01' on integer constant}} -} #endif +} #if __cplusplus >= 201103L // dr1948: yes @@ -77,10 +132,58 @@ unsigned x = 0x'01; // expected-error {{invalid suffix 'x'01' on integer constan void *operator new(__SIZE_TYPE__) noexcept { return nullptr; } // expected-error{{exception specification in declaration does not match previous declaration}} #endif +namespace dr1959 { // dr1959: 3.9 #if __cplusplus >= 201103L + struct b; + struct c; + struct a { + a() = default; + a(const a &) = delete; // expected-note 2{{deleted}} + a(const b &) = delete; // not inherited + a(c &&) = delete; // expected-note {{deleted}} + template<typename T> a(T) = delete; + }; + + struct b : a { // expected-note {{copy constructor of 'b' is implicitly deleted because base class 'dr1959::a' has a deleted copy constructor}} + using a::a; + }; + + a x; + b y = x; // expected-error {{deleted}} + b z = z; // expected-error {{deleted}} + + // FIXME: It's not really clear that this matches the intent, but it's + // consistent with the behavior for assignment operators. + struct c : a { + using a::a; + c(const c &); + }; + c q(static_cast<c&&>(q)); // expected-error {{call to deleted}} +#endif +} + namespace dr1968 { // dr1968: yes -static_assert(&typeid(int) == &typeid(int), ""); // expected-error{{not an integral constant expression}} +#if __cplusplus >= 201103L + static_assert(&typeid(int) == &typeid(int), ""); // expected-error{{not an integral constant expression}} +#endif } + +namespace dr1991 { // dr1991: 3.9 +#if __cplusplus >= 201103L + struct A { + A(int, int) = delete; + }; + + struct B : A { + using A::A; + B(int, int, int = 0); + }; + + // FIXME: As a resolution to an open DR against P0136R1, we treat derived + // class constructors as better than base class constructors in the presence + // of ambiguity. + B b(0, 0); // ok, calls B constructor #endif +} // dr1994: dup 529 diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp index 945a767584..c717d97797 100644 --- a/test/CXX/except/except.spec/p14.cpp +++ b/test/CXX/except/except.spec/p14.cpp @@ -124,14 +124,20 @@ namespace InhCtor { template<typename T> struct Throw { Throw() throw(T); }; - struct Derived : Base, Throw<X<3>> { + struct Derived1 : Base, X<5> { + using Base::Base; + int n; + }; + struct Derived2 : Base, Throw<X<3>> { using Base::Base; - Throw<X<4>> x; }; - struct Test { - friend Derived::Derived(X<0>) throw(X<3>, X<4>); - friend Derived::Derived(X<1>) noexcept(false); - friend Derived::Derived(X<2>) throw(X<2>, X<3>, X<4>); + struct Derived3 : Base { + using Base::Base; + Throw<X<4>> x; }; - static_assert(!noexcept(Derived{X<5>{}}), ""); + static_assert(noexcept(Derived1(X<0>())), ""); + static_assert(!noexcept(Derived1(X<1>())), ""); + static_assert(!noexcept(Derived1(X<2>())), ""); + static_assert(!noexcept(Derived2(X<0>())), ""); + static_assert(!noexcept(Derived3(X<0>())), ""); } diff --git a/test/CXX/special/class.inhctor/p1.cpp b/test/CXX/special/class.inhctor/p1.cpp index fa0416e117..c006abe350 100644 --- a/test/CXX/special/class.inhctor/p1.cpp +++ b/test/CXX/special/class.inhctor/p1.cpp @@ -1,53 +1,55 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -// Per a core issue (no number yet), an ellipsis is always dropped. -struct A { - A(...); // expected-note {{here}} - A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 9{{here}} expected-note 2{{constructor cannot be inherited}} - A(int = 0, int = 0, ...); // expected-note {{here}} +// +// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior +// for the wording that used to be there. - template<typename T> A(T, int = 0, ...); // expected-note 5{{here}} +struct A { // expected-note 8{{candidate is the implicit}} + A(...); // expected-note 4{{candidate constructor}} expected-note 4{{candidate inherited constructor}} + A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 3{{candidate constructor}} expected-note 3{{candidate inherited constructor}} + A(int = 0, int = 0, ...); // expected-note 3{{candidate constructor}} expected-note 3{{candidate inherited constructor}} - template<typename T, int N> A(const T (&)[N]); // expected-note 2{{here}} expected-note {{constructor cannot be inherited}} - template<typename T, int N> A(const T (&)[N], int = 0); // expected-note 2{{here}} + template<typename T> A(T, int = 0, ...); // expected-note 3{{candidate constructor}} expected-note 3{{candidate inherited constructor}} + + template<typename T, int N> A(const T (&)[N]); // expected-note {{candidate constructor}} expected-note {{candidate inherited constructor}} + template<typename T, int N> A(const T (&)[N], int = 0); // expected-note {{candidate constructor}} expected-note {{candidate inherited constructor}} }; -struct B : A { // expected-note 6{{candidate}} - using A::A; // expected-warning 4{{inheriting constructor does not inherit ellipsis}} expected-note 16{{candidate}} expected-note 3{{deleted constructor was inherited here}} +struct B : A { // expected-note 4{{candidate is the implicit}} + using A::A; // expected-note 19{{inherited here}} + B(void*); }; struct C {} c; -B b0{}; -// expected-error@-1 {{call to implicitly-deleted default constructor of 'B'}} -// expected-note@-8 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}} +A a0{}; // expected-error {{ambiguous}} +B b0{}; // expected-error {{ambiguous}} -B b1{1}; -// expected-error@-1 {{call to deleted constructor of 'B'}} +A a1{1}; // expected-error {{ambiguous}} +B b1{1}; // expected-error {{ambiguous}} -B b2{1,2}; -// expected-error@-1 {{call to deleted constructor of 'B'}} +A a2{1,2}; // expected-error {{ambiguous}} +B b2{1,2}; // expected-error {{ambiguous}} -B b3{1,2,3}; -// ok +A a3{1,2,3}; // ok +B b3{1,2,3}; // ok -B b4{1,2,3,4}; -// ok +A a4{1,2,3,4}; // ok +B b4{1,2,3,4}; // ok -B b5{1,2,3,4,5}; -// expected-error@-1 {{no matching constructor for initialization of 'B'}} +A a5{1,2,3,4,5}; // ok +B b5{1,2,3,4,5}; // ok -B b6{c}; -// ok +A a6{c}; // ok +B b6{c}; // ok -B b7{c,0}; -// ok +A a7{c,0}; // ok +B b7{c,0}; // ok -B b8{c,0,1}; -// expected-error@-1 {{no matching constructor}} +A a8{c,0,1}; // ok +B b8{c,0,1}; // ok -B b9{"foo"}; -// FIXME: explain why the inheriting constructor was deleted -// expected-error@-2 {{call to deleted constructor of 'B'}} +A a9{"foo"}; // expected-error {{ambiguous}} +B b9{"foo"}; // expected-error {{ambiguous}} namespace PR15755 { struct X { diff --git a/test/CXX/special/class.inhctor/p2.cpp b/test/CXX/special/class.inhctor/p2.cpp index d1c16ff886..f84dc64875 100644 --- a/test/CXX/special/class.inhctor/p2.cpp +++ b/test/CXX/special/class.inhctor/p2.cpp @@ -1,4 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -verify %s +// +// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior +// for the wording that used to be there. template<int> struct X {}; @@ -8,10 +11,10 @@ template<int> struct X {}; // - absence or presence of explicit // - absence or presence of constexpr struct A { - A(X<0>) {} // expected-note 2{{here}} + A(X<0>) {} // expected-note 4{{here}} constexpr A(X<1>) {} - explicit A(X<2>) {} // expected-note 3{{here}} - explicit constexpr A(X<3>) {} // expected-note 2{{here}} + explicit A(X<2>) {} // expected-note 6{{here}} + explicit constexpr A(X<3>) {} // expected-note 4{{here}} }; A a0 { X<0>{} }; @@ -36,7 +39,7 @@ constexpr A a3ic = { X<3>{} }; // expected-error {{constructor is explicit}} struct B : A { - using A::A; // expected-note 7{{here}} + using A::A; }; B b0 { X<0>{} }; @@ -62,14 +65,19 @@ constexpr B b3ic = { X<3>{} }; // expected-error {{constructor is explicit}} // 'constexpr' is OK even if the constructor doesn't obey the constraints. struct NonLiteral { NonLiteral(); }; -struct NonConstexpr { NonConstexpr(); constexpr NonConstexpr(int); }; // expected-note {{here}} +struct NonConstexpr { NonConstexpr(); constexpr NonConstexpr(int); }; struct Constexpr { constexpr Constexpr(int) {} }; struct BothNonLiteral : NonLiteral, Constexpr { using Constexpr::Constexpr; }; // expected-note {{base class 'NonLiteral' of non-literal type}} constexpr BothNonLiteral bothNL{42}; // expected-error {{constexpr variable cannot have non-literal type 'const BothNonLiteral'}} -struct BothNonConstexpr : NonConstexpr, Constexpr { using Constexpr::Constexpr; }; // expected-note {{non-constexpr constructor 'NonConstexpr}} -constexpr BothNonConstexpr bothNC{42}; // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'BothNonConstexpr(42)'}} +// FIXME: This diagnostic is not very good. We should explain that the problem is that base class NonConstexpr cannot be initialized. +struct BothNonConstexpr + : NonConstexpr, + Constexpr { + using Constexpr::Constexpr; // expected-note {{here}} +}; +constexpr BothNonConstexpr bothNC{42}; // expected-error {{must be initialized by a constant expression}} expected-note {{inherited from base class 'Constexpr'}} struct ConstexprEval { @@ -87,25 +95,25 @@ static_assert(ce.k == 'a', ""); static_assert(ce.k2 == 'x', ""); -struct TemplateCtors { - constexpr TemplateCtors() {} - template<template<int> class T> TemplateCtors(X<0>, T<0>); - template<int N> TemplateCtors(X<1>, X<N>); - template<typename T> TemplateCtors(X<2>, T); +struct TemplateCtors { // expected-note 2{{candidate constructor (the implicit}} + constexpr TemplateCtors() {} // expected-note {{candidate inherited constructor}} + template<template<int> class T> TemplateCtors(X<0>, T<0>); // expected-note {{here}} expected-note {{candidate inherited constructor}} + template<int N> TemplateCtors(X<1>, X<N>); // expected-note {{here}} expected-note {{candidate inherited constructor}} + template<typename T> TemplateCtors(X<2>, T); // expected-note {{here}} expected-note {{candidate inherited constructor}} - template<typename T = int> TemplateCtors(int, int = 0, int = 0); // expected-note {{inherited from here}} + template<typename T = int> TemplateCtors(int, int = 0, int = 0); }; -struct UsingTemplateCtors : TemplateCtors { // expected-note 2{{candidate is the implicit}} - using TemplateCtors::TemplateCtors; // expected-note 4{{here}} expected-note {{candidate}} +struct UsingTemplateCtors : TemplateCtors { // expected-note 2{{candidate constructor (the implicit}} + using TemplateCtors::TemplateCtors; // expected-note 6{{inherited here}} - constexpr UsingTemplateCtors(X<0>, X<0>) {} - constexpr UsingTemplateCtors(X<1>, X<1>) {} - constexpr UsingTemplateCtors(X<2>, X<2>) {} + constexpr UsingTemplateCtors(X<0>, X<0>) {} // expected-note {{not viable}} + constexpr UsingTemplateCtors(X<1>, X<1>) {} // expected-note {{not viable}} + constexpr UsingTemplateCtors(X<2>, X<2>) {} // expected-note {{not viable}} - template<int = 0> constexpr UsingTemplateCtors(int) {} // expected-note {{candidate}} - template<typename T = void> constexpr UsingTemplateCtors(int, int) {} - template<typename T, typename U> constexpr UsingTemplateCtors(int, int, int) {} + template<int = 0> constexpr UsingTemplateCtors(int) {} // expected-note {{not viable}} + template<typename T = void> constexpr UsingTemplateCtors(int, int) {} // expected-note {{not viable}} + template<typename T, typename U> constexpr UsingTemplateCtors(int, int, int) {} // expected-note {{couldn't infer}} }; template<int> struct Y {}; @@ -116,6 +124,10 @@ constexpr UsingTemplateCtors uct4{ X<1>{}, X<1>{} }; constexpr UsingTemplateCtors uct5{ X<2>{}, 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} constexpr UsingTemplateCtors uct6{ X<2>{}, X<2>{} }; -constexpr UsingTemplateCtors utc7{ 0 }; // expected-error {{ambiguous}} +constexpr UsingTemplateCtors utc7{ 0 }; // ok constexpr UsingTemplateCtors utc8{ 0, 0 }; // ok -constexpr UsingTemplateCtors utc9{ 0, 0, 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}} +// FIXME: The standard says that UsingTemplateCtors' (int, int, int) constructor +// hides the one from TemplateCtors, even though the template parameter lists +// don't match. It's not clear that that's *really* the intent, and it's not +// what other compilers do. +constexpr UsingTemplateCtors utc9{ 0, 0, 0 }; // expected-error {{no matching constructor}} diff --git a/test/CXX/special/class.inhctor/p3.cpp b/test/CXX/special/class.inhctor/p3.cpp index 7aaaa7a6f0..7f054874e0 100644 --- a/test/CXX/special/class.inhctor/p3.cpp +++ b/test/CXX/special/class.inhctor/p3.cpp @@ -1,8 +1,11 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// +// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior +// for the wording that used to be there. struct B1 { - B1(int); - B1(int, int); + B1(int); // expected-note 3{{target of using}} + B1(int, int); // expected-note 3{{target of using}} }; struct D1 : B1 { using B1::B1; @@ -11,48 +14,56 @@ D1 d1a(1), d1b(1, 1); D1 fd1() { return 1; } -struct B2 { +struct B2 { // expected-note 2{{candidate}} explicit B2(int, int = 0, int = 0); }; -struct D2 : B2 { // expected-note 2 {{candidate constructor}} - using B2::B2; +struct D2 : B2 { // expected-note 2{{candidate constructor}} + using B2::B2; // expected-note 2{{inherited here}} }; D2 d2a(1), d2b(1, 1), d2c(1, 1, 1); D2 fd2() { return 1; } // expected-error {{no viable conversion}} -struct B3 { - B3(void*); // expected-note {{inherited from here}} +struct B3 { // expected-note 2{{candidate}} + B3(void*); // expected-note {{candidate}} }; -struct D3 : B3 { // expected-note 2 {{candidate constructor}} - using B3::B3; // expected-note {{candidate constructor (inherited)}} +struct D3 : B3 { // expected-note 2{{candidate constructor}} + using B3::B3; // expected-note 3{{inherited here}} }; D3 fd3() { return 1; } // expected-error {{no viable conversion}} template<typename T> struct T1 : B1 { - using B1::B1; + using B1::B1; // expected-note 2{{using declaration}} }; template<typename T> struct T2 : T1<T> { - using T1<int>::T1; + using T1<int>::T1; // expected-note 2{{using declaration}} }; template<typename T> struct T3 : T1<int> { - using T1<T>::T1; + using T1<T>::T1; // expected-note 2{{using declaration}} }; struct U { - friend T1<int>::T1(int); - friend T1<int>::T1(int, int); - friend T2<int>::T2(int); - friend T2<int>::T2(int, int); - friend T3<int>::T3(int); - friend T3<int>::T3(int, int); + // [dcl.meaning]p1: "the member shall not merely hav ebeen introduced by a + // using-declaration in the scope of the class [...] nominated by the + // nested-name-specifier of the declarator-id" + friend T1<int>::T1(int); // expected-error {{cannot befriend target of using declaration}} + friend T1<int>::T1(int, int); // expected-error {{cannot befriend target of using declaration}} + friend T2<int>::T2(int); // expected-error {{cannot befriend target of using declaration}} + friend T2<int>::T2(int, int); // expected-error {{cannot befriend target of using declaration}} + friend T3<int>::T3(int); // expected-error {{cannot befriend target of using declaration}} + friend T3<int>::T3(int, int); // expected-error {{cannot befriend target of using declaration}} }; struct B4 { - template<typename T> explicit B4(T, int = 0); + template<typename T> explicit B4(T, int = 0); // expected-note 2{{here}} }; template<typename T> struct T4 : B4 { - using B4::B4; // expected-note {{here}} + using B4::B4; template<typename U> T4(U); }; +template<typename T> struct U4 : T4<T> { + using T4<T>::T4; +}; T4<void> t4a = {0}; T4<void> t4b = {0, 0}; // expected-error {{chosen constructor is explicit}} +U4<void> u4a = {0}; +U4<void> u4b = {0, 0}; // expected-error {{chosen constructor is explicit}} diff --git a/test/CXX/special/class.inhctor/p4.cpp b/test/CXX/special/class.inhctor/p4.cpp index ae1f7a5703..69fbea3e0e 100644 --- a/test/CXX/special/class.inhctor/p4.cpp +++ b/test/CXX/special/class.inhctor/p4.cpp @@ -1,4 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -verify %s +// +// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior +// for the wording that used to be there. template<int> struct X {}; @@ -8,20 +11,20 @@ struct A { public: A(X<0>) {} protected: - A(X<1>) {} + A(X<1>) {} // expected-note 2{{declared protected here}} private: - A(X<2>) {} // expected-note {{declared private here}} + A(X<2>) {} // expected-note 2{{declared private here}} friend class FA; }; struct B : A { - using A::A; // expected-error {{private constructor}} expected-note {{implicitly declared protected here}} + using A::A; friend class FB; }; B b0{X<0>{}}; B b1{X<1>{}}; // expected-error {{calling a protected constructor}} -B b2{X<2>{}}; // expected-note {{first required here}} +B b2{X<2>{}}; // expected-error {{calling a private constructor}} struct C : B { C(X<0> x) : B(x) {} @@ -34,7 +37,7 @@ struct FB { }; struct FA : A { - using A::A; // expected-note 2{{here}} + using A::A; }; FA fa0{X<0>{}}; FA fa1{X<1>{}}; // expected-error {{calling a protected constructor}} @@ -47,7 +50,7 @@ struct G { template<typename T> G(T*) = delete; // expected-note {{'G<const char>' has been explicitly marked deleted here}} }; struct H : G { - using G::G; // expected-note 2{{deleted constructor was inherited here}} + using G::G; }; H h1(5); // expected-error {{call to deleted constructor of 'H'}} H h2("foo"); // expected-error {{call to deleted constructor of 'H'}} @@ -57,15 +60,15 @@ H h2("foo"); // expected-error {{call to deleted constructor of 'H'}} // same signature. namespace DRnnnn { struct A { - constexpr A(int, float = 0) {} - explicit A(int, int = 0) {} // expected-note {{constructor cannot be inherited}} + constexpr A(int, float = 0) {} // expected-note {{candidate}} + explicit A(int, int = 0) {} // expected-note {{candidate}} - A(int, int, int = 0) = delete; + A(int, int, int = 0) = delete; // expected-note {{deleted}} }; struct B : A { - using A::A; // expected-note {{here}} + using A::A; // expected-note 3{{inherited here}} }; constexpr B b0(0, 0.0f); // ok, constexpr - B b1(0, 1); // expected-error {{call to deleted constructor of 'DRnnnn::B'}} + B b1(0, 1); // expected-error {{call to constructor of 'DRnnnn::B' is ambiguous}} } diff --git a/test/CXX/special/class.inhctor/p7.cpp b/test/CXX/special/class.inhctor/p7.cpp index a57e8558f5..c22a43a618 100644 --- a/test/CXX/special/class.inhctor/p7.cpp +++ b/test/CXX/special/class.inhctor/p7.cpp @@ -1,47 +1,48 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// +// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior +// for the wording that used to be there. -// Straight from the standard -struct B1 { - B1(int); // expected-note {{previous constructor}} expected-note {{conflicting constructor}} +struct B1 { // expected-note 2{{candidate}} + B1(int); // expected-note {{candidate}} }; -struct B2 { - B2(int); // expected-note {{conflicting constructor}} +struct B2 { // expected-note 2{{candidate}} + B2(int); // expected-note {{candidate}} }; -struct D1 : B1, B2 { - using B1::B1; // expected-note {{inherited here}} - using B2::B2; // expected-error {{already inherited constructor with the same signature}} +struct D1 : B1, B2 { // expected-note 2{{candidate}} + using B1::B1; // expected-note 3{{inherited here}} + using B2::B2; // expected-note 3{{inherited here}} }; struct D2 : B1, B2 { using B1::B1; using B2::B2; D2(int); }; +D1 d1(0); // expected-error {{ambiguous}} +D2 d2(0); template<typename T> struct B3 { - B3(T); // expected-note {{previous constructor}} + B3(T); }; template<typename T> struct B4 : B3<T>, B1 { B4(); - using B3<T>::B3; // expected-note {{inherited here}} - using B1::B1; // expected-error {{already inherited}} + using B3<T>::B3; + using B1::B1; }; B4<char> b4c; -B4<int> b4i; // expected-note {{here}} +B4<int> b4i; struct B5 { - template<typename T> B5(T); // expected-note {{previous constructor}} -}; -struct B6 { - template<typename T> B6(T); // expected-note {{conflicting constructor}} + template<typename T> B5(T); }; -struct B7 { - template<typename T, int> B7(T); -}; -struct D56 : B5, B6, B7 { - using B5::B5; // expected-note {{inherited here}} - using B6::B6; // expected-error {{already inherited}} +struct D6 : B5 { + using B5::B5; + template<typename T> D6(T); }; -struct D57 : B5, B6, B7 { +D6 d6(0); +struct D7 : B5 { using B5::B5; - using B7::B7; // ok, not the same signature + template<typename T> D7(T, ...); }; +// DRxxx (no number yet): derived class ctor beats base class ctor. +D7 d7(0); diff --git a/test/CXX/special/class.inhctor/p8.cpp b/test/CXX/special/class.inhctor/p8.cpp index effc2c3bca..58c01d2b91 100644 --- a/test/CXX/special/class.inhctor/p8.cpp +++ b/test/CXX/special/class.inhctor/p8.cpp @@ -1,4 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -verify %s +// +// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior +// for the wording that used to be there. struct A { constexpr A(const int&) : rval(false) {} @@ -13,8 +16,6 @@ constexpr int k = 0; constexpr A a0{0}; constexpr A a1{k}; constexpr B b0{0}; -// This performs static_cast<(const int&)&&>(k), so calls the A(const int&) -// constructor. constexpr B b1{k}; static_assert(a0.rval && !a1.rval && b0.rval && !b1.rval, ""); @@ -28,5 +29,4 @@ struct D : C { }; static_assert(D(123).v == 123, ""); -// FIXME: This diagnostic sucks. -template<typename T> constexpr D::D(T t) : C(t) {} // expected-error {{definition of implicitly declared function}} +template<typename T> constexpr D::D(T t) : C(t) {} // expected-error {{does not match any declaration in 'D'}} diff --git a/test/CXX/special/class.init/class.inhctor.init/p1.cpp b/test/CXX/special/class.init/class.inhctor.init/p1.cpp new file mode 100644 index 0000000000..346b0b05de --- /dev/null +++ b/test/CXX/special/class.init/class.inhctor.init/p1.cpp @@ -0,0 +1,124 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +namespace std_example { + struct B1 { // expected-note {{declared here}} + B1(int, ...) {} + }; + + struct B2 { + B2(double) {} + }; + + int get(); + + struct D1 : B1 { // expected-note {{no default constructor}} + using B1::B1; // inherits B1(int, ...) + int x; + int y = get(); + }; + + void test() { + D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4), + // then d.x is default-initialized (no initialization is performed), + // then d.y is initialized by calling get() + D1 e; // expected-error {{implicitly-deleted}} + } + + struct D2 : B2 { + using B2::B2; // expected-error {{cannot use constructor inherited from base class 'B2'; member 'b' of 'std_example::D2' does not have a default constructor}} + B1 b; // expected-note {{member}} + }; + + D2 f(1.0); // expected-note {{inherited constructor for 'D2' first required here}} + + struct W { + W(int); + }; + struct X : virtual W { + using W::W; + X() = delete; + }; + struct Y : X { + using X::X; + }; + struct Z : Y, virtual W { + using Y::Y; + }; + Z z(0); // OK: initialization of Y does not invoke default constructor of X + + template <class T> struct Log : T { + using T::T; // inherits all constructors from class T + ~Log() { /* ... */ } + }; +} + +namespace vbase { + struct V { // expected-note 2{{declared here}} + V(int); + }; + + struct A : virtual V { + A() = delete; // expected-note 2{{deleted here}} expected-note {{deleted}} + using V::V; + }; + struct B : virtual V { + B() = delete; // expected-note 2{{deleted here}} + B(int, int); + using V::V; + }; + struct C : B { // expected-note {{deleted default constructor}} + using B::B; // expected-error {{cannot use constructor inherited from base class 'B'; base class 'vbase::V' of 'vbase::C' does not have a default constructor}} + }; + struct D : A, C { // expected-note {{deleted default constructor}} + using A::A; + using C::C; // expected-error {{cannot use constructor inherited from base class 'C'; base class 'vbase::V' of 'vbase::D' does not have a default constructor}} expected-error {{call to deleted constructor of 'vbase::A'}} + }; + + A a0; // expected-error {{deleted}} + A a1(0); + B b0; // expected-error {{deleted}} + B b1(0); + B b2(0, 0); + C c0; // expected-error {{deleted}} + C c1(0); + C c2(0, 0); // expected-note {{first required here}} + D d0; // expected-error {{implicitly-deleted}} + D d1(0); + D d2(0, 0); // expected-note {{first required here}} +} + +namespace constexpr_init_order { + struct Param; + struct A { + constexpr A(Param); + int a; + }; + + struct B : A { B(); using A::A; int b = 2; }; + extern const B b; + + struct Param { + constexpr Param(int c) : n(4 * b.a + b.b + c) {} + int n; + }; + + constexpr A::A(Param p) : a(p.n) {} + + constexpr B b(1); + constexpr B c(1); + static_assert(b.a == 1, "p should be initialized before B() is executed"); + static_assert(c.a == 7, "b not initialzed properly"); +} + +namespace default_args { + // We work around a defect in P0136R1 where it would reject reasonable + // code like the following: + struct Base { + Base(int = 0); + }; + struct Derived : Base { + using Base::Base; + }; + Derived d; + // FIXME: Once a fix is standardized, implement it. +} diff --git a/test/CXX/special/class.init/class.inhctor.init/p2.cpp b/test/CXX/special/class.init/class.inhctor.init/p2.cpp new file mode 100644 index 0000000000..7ea2ccc360 --- /dev/null +++ b/test/CXX/special/class.init/class.inhctor.init/p2.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +namespace std_example { + struct A { A(int); }; + struct B : A { using A::A; }; + + struct C1 : B { using B::B; }; + struct C2 : B { using B::B; }; + + struct D1 : C1, C2 { + using C1::C1; // expected-note {{inherited from base class 'C1' here}} + using C2::C2; // expected-note {{inherited from base class 'C2' here}} + }; + + struct V1 : virtual B { using B::B; }; + struct V2 : virtual B { using B::B; }; + + struct D2 : V1, V2 { + using V1::V1; + using V2::V2; + }; + + D1 d1(0); // expected-error {{constructor of 'A' inherited from multiple base class subobjects}} + D2 d2(0); // OK: initializes virtual B base class, which initializes the A base class + // then initializes the V1 and V2 base classes as if by a defaulted default constructor + + struct M { M(); M(int); }; + struct N : M { using M::M; }; + struct O : M {}; + struct P : N, O { using N::N; using O::O; }; + P p(0); // OK: use M(0) to initialize N's base class, + // use M() to initialize O's base class +} diff --git a/test/CodeGenCXX/inheriting-constructor.cpp b/test/CodeGenCXX/inheriting-constructor.cpp index 42080a2daf..4ba59fdad8 100644 --- a/test/CodeGenCXX/inheriting-constructor.cpp +++ b/test/CodeGenCXX/inheriting-constructor.cpp @@ -1,4 +1,8 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple i386-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=ITANIUM +// RUN: %clang_cc1 -std=c++11 -triple x86_64-darwin -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=ITANIUM +// RUN: %clang_cc1 -std=c++11 -triple arm64-ehabi -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=ITANIUM +// RUN: %clang_cc1 -std=c++11 -triple i386-windows -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=MSABI --check-prefix=WIN32 +// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=MSABI --check-prefix=WIN64 // PR12219 struct A { A(int); virtual ~A(); }; @@ -11,18 +15,396 @@ struct C { template<typename T> C(T); }; struct D : C { using C::C; }; D d(123); -// CHECK-LABEL: define void @_ZN1BD2Ev -// CHECK-LABEL: define void @_ZN1BD1Ev -// CHECK-LABEL: define void @_ZN1BD0Ev +// ITANIUM-LABEL: define void @_ZN1BD2Ev +// ITANIUM-LABEL: define void @_ZN1BD1Ev +// ITANIUM-LABEL: define void @_ZN1BD0Ev +// WIN32-LABEL: define {{.*}}void @"\01??1B@@UAE@XZ" +// WIN64-LABEL: define {{.*}}void @"\01??1B@@UEAA@XZ" -// CHECK-LABEL: define linkonce_odr void @_ZN1BC1Ei( -// CHECK: call void @_ZN1BC2Ei( +// ITANIUM-LABEL: define linkonce_odr void @_ZN1BCI11AEi( +// ITANIUM: call void @_ZN1BCI21AEi( -// CHECK-LABEL: define linkonce_odr void @_ZN1DC1IiEET_( -// CHECK: call void @_ZN1DC2IiEET_( +// ITANIUM-LABEL: define linkonce_odr void @_ZN1DCI11CIiEET_( +// ITANIUM: call void @_ZN1DCI21CIiEET_( -// CHECK-LABEL: define linkonce_odr void @_ZN1BC2Ei( -// CHECK: call void @_ZN1AC2Ei( +// WIN32-LABEL: define internal {{.*}} @"\01??0B@@QAE@H@Z"( +// WIN32: call {{.*}} @"\01??0A@@QAE@H@Z"( +// WIN64-LABEL: define internal {{.*}} @"\01??0B@@QEAA@H@Z"( +// WIN64: call {{.*}} @"\01??0A@@QEAA@H@Z"( -// CHECK-LABEL: define linkonce_odr void @_ZN1DC2IiEET_( -// CHECK: call void @_ZN1CC2IiEET_( +// WIN32-LABEL: define internal {{.*}} @"\01??0D@@QAE@H@Z"( +// WIN32: call {{.*}} @"\01??$?0H@C@@QAE@H@Z" +// WIN64-LABEL: define internal {{.*}} @"\01??0D@@QEAA@H@Z"( +// WIN64: call {{.*}} @"\01??$?0H@C@@QEAA@H@Z" + +struct Q { Q(int); Q(const Q&); ~Q(); }; +struct Z { Z(); Z(int); ~Z(); int n; }; + +namespace noninline_nonvirt { + struct A { A(int, Q&&, void *__attribute__((pass_object_size(0)))); int n; }; + struct B : Z, A { Z z; using A::A; }; + B b(1, 2, &b); + // ITANIUM-LABEL: define {{.*}} @__cxx_global_var_init + // ITANIUM: call void @_ZN1QC1Ei({{.*}} %[[TMP:.*]], i32 2) + // ITANIUM: call void @_ZN17noninline_nonvirt1BCI1NS_1AEEiO1QPvU17pass_object_size0({{.*}} @_ZN17noninline_nonvirt1bE, i32 1, {{.*}} %[[TMP]], i8* {{.*}} @_ZN17noninline_nonvirt1bE{{.*}}, i{{32|64}} 12) + // ITANIUM: call void @_ZN1QD1Ev({{.*}} %[[TMP]]) + // ITANIUM: call i32 @__cxa_atexit( + + // Complete object ctor for B delegates to base object ctor. + // ITANIUM-LABEL: define linkonce_odr void @_ZN17noninline_nonvirt1BCI1NS_1AEEiO1QPvU17pass_object_size0( + // ITANIUM: call void @_ZN17noninline_nonvirt1BCI2NS_1AEEiO1QPvU17pass_object_size0({{.*}}, i32 {{.*}}, %{{.*}}* {{.*}}, i8* {{.*}}, i{{32|64}} {{.*}}) + + // In MSABI, we don't have ctor variants. B ctor forwards to A ctor. + // MSABI-LABEL: define internal {{.*}} @"\01??0B@noninline_nonvirt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}) + // MSABI: call {{.*}} @"\01??0Z@@Q{{AE|EAA}}@XZ"( + // MSABI: call {{.*}} @"\01??0A@noninline_nonvirt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}) + // MSABI: call {{.*}} @"\01??0Z@@Q{{AE|EAA}}@XZ"( + + struct C : B { using B::B; }; + C c(1, 2, &c); + // Complete object ctor for C delegates. + // ITANIUM-LABEL: define linkonce_odr void @_ZN17noninline_nonvirt1CCI1NS_1AEEiO1QPvU17pass_object_size0( + // ITANIUM: call void @_ZN17noninline_nonvirt1CCI2NS_1AEEiO1QPvU17pass_object_size0({{.*}}, i32 {{.*}}, %{{.*}}* {{.*}}, i8* {{.*}}, i{{32|64}} {{.*}}) + + // MSABI-LABEL: define internal {{.*}} @"\01??0C@noninline_nonvirt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}) + // MSABI: call {{.*}} @"\01??0B@noninline_nonvirt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}) +} + +namespace noninline_virt { + struct A { A(int, Q&&, void *__attribute__((pass_object_size(0)))); int n; }; + struct B : Z, virtual A { Z z; using A::A; }; + B b(1, 2, &b); + // Complete object ctor forwards to A ctor then constructs Zs. + // ITANIUM-LABEL: define linkonce_odr void @_ZN14noninline_virt1BCI1NS_1AEEiO1QPvU17pass_object_size0( + // ITANIUM: call void @_ZN14noninline_virt1AC2EiO1QPvU17pass_object_size0({{.*}} %{{.*}}, i32 %{{.*}}, %{{.*}}* {{.*}}, i8* {{.*}}, i{{32|64}} %{{.*}} + // ITANIUM: call void @_ZN1ZC2Ev( + // ITANIUM: store {{.*}} @_ZTVN14noninline_virt1BE + // ITANIUM: call void @_ZN1ZC1Ev( + + // MSABI-LABEL: define internal {{.*}} @"\01??0B@noninline_virt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}, i32 %{{.*}}) + // MSABI: %[[COMPLETE:.*]] = icmp ne + // MSABI: br i1 %[[COMPLETE]], + // MSABI: call {{.*}} @"\01??0A@noninline_virt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}) + // MSABI: br + // MSABI: call {{.*}} @"\01??0Z@@Q{{AE|EAA}}@XZ"( + // MSABI: call {{.*}} @"\01??0Z@@Q{{AE|EAA}}@XZ"( + + struct C : B { using B::B; }; + C c(1, 2, &c); + // Complete object ctor forwards to A ctor, then calls B's base inheriting + // constructor, which takes no arguments other than the this pointer and VTT. + // ITANIUM_LABEL: define linkonce_odr void @_ZN14noninline_virt1CCI1NS_1AEEiO1QPvU17pass_object_size0( + // ITANIUM: call void @_ZN14noninline_virt1AC2EiO1QPvU17pass_object_size0({{.*}} %{{.*}}, i32 %{{.*}}, %{{.*}}* {{.*}}, i8* %{{.*}}, i{{32|64}} %{{.*}}) + // ITANIUM: call void @_ZN14noninline_virt1BCI2NS_1AEEiO1QPvU17pass_object_size0(%{{.*}}* %{{.*}}, i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @_ZTTN14noninline_virt1CE, i64 0, i64 1)) + // ITANIUM: store {{.*}} @_ZTVN14noninline_virt1CE + + // C constructor forwards to B constructor and A constructor. We pass the args + // to both. FIXME: Can we pass undef here instead, for the base object + // constructor call? + // MSABI-LABEL: define internal {{.*}} @"\01??0C@noninline_virt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}, i32 %{{.*}}) + // MSABI: %[[COMPLETE:.*]] = icmp ne + // MSABI: br i1 %[[COMPLETE]], + // MSABI: call {{.*}} @"\01??0A@noninline_virt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}) + // MSABI: br + // MSABI: call {{.*}} @"\01??0B@noninline_virt@@Q{{AE|EAA}}@H$$Q{{E?}}AUQ@@P{{E?}}AXW4__pass_object_size0@__clang@@@Z"(%{{.*}}, i32{{.*}}, %{{.*}}, i8*{{.*}}, i{{32|64}}{{.*}}, i32 0) +} + +// For MSABI only, check that inalloca arguments result in inlining. +namespace inalloca_nonvirt { + struct A { A(Q, int, Q, Q&&); int n; }; + struct B : Z, A { Z z; using A::A; }; + B b(1, 2, 3, 4); + // No inlining implied for Itanium. + // ITANIUM-LABEL: define linkonce_odr void @_ZN16inalloca_nonvirt1BCI1NS_1AEE1QiS1_OS1_( + // ITANIUM: call void @_ZN16inalloca_nonvirt1BCI2NS_1AEE1QiS1_OS1_( + + // MSABI-LABEL: define internal void @"\01??__Eb@inalloca_nonvirt@@YAXXZ"( + + // On Win32, the inalloca call can't be forwarded so we force inlining. + // WIN32: %[[TMP:.*]] = alloca + // WIN32: call i8* @llvm.stacksave() + // WIN32: %[[ARGMEM:.*]] = alloca inalloca + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"(%{{.*}}* %[[TMP]], i32 4) + // WIN32: %[[ARG3:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"({{.*}}* %[[ARG3]], i32 3) + // WIN32: %[[ARG1:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"({{.*}}* %[[ARG1]], i32 1) + // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( + // WIN32: %[[ARG2:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: store i32 2, i32* %[[ARG2]] + // WIN32: %[[ARG4:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: store {{.*}}* %[[TMP]], {{.*}}** %[[ARG4]] + // WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) + // WIN32: call void @llvm.stackrestore( + // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( + // WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"( + + // On Win64, the Q arguments would be destroyed in the callee. We don't yet + // support that in the non-inlined case, so we force inlining. + // WIN64: %[[TMP:.*]] = alloca + // WIN64: %[[ARG3:.*]] = alloca + // WIN64: %[[ARG1:.*]] = alloca + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[TMP]], i32 4) + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[ARG3]], i32 3) + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[ARG1]], i32 1) + // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( + // WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]]) + // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( + // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) + + struct C : B { using B::B; }; + C c(1, 2, 3, 4); + // MSABI-LABEL: define internal void @"\01??__Ec@inalloca_nonvirt@@YAXXZ"( + + // On Win32, the inalloca call can't be forwarded so we force inlining. + // WIN32: %[[TMP:.*]] = alloca + // WIN32: call i8* @llvm.stacksave() + // WIN32: %[[ARGMEM:.*]] = alloca inalloca + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"(%{{.*}}* %[[TMP]], i32 4) + // WIN32: %[[ARG3:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"({{.*}}* %[[ARG3]], i32 3) + // WIN32: %[[ARG1:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"({{.*}}* %[[ARG1]], i32 1) + // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( + // WIN32: %[[ARG2:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: store i32 2, i32* %[[ARG2]] + // WIN32: %[[ARG4:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: store {{.*}}* %[[TMP]], {{.*}}** %[[ARG4]] + // WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) + // WIN32: call void @llvm.stackrestore( + // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( + // WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"( + + // On Win64, the Q arguments would be destroyed in the callee. We don't yet + // support that in the non-inlined case, so we force inlining. + // WIN64: %[[TMP:.*]] = alloca + // WIN64: %[[ARG3:.*]] = alloca + // WIN64: %[[ARG1:.*]] = alloca + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[TMP]], i32 4) + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[ARG3]], i32 3) + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[ARG1]], i32 1) + // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( + // WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]]) + // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( + // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) +} + +namespace inalloca_virt { + struct A { A(Q, int, Q, Q&&); int n; }; + struct B : Z, virtual A { Z z; using A::A; }; + B b(1, 2, 3, 4); + + // MSABI-LABEL: define internal void @"\01??__Eb@inalloca_virt@@YAXXZ"( + + // On Win32, the inalloca call can't be forwarded so we force inlining. + // WIN32: %[[TMP:.*]] = alloca + // WIN32: call i8* @llvm.stacksave() + // WIN32: %[[ARGMEM:.*]] = alloca inalloca + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"(%{{.*}}* %[[TMP]], i32 4) + // WIN32: %[[ARG3:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"({{.*}}* %[[ARG3]], i32 3) + // WIN32: %[[ARG1:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"({{.*}}* %[[ARG1]], i32 1) + // FIXME: It's dumb to round-trip this though memory and generate a branch. + // WIN32: store i32 1, i32* %[[IS_MOST_DERIVED_ADDR:.*]] + // WIN32: %[[IS_MOST_DERIVED:.*]] = load i32, i32* %[[IS_MOST_DERIVED_ADDR]] + // WIN32: %[[IS_MOST_DERIVED_i1:.*]] = icmp ne i32 %[[IS_MOST_DERIVED]], 0 + // WIN32: br i1 %[[IS_MOST_DERIVED_i1]] + // + // WIN32: store {{.*}} @"\01??_8B@inalloca_virt@@7B@" + // WIN32: %[[ARG2:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: store i32 2, i32* %[[ARG2]] + // WIN32: %[[ARG4:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: store {{.*}}* %[[TMP]], {{.*}}** %[[ARG4]] + // WIN32: call {{.*}} @"\01??0A@inalloca_virt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) + // WIN32: call void @llvm.stackrestore( + // WIN32: br + // + // Note that if we jumped directly to here we would fail to stackrestore and + // destroy the parameters, but that's not actually possible. + // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( + // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( + // WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"( + + // On Win64, the Q arguments would be destroyed in the callee. We don't yet + // support that in the non-inlined case, so we force inlining. + // WIN64: %[[TMP:.*]] = alloca + // WIN64: %[[ARG3:.*]] = alloca + // WIN64: %[[ARG1:.*]] = alloca + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[TMP]], i32 4) + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[ARG3]], i32 3) + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[ARG1]], i32 1) + // WIN64: br i1 + // WIN64: call {{.*}} @"\01??0A@inalloca_virt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]]) + // WIN64: br + // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( + // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( + // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) + + struct C : B { using B::B; }; + C c(1, 2, 3, 4); + // ITANIUM-LABEL: define linkonce_odr void @_ZN13inalloca_virt1CD1Ev( + + // MSABI-LABEL: define internal void @"\01??__Ec@inalloca_virt@@YAXXZ"( + + // On Win32, the inalloca call can't be forwarded so we force inlining. + // WIN32: %[[TMP:.*]] = alloca + // WIN32: call i8* @llvm.stacksave() + // WIN32: %[[ARGMEM:.*]] = alloca inalloca + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"(%{{.*}}* %[[TMP]], i32 4) + // WIN32: %[[ARG3:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"({{.*}}* %[[ARG3]], i32 3) + // WIN32: %[[ARG1:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: call {{.*}} @"\01??0Q@@QAE@H@Z"({{.*}}* %[[ARG1]], i32 1) + // WIN32: store i32 1, i32* %[[IS_MOST_DERIVED_ADDR:.*]] + // WIN32: %[[IS_MOST_DERIVED:.*]] = load i32, i32* %[[IS_MOST_DERIVED_ADDR]] + // WIN32: %[[IS_MOST_DERIVED_i1:.*]] = icmp ne i32 %[[IS_MOST_DERIVED]], 0 + // WIN32: br i1 %[[IS_MOST_DERIVED_i1]] + // + // WIN32: store {{.*}} @"\01??_8C@inalloca_virt@@7B@" + // WIN32: %[[ARG2:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: store i32 2, i32* %[[ARG2]] + // WIN32: %[[ARG4:.*]] = getelementptr {{.*}} %[[ARGMEM]] + // WIN32: store {{.*}}* %[[TMP]], {{.*}}** %[[ARG4]] + // WIN32: call {{.*}} @"\01??0A@inalloca_virt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) + // WIN32: call void @llvm.stackrestore( + // WIN32: br + // + // WIN32: store i32 0, i32* %[[IS_MOST_DERIVED_ADDR:.*]] + // WIN32: %[[IS_MOST_DERIVED:.*]] = load i32, i32* %[[IS_MOST_DERIVED_ADDR]] + // WIN32: %[[IS_MOST_DERIVED_i1:.*]] = icmp ne i32 %[[IS_MOST_DERIVED]], 0 + // WIN32: br i1 %[[IS_MOST_DERIVED_i1]] + // + // Note: this block is unreachable. + // WIN32: store {{.*}} @"\01??_8B@inalloca_virt@@7B@" + // WIN32: br + // + // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( + // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( + // WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"( + + // On Win64, the Q arguments would be destroyed in the callee. We don't yet + // support that in the non-inlined case, so we force inlining. + // WIN64: %[[TMP:.*]] = alloca + // WIN64: %[[ARG3:.*]] = alloca + // WIN64: %[[ARG1:.*]] = alloca + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[TMP]], i32 4) + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[ARG3]], i32 3) + // WIN64: call {{.*}} @"\01??0Q@@QEAA@H@Z"({{.*}}* %[[ARG1]], i32 1) + // WIN64: br i1 + // WIN64: store {{.*}} @"\01??_8C@inalloca_virt@@7B@" + // WIN64: call {{.*}} @"\01??0A@inalloca_virt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]]) + // WIN64: br + // WIN64: br i1 + // (Unreachable block) + // WIN64: store {{.*}} @"\01??_8B@inalloca_virt@@7B@" + // WIN64: br + // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( + // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( + // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) +} + +namespace inline_nonvirt { + struct A { A(Q, int, Q, Q&&, ...); int n; }; + struct B : Z, A { Z z; using A::A; }; + B b(1, 2, 3, 4, 5, 6); + // Inlined all the way down to the A ctor. + // ITANIUM-LABEL: define {{.*}} @__cxx_global_var_init + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 1) + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 3) + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 4) + // ITANIUM: %[[Z_BASE:.*]] = bitcast %{{.*}}* %[[THIS:.*]] to + // ITANIUM: call void @_ZN1ZC2Ev( + // ITANIUM: %[[B_CAST:.*]] = bitcast {{.*}} %[[THIS]] + // ITANIUM: %[[A_CAST:.*]] = getelementptr {{.*}} %[[B_CAST]], i{{32|64}} 4 + // ITANIUM: %[[A:.*]] = bitcast {{.*}} %[[A_CAST]] + // ITANIUM: call void ({{.*}}, ...) @_ZN14inline_nonvirt1AC2E1QiS1_OS1_z(%{{.*}}* %[[A]], {{.*}}, i32 2, {{.*}}, {{.*}}, i32 5, i32 6) + // ITANIUM: %[[Z_MEMBER:.*]] = getelementptr {{.*}} %[[THIS]], i32 0, i32 2 + // ITANIUM: call void @_ZN1ZC1Ev({{.*}} %[[Z_MEMBER]]) + // ITANIUM: call void @_ZN1QD1Ev( + // ITANIUM: call void @_ZN1QD1Ev( + // ITANIUM: call void @_ZN1QD1Ev( + + struct C : B { using B::B; }; + C c(1, 2, 3, 4, 5, 6); + // Inlined all the way down to the A ctor. + // ITANIUM-LABEL: define {{.*}} @__cxx_global_var_init + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 1) + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 3) + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 4) + // ITANIUM: %[[Z_BASE:.*]] = bitcast %{{.*}}* %[[THIS:.*]] to + // ITANIUM: call void @_ZN1ZC2Ev( + // ITANIUM: %[[B_CAST:.*]] = bitcast {{.*}} %[[THIS]] + // ITANIUM: %[[A_CAST:.*]] = getelementptr {{.*}} %[[B_CAST]], i{{32|64}} 4 + // ITANIUM: %[[A:.*]] = bitcast {{.*}} %[[A_CAST]] + // ITANIUM: call void ({{.*}}, ...) @_ZN14inline_nonvirt1AC2E1QiS1_OS1_z(%{{.*}}* %[[A]], {{.*}}, i32 2, {{.*}}, {{.*}}, i32 5, i32 6) + // ITANIUM: %[[Z_MEMBER:.*]] = getelementptr {{.*}} %{{.*}}, i32 0, i32 2 + // ITANIUM: call void @_ZN1ZC1Ev({{.*}} %[[Z_MEMBER]]) + // ITANIUM: call void @_ZN1QD1Ev( + // ITANIUM: call void @_ZN1QD1Ev( + // ITANIUM: call void @_ZN1QD1Ev( +} + +namespace inline_virt { + struct A { A(Q, int, Q, Q&&, ...); int n; }; + struct B : Z, virtual A { Z z; using A::A; }; + B b(1, 2, 3, 4, 5, 6); + // Inlined all the way down to the A ctor. + // ITANIUM-LABEL: define {{.*}} @__cxx_global_var_init + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 1) + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 3) + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 4) + // ITANIUM: %[[B_CAST:.*]] = bitcast {{.*}} %[[THIS:.*]] + // ITANIUM: %[[A_CAST:.*]] = getelementptr {{.*}} %[[B_CAST]], i{{32|64}} {{12|16}} + // ITANIUM: %[[A:.*]] = bitcast {{.*}} %[[A_CAST]] + // ITANIUM: call void ({{.*}}, ...) @_ZN11inline_virt1AC2E1QiS1_OS1_z(%{{.*}}* %[[A]], {{.*}}, i32 2, {{.*}}, {{.*}}, i32 5, i32 6) + // ITANIUM: call void @_ZN1ZC2Ev( + // ITANIUM: call void @_ZN1ZC1Ev( + // ITANIUM: call void @_ZN1QD1Ev( + // ITANIUM: call void @_ZN1QD1Ev( + // ITANIUM: call void @_ZN1QD1Ev( + + struct C : B { using B::B; }; + C c(1, 2, 3, 4, 5, 6); + // Inlined all the way down to the A ctor, except that we can just call the + // B base inheriting constructor to construct that portion (it doesn't need + // the forwarded arguments). + // ITANIUM-LABEL: define {{.*}} @__cxx_global_var_init + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 1) + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 3) + // ITANIUM: call void @_ZN1QC1Ei({{.*}}, i32 4) + // ITANIUM: %[[B_CAST:.*]] = bitcast {{.*}} %[[THIS:.*]] + // ITANIUM: %[[A_CAST:.*]] = getelementptr {{.*}} %[[B_CAST]], i{{32|64}} {{12|16}} + // ITANIUM: %[[A:.*]] = bitcast {{.*}} %[[A_CAST]] + // ITANIUM: call void ({{.*}}, ...) @_ZN11inline_virt1AC2E1QiS1_OS1_z(%{{.*}}* %[[A]], {{.*}}, i32 2, {{.*}}, {{.*}}, i32 5, i32 6) + // ITANIUM: call void @_ZN11inline_virt1BCI2NS_1AEE1QiS1_OS1_z({{[^,]*}}, i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @_ZTTN11inline_virt1CE, i64 0, i64 1)) + // ITANIUM: store {{.*}} @_ZTVN11inline_virt1CE + // ITANIUM: call void @_ZN1QD1Ev( + // ITANIUM: call void @_ZN1QD1Ev( + // ITANIUM: call void @_ZN1QD1Ev( + + // B base object inheriting constructor does not get passed arguments. + // ITANIUM-LABEL: define linkonce_odr void @_ZN11inline_virt1BCI2NS_1AEE1QiS1_OS1_z( + // ITANIUM-NOT: call + // ITANIUM: call void @_ZN1ZC2Ev(%struct.Z* %2) + // ITANIUM-NOT: call + // VTT -> vtable + // ITANIUM: store + // ITANIUM-NOT: call + // ITANIUM: call void @_ZN1ZC1Ev(%struct.Z* %z) + // ITANIUM-NOT: call + // ITANIUM: } +} + +// ITANIUM-LABEL: define linkonce_odr void @_ZN1BCI21AEi( +// ITANIUM: call void @_ZN1AC2Ei( + +// ITANIUM-LABEL: define linkonce_odr void @_ZN1DCI21CIiEET_( +// ITANIUM: call void @_ZN1CC2IiEET_( + +// ITANIUM-LABEL: define linkonce_odr void @_ZN17noninline_nonvirt1BCI2NS_1AEEiO1QPvU17pass_object_size0( +// ITANIUM: call void @_ZN1ZC2Ev( +// ITANIUM: call void @_ZN17noninline_nonvirt1AC2EiO1QPvU17pass_object_size0( + +// ITANIUM-LABEL: define linkonce_odr void @_ZN17noninline_nonvirt1CCI2NS_1AEEiO1QPvU17pass_object_size0( +// ITANIUM: call void @_ZN17noninline_nonvirt1BCI2NS_1AEEiO1QPvU17pass_object_size0( diff --git a/test/PCH/cxx11-inheriting-ctors.cpp b/test/PCH/cxx11-inheriting-ctors.cpp index 79f78ba6c1..bf9a2b7609 100644 --- a/test/PCH/cxx11-inheriting-ctors.cpp +++ b/test/PCH/cxx11-inheriting-ctors.cpp @@ -1,10 +1,19 @@ -// RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s +// RUN: %clang_cc1 -std=c++11 -include %s -include %s -verify %s +// +// Emit with definitions in the declaration: +// RxN: %clang_cc1 -std=c++11 -emit-pch -o %t.12 -include %s %s +// RxN: %clang_cc1 -std=c++11 -include-pch %t.12 -verify %s +// +// Emit with definitions in update records: +// RxN: %clang_cc1 -std=c++11 -emit-pch -o %t.1 %s +// RxN: %clang_cc1 -std=c++11 -include-pch %t.1 -emit-pch -o %t.2 -verify %s +// RxN: %clang_cc1 -std=c++11 -include-pch %t.1 -include-pch %t.2 -verify %s + // expected-no-diagnostics -#ifndef HEADER_INCLUDED -#define HEADER_INCLUDED +#ifndef HEADER1 +#define HEADER1 struct Base { Base(int) {} @@ -27,7 +36,8 @@ struct Test3 : B { using B::B; }; -#else +#elif !defined(HEADER2) +#define HEADER2 Test test1a(42); Test test1b(nullptr); @@ -36,4 +46,16 @@ Test2<int> test2b(nullptr); Test3<Base> test3a(42); Test3<Base> test3b(nullptr); -#endif // HEADER_INCLUDED +#pragma clang __debug dump Test +#pragma clang __debug dump Test2 + +#else + +Test retest1a(42); +Test retest1b(nullptr); +Test2<int> retest2a(42); +Test2<int> retest2b(nullptr); +Test3<Base> retest3a(42); +Test3<Base> retest3b(nullptr); + +#endif diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index a755f48048..e2b3f091f7 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -2029,3 +2029,40 @@ namespace IncompleteClass { static constexpr int j = g(static_cast<XX*>(nullptr)); // expected-error {{constexpr variable 'j' must be initialized by a constant expression}} expected-note {{undefined function 'g' cannot be used in a constant expression}} }; } + +namespace InheritedCtor { + struct A { constexpr A(int) {} }; + + struct B : A { int n; using A::A; }; // expected-note {{here}} + constexpr B b(0); // expected-error {{constant expression}} expected-note {{derived class}} + + struct C : A { using A::A; struct { union { int n, m = 0; }; union { int a = 0; }; int k = 0; }; struct {}; union {}; }; // expected-warning 4{{extension}} + constexpr C c(0); + + struct D : A { + using A::A; // expected-note {{here}} + struct { // expected-warning {{extension}} + union { // expected-warning {{extension}} + int n; + }; + }; + }; + constexpr D d(0); // expected-error {{constant expression}} expected-note {{derived class}} + + struct E : virtual A { using A::A; }; // expected-note {{here}} + // We wrap a function around this to avoid implicit zero-initialization + // happening first; the zero-initialization step would produce the same + // error and defeat the point of this test. + void f() { + constexpr E e(0); // expected-error {{constant expression}} expected-note {{derived class}} + } + // FIXME: This produces a note with no source location. + //constexpr E e(0); + + struct W { constexpr W(int n) : w(n) {} int w; }; + struct X : W { using W::W; int x = 2; }; + struct Y : X { using X::X; int y = 3; }; + struct Z : Y { using Y::Y; int z = 4; }; + constexpr Z z(1); + static_assert(z.w == 1 && z.x == 2 && z.y == 3 && z.z == 4, ""); +} diff --git a/test/SemaCXX/cxx11-inheriting-ctors.cpp b/test/SemaCXX/cxx11-inheriting-ctors.cpp index 04aa117b29..8e053212ed 100644 --- a/test/SemaCXX/cxx11-inheriting-ctors.cpp +++ b/test/SemaCXX/cxx11-inheriting-ctors.cpp @@ -34,3 +34,13 @@ namespace WrongIdent { using B::A; }; } + +namespace DefaultCtorConflict { + struct A { A(int = 0); }; + struct B : A { + using A::A; + } b; // ok, not ambiguous, inherited constructor suppresses implicit default constructor + struct C { + B b; + } c; +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 43d8edc3fe..4d1cfb1165 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -3955,6 +3955,9 @@ static const Decl *getDeclFromExpr(const Stmt *E) { if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) if (!CE->isElidable()) return CE->getConstructor(); + if (const CXXInheritedCtorInitExpr *CE = + dyn_cast<CXXInheritedCtorInitExpr>(E)) + return CE->getConstructor(); if (const ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E)) return OME->getMethodDecl(); @@ -5665,6 +5668,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { D->getLocation(), TU); case Decl::UsingShadow: + case Decl::ConstructorUsingShadow: return clang_getCursorDefinition( MakeCXCursor(cast<UsingShadowDecl>(D)->getTargetDecl(), TU)); diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 28f37d8959..2cf923396f 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -504,6 +504,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::CXXMemberCallExprClass: case Stmt::CUDAKernelCallExprClass: case Stmt::CXXConstructExprClass: + case Stmt::CXXInheritedCtorInitExprClass: case Stmt::CXXTemporaryObjectExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::UserDefinedLiteralClass: diff --git a/www/cxx_status.html b/www/cxx_status.html index 580d456e67..c902cdfe57 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -623,7 +623,7 @@ as the draft C++1z standard evolves.</p> <tr> <td>New specification for inheriting constructors (<a href="cxx_dr_status.html#1941">DR1941</a> et al)</td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html">P0136R1</a></td> - <td class="none" align="center">No</td> + <td class="svn" align="center">SVN <a href="p0136">(9)</a></td> </tr> <!-- Jacksonville papers --> <tr> @@ -735,6 +735,9 @@ all language versions that allow type deduction from <tt>auto</tt> (per the request of the C++ committee). In Clang 3.7, a warning is emitted for all cases that would change meaning. </span> +<span id="p0136">(9): This is the resolution to a Defect Report, so is applied +to all language versions supporting inheriting constructors. +</span> </p> <h2 id="ts">Technical specifications and standing documents</h2> |