[cfe-commits] r124970 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaOverload.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/CXX/special/class.inhctor/elsewhere.cpp test/CXX/special/class.inhctor/p3.cpp test/CXX/special/class.inhctor/p7.cpp
Douglas Gregor
dgregor at apple.com
Sun Mar 6 11:01:20 PST 2011
We should turn this off for the branch, since it's not going to be fully implemented in 2.9.
- Doug
On Feb 5, 2011, at 11:23 AM, Sebastian Redl wrote:
> Author: cornedbee
> Date: Sat Feb 5 13:23:19 2011
> New Revision: 124970
>
> URL: http://llvm.org/viewvc/llvm-project?rev=124970&view=rev
> Log:
> Basic implementation of inherited constructors. Only generates declarations, and probably only works for very basic use cases.
>
> Added:
> cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp
> cfe/trunk/test/CXX/special/class.inhctor/p3.cpp
> cfe/trunk/test/CXX/special/class.inhctor/p7.cpp
> Modified:
> cfe/trunk/include/clang/AST/DeclCXX.h
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> cfe/trunk/include/clang/Sema/Sema.h
> cfe/trunk/lib/AST/DeclCXX.cpp
> cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> cfe/trunk/lib/Sema/SemaOverload.cpp
> cfe/trunk/lib/Serialization/ASTReader.cpp
> cfe/trunk/lib/Serialization/ASTWriter.cpp
>
> Modified: cfe/trunk/include/clang/AST/DeclCXX.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=124970&r1=124969&r2=124970&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
> +++ cfe/trunk/include/clang/AST/DeclCXX.h Sat Feb 5 13:23:19 2011
> @@ -187,6 +187,10 @@
> /// VC++ bug.
> unsigned Access : 2;
>
> + /// InheritConstructors - Whether the class contains a using declaration
> + /// to inherit the named class's constructors.
> + bool InheritConstructors : 1;
> +
> /// BaseTypeInfo - The type of the base class. This will be a class or struct
> /// (or a typedef of such). The source code range does not include the
> /// "virtual" or access specifier.
> @@ -198,7 +202,7 @@
> CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A,
> TypeSourceInfo *TInfo, SourceLocation EllipsisLoc)
> : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC),
> - Access(A), BaseTypeInfo(TInfo) { }
> + Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { }
>
> /// getSourceRange - Retrieves the source range that contains the
> /// entire base specifier.
> @@ -214,12 +218,20 @@
>
> /// \brief Determine whether this base specifier is a pack expansion.
> bool isPackExpansion() const { return EllipsisLoc.isValid(); }
> -
> +
> + /// \brief Determine whether this base class's constructors get inherited.
> + bool getInheritConstructors() const { return InheritConstructors; }
> +
> + /// \brief Set that this base class's constructors should be inherited.
> + void setInheritConstructors(bool Inherit = true) {
> + InheritConstructors = Inherit;
> + }
> +
> /// \brief For a pack expansion, determine the location of the ellipsis.
> SourceLocation getEllipsisLoc() const {
> return EllipsisLoc;
> }
> -
> +
> /// getAccessSpecifier - Returns the access specifier for this base
> /// specifier. This is the actual base specifier as used for
> /// semantic analysis, so the result can never be AS_none. To
> @@ -1519,6 +1531,12 @@
> /// would copy the object to itself. Such constructors are never used to copy
> /// an object.
> bool isSpecializationCopyingObject() const;
> +
> + /// \brief Get the constructor that this inheriting constructor is based on.
> + const CXXConstructorDecl *getInheritedConstructor() const;
> +
> + /// \brief Set the constructor that this inheriting constructor is based on.
> + void setInheritedConstructor(const CXXConstructorDecl *BaseCtor);
>
> // Implement isa/cast/dyncast/etc.
> static bool classof(const Decl *D) { return classofKind(D->getKind()); }
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124970&r1=124969&r2=124970&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Feb 5 13:23:19 2011
> @@ -162,6 +162,17 @@
> "using declaration refers to its own class">;
> 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, can not inherit constructors">;
> +def err_using_decl_constructor_conflict : Error<
> + "can not 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 err_using_decl_can_not_refer_to_class_member : Error<
> "using declaration can not refer to class member">;
> def err_using_decl_can_not_refer_to_namespace : Error<
> @@ -1282,12 +1293,14 @@
> "function |function |constructor |"
> "is the implicit default constructor|"
> "is the implicit copy constructor|"
> - "is the implicit copy assignment operator}0%1">;
> + "is the implicit copy assignment operator|"
> + "is an inherited constructor}0%1">;
>
> def warn_init_pointer_from_false : Warning<
> "initialization of pointer of type %0 from literal 'false'">,
> InGroup<BoolConversions>;
>
> +def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
> def note_ovl_candidate_bad_deduction : Note<
> "candidate template ignored: failed template argument deduction">;
> def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
> @@ -1315,14 +1328,15 @@
> "%select{function|function|constructor|function|function|constructor|"
> "constructor (the implicit default constructor)|"
> "constructor (the implicit copy constructor)|"
> - "function (the implicit copy assignment operator)}0 %select{|template }1"
> + "function (the implicit copy assignment operator)|"
> + "constructor (inherited)}0 %select{|template }1"
> "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 "
> "%plural{1:was|:were}4 provided">;
>
> def note_ovl_candidate_deleted : Note<
> - "candidate %select{function|function|constructor|"
> - "function |function |constructor |||}0%1 "
> - "has been explicitly %select{made unavailable|deleted}2">;
> + "candidate %select{function|function|constructor|"
> + "function |function |constructor ||||constructor (inherited)}0%1 "
> + "has been explicitly %select{made unavailable|deleted}2">;
>
> // Giving the index of the bad argument really clutters this message, and
> // it's relatively unimportant because 1) it's generally obvious which
> @@ -1334,21 +1348,24 @@
> "function |function |constructor |"
> "constructor (the implicit default constructor)|"
> "constructor (the implicit copy constructor)|"
> - "function (the implicit copy assignment operator)}0%1 "
> + "function (the implicit copy assignment operator)|"
> + "constructor (inherited)}0%1 "
> "not viable: cannot convert argument of incomplete type %2 to %3">;
> def note_ovl_candidate_bad_overload : Note<"candidate "
> "%select{function|function|constructor|"
> "function |function |constructor |"
> "constructor (the implicit default constructor)|"
> "constructor (the implicit copy constructor)|"
> - "function (the implicit copy assignment operator)}0%1"
> + "function (the implicit copy assignment operator)|"
> + "constructor (inherited)}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|"
> "function |function |constructor |"
> "constructor (the implicit default constructor)|"
> "constructor (the implicit copy constructor)|"
> - "function (the implicit copy assignment operator)}0%1"
> + "function (the implicit copy assignment operator)|"
> + "constructor (inherited)}0%1"
> " not viable: no known conversion from %2 to %3 for "
> "%select{%ordinal5 argument|object argument}4">;
> def note_ovl_candidate_bad_addrspace : Note<"candidate "
> @@ -1356,12 +1373,13 @@
> "function |function |constructor |"
> "constructor (the implicit default constructor)|"
> "constructor (the implicit copy constructor)|"
> - "function (the implicit copy assignment operator)}0%1 not viable: "
> + "function (the implicit copy assignment operator)|"
> + "constructor (inherited)}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_cvr_this : Note<"candidate "
> "%select{|function|||function||||"
> - "function (the implicit copy assignment operator)}0 not viable: "
> + "function (the implicit copy 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">;
> @@ -1370,7 +1388,8 @@
> "function |function |constructor |"
> "constructor (the implicit default constructor)|"
> "constructor (the implicit copy constructor)|"
> - "function (the implicit copy assignment operator)}0%1 not viable: "
> + "function (the implicit copy assignment operator)|"
> + "constructor (inherited)}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"
> @@ -1380,7 +1399,8 @@
> "function |function |constructor |"
> "constructor (the implicit default constructor)|"
> "constructor (the implicit copy constructor)|"
> - "function (the implicit copy assignment operator)}0%1"
> + "function (the implicit copy assignment operator)|"
> + "constructor (inherited)}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 "
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124970&r1=124969&r2=124970&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Sat Feb 5 13:23:19 2011
> @@ -2091,6 +2091,8 @@
> bool IsTypeName,
> SourceLocation TypenameLoc);
>
> + bool CheckInheritedConstructorUsingDecl(UsingDecl *UD);
> +
> Decl *ActOnUsingDeclaration(Scope *CurScope,
> AccessSpecifier AS,
> bool HasUsingKeyword,
> @@ -2171,6 +2173,12 @@
> void DefineImplicitDestructor(SourceLocation CurrentLocation,
> CXXDestructorDecl *Destructor);
>
> + /// \brief Declare all inherited constructors for the given class.
> + ///
> + /// \param ClassDecl The class declaration into which the inherited
> + /// constructors will be added.
> + void DeclareInheritedConstructors(CXXRecordDecl *ClassDecl);
> +
> /// \brief Declare the implicit copy constructor for the given class.
> ///
> /// \param S The scope of the class, which may be NULL if this is a
>
> Modified: cfe/trunk/lib/AST/DeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=124970&r1=124969&r2=124970&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/DeclCXX.cpp (original)
> +++ cfe/trunk/lib/AST/DeclCXX.cpp Sat Feb 5 13:23:19 2011
> @@ -1204,6 +1204,22 @@
> return true;
> }
>
> +const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const {
> + // Hack: we store the inherited constructor in the overridden method table
> + method_iterator It = begin_overridden_methods();
> + if (It == end_overridden_methods())
> + return 0;
> +
> + return cast<CXXConstructorDecl>(*It);
> +}
> +
> +void
> +CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){
> + // Hack: we store the inherited constructor in the overridden method table
> + assert(size_overridden_methods() == 0 && "Base ctor already set.");
> + addOverriddenMethod(BaseCtor);
> +}
> +
> CXXDestructorDecl *
> CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) {
> return new (C) CXXDestructorDecl(0, DeclarationNameInfo(),
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124970&r1=124969&r2=124970&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Feb 5 13:23:19 2011
> @@ -2787,6 +2787,15 @@
> DiagnoseHiddenVirtualMethods(Record, *M);
> }
> }
> +
> + // Declare inherited constructors. We do this eagerly here because:
> + // - The standard requires an eager diagnostic for conflicting inherited
> + // 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 inherited constructors.
> + DeclareInheritedConstructors(Record);
> }
>
> /// \brief Data used with FindHiddenVirtualMethod
> @@ -4122,8 +4131,7 @@
> LookupQualifiedName(Previous, CurContext);
> }
>
> - NestedNameSpecifier *NNS =
> - static_cast<NestedNameSpecifier *>(SS.getScopeRep());
> + NestedNameSpecifier *NNS = SS.getScopeRep();
>
> // Check for invalid redeclarations.
> if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous))
> @@ -4163,7 +4171,14 @@
> return UD;
> }
>
> - // Look up the target name.
> + // Constructor inheriting using decls get special treatment.
> + if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
> + if (CheckInheritedConstructorUsingDecl(UD))
> + UD->setInvalidDecl();
> + return UD;
> + }
> +
> + // Otherwise, look up the target name.
>
> LookupResult R(*this, NameInfo, LookupOrdinaryName);
>
> @@ -4227,6 +4242,42 @@
> return UD;
> }
>
> +/// Additional checks for a using declaration referring to a constructor name.
> +bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) {
> + if (UD->isTypeName()) {
> + // FIXME: Cannot specify typename when specifying constructor
> + return true;
> + }
> +
> + const Type *SourceType = UD->getTargetNestedNameDecl()->getAsType();
> + assert(SourceType &&
> + "Using decl naming constructor doesn't have type in scope spec.");
> + CXXRecordDecl *TargetClass = cast<CXXRecordDecl>(CurContext);
> +
> + // Check whether the named type is a direct base class.
> + CanQualType CanonicalSourceType = SourceType->getCanonicalTypeUnqualified();
> + CXXRecordDecl::base_class_iterator BaseIt, BaseE;
> + for (BaseIt = TargetClass->bases_begin(), BaseE = TargetClass->bases_end();
> + BaseIt != BaseE; ++BaseIt) {
> + CanQualType BaseType = BaseIt->getType()->getCanonicalTypeUnqualified();
> + if (CanonicalSourceType == BaseType)
> + break;
> + }
> +
> + if (BaseIt == BaseE) {
> + // Did not find SourceType in the bases.
> + Diag(UD->getUsingLocation(),
> + diag::err_using_decl_constructor_not_in_direct_base)
> + << UD->getNameInfo().getSourceRange()
> + << QualType(SourceType, 0) << TargetClass;
> + return true;
> + }
> +
> + BaseIt->setInheritConstructors();
> +
> + return false;
> +}
> +
> /// Checks that the given using declaration is not an invalid
> /// redeclaration. Note that this is checking only for the using decl
> /// itself, not for any ill-formedness among the UsingShadowDecls.
> @@ -4670,6 +4721,180 @@
> MarkVTableUsed(CurrentLocation, ClassDecl);
> }
>
> +void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
> + // We start with an initial pass over the base classes to collect those that
> + // inherit constructors from. If there are none, we can forgo all further
> + // processing.
> + typedef llvm::SmallVector<const RecordType *, 4> BasesVector;
> + BasesVector BasesToInheritFrom;
> + for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(),
> + BaseE = ClassDecl->bases_end();
> + BaseIt != BaseE; ++BaseIt) {
> + if (BaseIt->getInheritConstructors()) {
> + QualType Base = BaseIt->getType();
> + if (Base->isDependentType()) {
> + // If we inherit constructors from anything that is dependent, just
> + // abort processing altogether. We'll get another chance for the
> + // instantiations.
> + return;
> + }
> + BasesToInheritFrom.push_back(Base->castAs<RecordType>());
> + }
> + }
> + if (BasesToInheritFrom.empty())
> + return;
> +
> + // Now collect the constructors that we already have in the current class.
> + // Those take precedence over inherited constructors.
> + // C++0x [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.
> + llvm::SmallSet<const Type *, 8> ExistingConstructors;
> + for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(),
> + CtorE = ClassDecl->ctor_end();
> + CtorIt != CtorE; ++CtorIt) {
> + ExistingConstructors.insert(
> + Context.getCanonicalType(CtorIt->getType()).getTypePtr());
> + }
> +
> + Scope *S = getScopeForContext(ClassDecl);
> + DeclarationName CreatedCtorName =
> + Context.DeclarationNames.getCXXConstructorName(
> + ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified());
> +
> + // Now comes the true work.
> + // First, we keep a map from constructor types to the base that introduced
> + // them. Needed for finding conflicting constructors. We also keep the
> + // actually inserted declarations in there, for pretty diagnostics.
> + typedef std::pair<CanQualType, CXXConstructorDecl *> ConstructorInfo;
> + typedef llvm::DenseMap<const Type *, ConstructorInfo> ConstructorToSourceMap;
> + ConstructorToSourceMap InheritedConstructors;
> + for (BasesVector::iterator BaseIt = BasesToInheritFrom.begin(),
> + BaseE = BasesToInheritFrom.end();
> + BaseIt != BaseE; ++BaseIt) {
> + const RecordType *Base = *BaseIt;
> + CanQualType CanonicalBase = Base->getCanonicalTypeUnqualified();
> + CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getDecl());
> + for (CXXRecordDecl::ctor_iterator CtorIt = BaseDecl->ctor_begin(),
> + CtorE = BaseDecl->ctor_end();
> + CtorIt != CtorE; ++CtorIt) {
> + // Find the using declaration for inheriting this base's constructors.
> + DeclarationName Name =
> + Context.DeclarationNames.getCXXConstructorName(CanonicalBase);
> + UsingDecl *UD = dyn_cast_or_null<UsingDecl>(
> + LookupSingleName(S, Name,SourceLocation(), LookupUsingDeclName));
> + SourceLocation UsingLoc = UD ? UD->getLocation() :
> + ClassDecl->getLocation();
> +
> + // C++0x [class.inhctor]p1: The candidate set of inherited constructors
> + // from the class X named in the using-declaration consists of actual
> + // constructors and notional constructors that result from the
> + // transformation of defaulted parameters as follows:
> + // - all non-template default constructors of X, and
> + // - for each non-template constructor of X that has at least one
> + // parameter with a default argument, the set of constructors that
> + // results from omitting any ellipsis parameter specification and
> + // successively omitting parameters with a default argument from the
> + // end of the parameter-type-list.
> + CXXConstructorDecl *BaseCtor = *CtorIt;
> + bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor();
> + const FunctionProtoType *BaseCtorType =
> + BaseCtor->getType()->getAs<FunctionProtoType>();
> +
> + for (unsigned params = BaseCtor->getMinRequiredArguments(),
> + maxParams = BaseCtor->getNumParams();
> + params <= maxParams; ++params) {
> + // Skip default constructors. They're never inherited.
> + if (params == 0)
> + continue;
> + // Skip copy and move constructors for the same reason.
> + if (CanBeCopyOrMove && params == 1)
> + continue;
> +
> + // Build up a function type for this particular constructor.
> + // FIXME: The working paper does not consider that the exception spec
> + // for the inheriting constructor might be larger than that of the
> + // source. This code doesn't yet, either.
> + const Type *NewCtorType;
> + if (params == maxParams)
> + NewCtorType = BaseCtorType;
> + else {
> + llvm::SmallVector<QualType, 16> Args;
> + for (unsigned i = 0; i < params; ++i) {
> + Args.push_back(BaseCtorType->getArgType(i));
> + }
> + FunctionProtoType::ExtProtoInfo ExtInfo =
> + BaseCtorType->getExtProtoInfo();
> + ExtInfo.Variadic = false;
> + NewCtorType = Context.getFunctionType(BaseCtorType->getResultType(),
> + Args.data(), params, ExtInfo)
> + .getTypePtr();
> + }
> + const Type *CanonicalNewCtorType =
> + Context.getCanonicalType(NewCtorType);
> +
> + // Now that we have the type, first check if the class already has a
> + // constructor with this signature.
> + if (ExistingConstructors.count(CanonicalNewCtorType))
> + continue;
> +
> + // Then we check if we have already declared an inherited constructor
> + // with this signature.
> + std::pair<ConstructorToSourceMap::iterator, bool> result =
> + InheritedConstructors.insert(std::make_pair(
> + CanonicalNewCtorType,
> + std::make_pair(CanonicalBase, (CXXConstructorDecl*)0)));
> + if (!result.second) {
> + // Already in the map. If it came from a different class, that's an
> + // error. Not if it's from the same.
> + CanQualType PreviousBase = result.first->second.first;
> + if (CanonicalBase != PreviousBase) {
> + const CXXConstructorDecl *PrevCtor = result.first->second.second;
> + const CXXConstructorDecl *PrevBaseCtor =
> + PrevCtor->getInheritedConstructor();
> + assert(PrevBaseCtor && "Conflicting constructor was not inherited");
> +
> + Diag(UsingLoc, diag::err_using_decl_constructor_conflict);
> + Diag(BaseCtor->getLocation(),
> + diag::note_using_decl_constructor_conflict_current_ctor);
> + Diag(PrevBaseCtor->getLocation(),
> + diag::note_using_decl_constructor_conflict_previous_ctor);
> + Diag(PrevCtor->getLocation(),
> + diag::note_using_decl_constructor_conflict_previous_using);
> + }
> + continue;
> + }
> +
> + // OK, we're there, now add the constructor.
> + // C++0x [class.inhctor]p8: [...] that would be performed by a
> + // user-writtern inline constructor [...]
> + DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
> + CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
> + Context, ClassDecl, DNI, QualType(NewCtorType, 0), /*TInfo=*/0,
> + BaseCtor->isExplicit(), /*Inline=*/true,
> + /*ImplicitlyDeclared=*/true);
> + NewCtor->setAccess(BaseCtor->getAccess());
> +
> + // Build up the parameter decls and add them.
> + llvm::SmallVector<ParmVarDecl *, 16> ParamDecls;
> + for (unsigned i = 0; i < params; ++i) {
> + ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, UsingLoc,
> + /*IdentifierInfo=*/0,
> + BaseCtorType->getArgType(i),
> + /*TInfo=*/0, SC_None,
> + SC_None, /*DefaultArg=*/0));
> + }
> + NewCtor->setParams(ParamDecls.data(), ParamDecls.size());
> + NewCtor->setInheritedConstructor(BaseCtor);
> +
> + PushOnScopeChains(NewCtor, S, false);
> + ClassDecl->addDecl(NewCtor);
> + result.first->second.second = NewCtor;
> + }
> + }
> + }
> +}
> +
> CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
> // C++ [class.dtor]p2:
> // If a class has no user-declared destructor, a destructor is
> @@ -5590,7 +5815,6 @@
> /*isInline=*/true,
> /*isImplicitlyDeclared=*/true);
> CopyConstructor->setAccess(AS_public);
> - CopyConstructor->setImplicit();
> CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
>
> // Note that we have declared this constructor.
>
> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124970&r1=124969&r2=124970&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Feb 5 13:23:19 2011
> @@ -6201,7 +6201,8 @@
> oc_constructor_template,
> oc_implicit_default_constructor,
> oc_implicit_copy_constructor,
> - oc_implicit_copy_assignment
> + oc_implicit_copy_assignment,
> + oc_implicit_inherited_constructor
> };
>
> OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
> @@ -6219,6 +6220,9 @@
> if (!Ctor->isImplicit())
> return isTemplate ? oc_constructor_template : oc_constructor;
>
> + if (Ctor->getInheritedConstructor())
> + return oc_implicit_inherited_constructor;
> +
> return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor
> : oc_implicit_default_constructor;
> }
> @@ -6237,6 +6241,16 @@
> return isTemplate ? oc_function_template : oc_function;
> }
>
> +void MaybeEmitInheritedConstructorNote(Sema &S, FunctionDecl *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);
> +}
> +
> } // end anonymous namespace
>
> // Notes the location of an overload candidate.
> @@ -6245,6 +6259,7 @@
> OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc);
> Diag(Fn->getLocation(), diag::note_ovl_candidate)
> << (unsigned) K << FnDesc;
> + MaybeEmitInheritedConstructorNote(*this, Fn);
> }
>
> /// Diagnoses an ambiguous conversion. The partial diagnostic is the
> @@ -6299,6 +6314,7 @@
> << (unsigned) FnKind << FnDesc
> << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
> << ToTy << Name << I+1;
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6333,6 +6349,7 @@
> << FromTy
> << FromQs.getAddressSpace() << ToQs.getAddressSpace()
> << (unsigned) isObjectArgument << I+1;
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6350,6 +6367,7 @@
> << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
> << FromTy << (CVR - 1) << I+1;
> }
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6364,6 +6382,7 @@
> << (unsigned) FnKind << FnDesc
> << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
> << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6404,6 +6423,7 @@
> << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
> << (BaseToDerivedConversion - 1)
> << FromTy << ToTy << I+1;
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6412,6 +6432,7 @@
> << (unsigned) FnKind << FnDesc
> << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
> << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
> + MaybeEmitInheritedConstructorNote(S, Fn);
> }
>
> void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
> @@ -6452,6 +6473,7 @@
> S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
> << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
> << modeCount << NumFormalArgs;
> + MaybeEmitInheritedConstructorNote(S, Fn);
> }
>
> /// Diagnose a failed template-argument deduction.
> @@ -6472,6 +6494,7 @@
> assert(ParamD && "no parameter found for incomplete deduction result");
> S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction)
> << ParamD->getDeclName();
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6496,6 +6519,7 @@
>
> S.Diag(Fn->getLocation(), diag::note_ovl_candidate_underqualified)
> << ParamD->getDeclName() << Arg << NonCanonParam;
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6514,6 +6538,7 @@
> << which << ParamD->getDeclName()
> << *Cand->DeductionFailure.getFirstArg()
> << *Cand->DeductionFailure.getSecondArg();
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6536,6 +6561,7 @@
> diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
> << (index + 1);
> }
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
>
> case Sema::TDK_TooManyArguments:
> @@ -6545,6 +6571,7 @@
>
> case Sema::TDK_InstantiationDepth:
> S.Diag(Fn->getLocation(), diag::note_ovl_candidate_instantiation_depth);
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
>
> case Sema::TDK_SubstitutionFailure: {
> @@ -6556,6 +6583,7 @@
> *Args);
> S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure)
> << ArgString;
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6564,6 +6592,7 @@
> case Sema::TDK_NonDeducedMismatch:
> case Sema::TDK_FailedOverloadResolution:
> S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
> }
> @@ -6592,6 +6621,7 @@
>
> S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
> << FnKind << FnDesc << Fn->isDeleted();
> + MaybeEmitInheritedConstructorNote(S, Fn);
> return;
> }
>
> @@ -6658,6 +6688,7 @@
>
> S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand)
> << FnType;
> + MaybeEmitInheritedConstructorNote(S, Cand->Surrogate);
> }
>
> void NoteBuiltinOperatorCandidate(Sema &S,
>
> Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=124970&r1=124969&r2=124970&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReader.cpp Sat Feb 5 13:23:19 2011
> @@ -4381,11 +4381,14 @@
> bool isVirtual = static_cast<bool>(Record[Idx++]);
> bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
> AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]);
> + bool inheritConstructors = static_cast<bool>(Record[Idx++]);
> TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx);
> SourceRange Range = ReadSourceRange(F, Record, Idx);
> SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx);
> - return CXXBaseSpecifier(Range, isVirtual, isBaseOfClass, AS, TInfo,
> + CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo,
> EllipsisLoc);
> + Result.setInheritConstructors(inheritConstructors);
> + return Result;
> }
>
> std::pair<CXXCtorInitializer **, unsigned>
>
> Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=124970&r1=124969&r2=124970&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Sat Feb 5 13:23:19 2011
> @@ -3304,6 +3304,7 @@
> Record.push_back(Base.isVirtual());
> Record.push_back(Base.isBaseOfClass());
> Record.push_back(Base.getAccessSpecifierAsWritten());
> + Record.push_back(Base.getInheritConstructors());
> AddTypeSourceInfo(Base.getTypeSourceInfo(), Record);
> AddSourceRange(Base.getSourceRange(), Record);
> AddSourceLocation(Base.isPackExpansion()? Base.getEllipsisLoc()
>
> Added: cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp?rev=124970&view=auto
> ==============================================================================
> --- cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp (added)
> +++ cfe/trunk/test/CXX/special/class.inhctor/elsewhere.cpp Sat Feb 5 13:23:19 2011
> @@ -0,0 +1,31 @@
> +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
> +
> +// Tests related to constructor inheriting, but not specified in [class.inhctor]
> +
> +// [namespace.udecl]p8:
> +// A using-declaration for a class member shall be a member-declaration.
> +
> +struct B1 {
> + B1(int);
> +};
> +
> +using B1::B1; // expected-error {{using declaration can not refer to class member}}
> +
> +// C++0x [namespace.udecl]p10:
> +// A using-declaration is a declaration and can therefore be used repeatedly
> +// where (and only where) multiple declarations are allowed.
> +
> +struct I1 : B1 {
> + using B1::B1; // expected-note {{previous using declaration}}
> + using B1::B1; // expected-error {{redeclaration of using decl}}
> +};
> +
> +// C++0x [namespace.udecl]p3:
> +// In a using declaration used as a member-declaration, the nested-name-
> +// specifier shall name a base class of the class being defined.
> +// If such a using-declaration names a constructor, the nested-name-specifier
> +// shall name a direct base class of the class being defined.
> +
> +struct D1 : I1 {
> + using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}}
> +};
>
> Added: cfe/trunk/test/CXX/special/class.inhctor/p3.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p3.cpp?rev=124970&view=auto
> ==============================================================================
> --- cfe/trunk/test/CXX/special/class.inhctor/p3.cpp (added)
> +++ cfe/trunk/test/CXX/special/class.inhctor/p3.cpp Sat Feb 5 13:23:19 2011
> @@ -0,0 +1,30 @@
> +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
> +
> +struct B1 {
> + B1(int);
> + B1(int, int);
> +};
> +struct D1 : B1 {
> + using B1::B1;
> +};
> +D1 d1a(1), d1b(1, 1);
> +
> +D1 fd1() { return 1; }
> +
> +struct B2 {
> + explicit B2(int, int = 0, int = 0);
> +};
> +struct D2 : B2 { // expected-note {{candidate constructor}}
> + using B2::B2;
> +};
> +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 D3 : B3 { // expected-note {{candidate constructor}}
> + using B3::B3; // expected-note {{candidate constructor (inherited)}}
> +};
> +D3 fd3() { return 1; } // expected-error {{no viable conversion}}
>
> Added: cfe/trunk/test/CXX/special/class.inhctor/p7.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.inhctor/p7.cpp?rev=124970&view=auto
> ==============================================================================
> --- cfe/trunk/test/CXX/special/class.inhctor/p7.cpp (added)
> +++ cfe/trunk/test/CXX/special/class.inhctor/p7.cpp Sat Feb 5 13:23:19 2011
> @@ -0,0 +1,18 @@
> +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
> +
> +// Straight from the standard
> +struct B1 {
> + B1(int); // expected-note {{previous constructor}}
> +};
> +struct B2 {
> + B2(int); // expected-note {{conflicting constructor}}
> +};
> +struct D1 : B1, B2 {
> + using B1::B1; // expected-note {{inherited here}}
> + using B2::B2; // expected-error {{already inherited constructor with the same signature}}
> +};
> +struct D2 : B1, B2 {
> + using B1::B1;
> + using B2::B2;
> + D2(int);
> +};
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list