summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2011-02-05 19:23:19 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2011-02-05 19:23:19 +0000
commitf677ea3cc9598d9952ad7ffab5fb322ba4c5be31 (patch)
tree6fd84ac5d0d6b1128c4f53e7a36f08b89996f47b
parent57ca32bbf03d30b8867f6c07f1a3e42484bbfec7 (diff)
Basic implementation of inherited constructors. Only generates declarations, and probably only works for very basic use cases.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124970 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclCXX.h24
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td44
-rw-r--r--include/clang/Sema/Sema.h8
-rw-r--r--lib/AST/DeclCXX.cpp16
-rw-r--r--lib/Sema/SemaDeclCXX.cpp232
-rw-r--r--lib/Sema/SemaOverload.cpp33
-rw-r--r--lib/Serialization/ASTReader.cpp5
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--test/CXX/special/class.inhctor/elsewhere.cpp31
-rw-r--r--test/CXX/special/class.inhctor/p3.cpp30
-rw-r--r--test/CXX/special/class.inhctor/p7.cpp18
11 files changed, 421 insertions, 21 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 1d1b749feb..d11ee8f7fd 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -187,6 +187,10 @@ class CXXBaseSpecifier {
/// 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 @@ public:
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 @@ public:
/// \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 @@ public:
/// 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()); }
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 4c5db08802..9839359688 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -162,6 +162,17 @@ def err_using_decl_nested_name_specifier_is_current_class : Error<
"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 @@ def note_ovl_candidate : Note<"candidate "
"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 @@ def note_ovl_candidate_arity : 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 %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 @@ def note_ovl_candidate_bad_conv_incomplete : Note<"candidate "
"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 @@ def note_ovl_candidate_bad_addrspace : Note<"candidate "
"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 @@ def note_ovl_candidate_bad_cvr : Note<"candidate "
"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 @@ def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate "
"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 "
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 026930dabf..65b6c860f4 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2091,6 +2091,8 @@ public:
bool IsTypeName,
SourceLocation TypenameLoc);
+ bool CheckInheritedConstructorUsingDecl(UsingDecl *UD);
+
Decl *ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
bool HasUsingKeyword,
@@ -2171,6 +2173,12 @@ public:
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
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index bce8b92c48..fba73f59d5 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1204,6 +1204,22 @@ 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 = 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(),
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 49be40c5e4..0f8f87143e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2787,6 +2787,15 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
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 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
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 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
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 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
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 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
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 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
CopyConstructor->setAccess(AS_public);
- CopyConstructor->setImplicit();
CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Note that we have declared this constructor.
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 00cdca3bcf..916c5a198f 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -6201,7 +6201,8 @@ enum OverloadCandidateKind {
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 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
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 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
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 @@ void Sema::NoteOverloadCandidate(FunctionDecl *Fn) {
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 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< ToTy << Name << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6333,6 +6349,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
<< FromTy
<< FromQs.getAddressSpace() << ToQs.getAddressSpace()
<< (unsigned) isObjectArgument << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6350,6 +6367,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << (CVR - 1) << I+1;
}
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6364,6 +6382,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6404,6 +6423,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< (BaseToDerivedConversion - 1)
<< FromTy << ToTy << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6412,6 +6432,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
<< (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 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
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 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
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 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_underqualified)
<< ParamD->getDeclName() << Arg << NonCanonParam;
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6514,6 +6538,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
<< which << ParamD->getDeclName()
<< *Cand->DeductionFailure.getFirstArg()
<< *Cand->DeductionFailure.getSecondArg();
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6536,6 +6561,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
<< (index + 1);
}
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
case Sema::TDK_TooManyArguments:
@@ -6545,6 +6571,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
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 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
*Args);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_substitution_failure)
<< ArgString;
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6564,6 +6592,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
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 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
<< FnKind << FnDesc << Fn->isDeleted();
+ MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -6658,6 +6688,7 @@ void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand)
<< FnType;
+ MaybeEmitInheritedConstructorNote(S, Cand->Surrogate);
}
void NoteBuiltinOperatorCandidate(Sema &S,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index f8f281d999..68e2e79dde 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -4381,11 +4381,14 @@ ASTReader::ReadCXXBaseSpecifier(PerFileData &F,
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>
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b85aac1cc9..9ffcc1d9d3 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -3304,6 +3304,7 @@ void ASTWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
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()
diff --git a/test/CXX/special/class.inhctor/elsewhere.cpp b/test/CXX/special/class.inhctor/elsewhere.cpp
new file mode 100644
index 0000000000..82944d65df
--- /dev/null
+++ b/test/CXX/special/class.inhctor/elsewhere.cpp
@@ -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}}
+};
diff --git a/test/CXX/special/class.inhctor/p3.cpp b/test/CXX/special/class.inhctor/p3.cpp
new file mode 100644
index 0000000000..021f701ab4
--- /dev/null
+++ b/test/CXX/special/class.inhctor/p3.cpp
@@ -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}}
diff --git a/test/CXX/special/class.inhctor/p7.cpp b/test/CXX/special/class.inhctor/p7.cpp
new file mode 100644
index 0000000000..3ad761f08b
--- /dev/null
+++ b/test/CXX/special/class.inhctor/p7.cpp
@@ -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);
+};