Bring inheriting constructor implementation up-to-date with current defect

reports, and implement implicit definition of inheriting constructors.
Remaining missing features: inheriting constructor templates, implicit
exception specifications for inheriting constructors, inheriting constructors
from dependent bases.

llvm-svn: 177320
This commit is contained in:
Richard Smith 2013-03-18 21:12:30 +00:00
parent 260e28d65a
commit c2bc61b006
14 changed files with 446 additions and 120 deletions

View File

@ -2863,6 +2863,9 @@ public:
assert(i < NumArgs && "Invalid argument number!");
return arg_type_begin()[i];
}
ArrayRef<QualType> getArgTypes() const {
return ArrayRef<QualType>(arg_type_begin(), arg_type_end());
}
ExtProtoInfo getExtProtoInfo() const {
ExtProtoInfo EPI;

View File

@ -254,19 +254,20 @@ 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 can not refer to class member">;
def err_using_decl_can_not_refer_to_namespace : Error<
"using declaration can not refer to namespace">;
def err_using_decl_constructor : Error<
"using declaration can not refer to a constructor">;
def err_using_decl_constructor_unsupported : Error<
"inheriting constructors are not supported">;
// FIXME: Replace the above error with this warning if support for
// inheriting constructors is implemented.
//def warn_cxx98_compat_using_decl_constructor : Warning<
// "inheriting constructors are incompatible with C++98">,
// InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_using_decl_constructor : Warning<
"inheriting constructors are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_using_decl_destructor : Error<
"using declaration can not refer to a destructor">;
def err_using_decl_template_id : Error<
@ -1104,9 +1105,11 @@ def note_member_synthesized_at : Note<
"implicit default %select{constructor|copy constructor|move constructor|copy "
"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">;
def err_missing_default_ctor : Error<
"%select{|implicit default }0constructor for %1 must explicitly initialize "
"the %select{base class|member}2 %3 which does not have a default "
"%select{|implicit default |inheriting }0constructor for %1 must explicitly "
"initialize the %select{base class|member}2 %3 which does not have a default "
"constructor">;
def err_illegal_union_or_anon_struct_member : Error<
@ -2274,8 +2277,8 @@ def err_uninitialized_member_for_assign : Error<
"non-static %select{reference|const}1 member %2 can't use default "
"assignment operator">;
def err_uninitialized_member_in_ctor : Error<
"%select{|implicit default }0constructor for %1 must explicitly initialize "
"the %select{reference|const}2 member %3">;
"%select{|implicit default |inheriting }0constructor for %1 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 "
"%select{default|copy|move}0 constructor">;

View File

@ -3597,6 +3597,11 @@ public:
ImplicitExceptionSpecification
ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD);
/// \brief Determine what sort of exception specification an inheriting
/// constructor of a class will have.
ImplicitExceptionSpecification
ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD);
/// \brief Evaluate the implicit exception specification for a defaulted
/// special member function.
void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD);
@ -3649,11 +3654,15 @@ public:
void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
CXXDestructorDecl *Destructor);
/// \brief Declare all inherited constructors for the given class.
/// \brief Declare all inheriting constructors for the given class.
///
/// \param ClassDecl The class declaration into which the inherited
/// \param ClassDecl The class declaration into which the inheriting
/// constructors will be added.
void DeclareInheritedConstructors(CXXRecordDecl *ClassDecl);
void DeclareInheritingConstructors(CXXRecordDecl *ClassDecl);
/// \brief Define the specified inheriting constructor.
void DefineInheritingConstructor(SourceLocation UseLoc,
CXXConstructorDecl *Constructor);
/// \brief Declare the implicit copy constructor for the given class.
///

View File

@ -2642,9 +2642,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
}
// Create a static_cast\<T&&>(expr).
static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
QualType ExprType = E->getType();
QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType);
static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) {
if (T.isNull()) T = E->getType();
QualType TargetType = SemaRef.BuildReferenceType(
T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName());
SourceLocation ExprLoc = E->getLocStart();
TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo(
TargetType, ExprLoc);
@ -2659,7 +2660,8 @@ static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
enum ImplicitInitializerKind {
IIK_Default,
IIK_Copy,
IIK_Move
IIK_Move,
IIK_Inherit
};
static bool
@ -2675,6 +2677,35 @@ 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.take(), PD->getType()));
}
InitializationKind InitKind = InitializationKind::CreateDirect(
Constructor->getLocation(), SourceLocation(), SourceLocation());
InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
Args.data(), Args.size());
BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args);
break;
}
}
// Fall through.
case IIK_Default: {
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
@ -2897,7 +2928,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
return false;
}
assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!");
assert((ImplicitInitKind == IIK_Default || ImplicitInitKind == IIK_Inherit) &&
"Unhandled implicit init kind!");
QualType FieldBaseElementType =
SemaRef.Context.getBaseElementType(Field->getType());
@ -2988,6 +3020,8 @@ struct BaseAndFieldInfo {
IIK = IIK_Copy;
else if (Generated && Ctor->isMoveConstructor())
IIK = IIK_Move;
else if (Ctor->getInheritedConstructor())
IIK = IIK_Inherit;
else
IIK = IIK_Default;
}
@ -2999,6 +3033,7 @@ struct BaseAndFieldInfo {
return true;
case IIK_Default:
case IIK_Inherit:
return false;
}
@ -3226,7 +3261,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
// If we're not generating the implicit copy/move constructor, then we'll
// handle anonymous struct/union fields based on their individual
// indirect fields.
if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default)
if (F->isAnonymousStructOrUnion() && !Info.isImplicitCopyOrMove())
continue;
if (CollectFieldInitializer(*this, Info, F))
@ -3235,7 +3270,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
}
// Beyond this point, we only consider default initialization.
if (Info.IIK != IIK_Default)
if (Info.isImplicitCopyOrMove())
continue;
if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) {
@ -4062,14 +4097,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
// Declare inherited constructors. We do this eagerly here because:
// - The standard requires an eager diagnostic for conflicting inherited
// 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 inherited constructors.
DeclareInheritedConstructors(Record);
// have inheriting constructors.
DeclareInheritingConstructors(Record);
}
/// Is the special member function which would be selected to perform the
@ -4185,7 +4220,9 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
case Sema::CXXInvalid:
break;
}
llvm_unreachable("only special members have implicit exception specs");
assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
"only special members have implicit exception specs");
return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
}
static void
@ -4194,10 +4231,7 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
ExceptSpec.getEPI(EPI);
const FunctionProtoType *NewFPT = cast<FunctionProtoType>(
S.Context.getFunctionType(FPT->getResultType(),
ArrayRef<QualType>(FPT->arg_type_begin(),
FPT->getNumArgs()),
EPI));
S.Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI));
FD->setType(QualType(NewFPT, 0));
}
@ -5644,10 +5678,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
return Context.getFunctionType(Context.VoidTy,
ArrayRef<QualType>(Proto->arg_type_begin(),
Proto->getNumArgs()),
EPI);
return Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(), EPI);
}
/// CheckConstructor - Checks a fully-formed constructor for
@ -6519,9 +6550,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
// C++11 inheriting constructors.
Diag(Name.getLocStart(),
getLangOpts().CPlusPlus11 ?
// FIXME: Produce warn_cxx98_compat_using_decl_constructor
// instead once inheriting constructors work.
diag::err_using_decl_constructor_unsupported :
diag::warn_cxx98_compat_using_decl_constructor :
diag::err_using_decl_constructor)
<< SS.getRange();
@ -6545,7 +6574,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
if (!TargetName)
return 0;
// Warn about using declarations.
// Warn about access declarations.
// TODO: store that the declaration was written without 'using' and
// talk about access decls instead of using decls in the
// diagnostics.
@ -7471,6 +7500,13 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
return ExceptSpec;
}
Sema::ImplicitExceptionSpecification
Sema::ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD) {
ImplicitExceptionSpecification ExceptSpec(*this);
// FIXME: Compute the exception spec.
return ExceptSpec;
}
namespace {
/// RAII object to register a special member as being currently declared.
struct DeclaringSpecialMember {
@ -7597,7 +7633,7 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
}
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
void Sema::DeclareInheritingConstructors(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.
@ -7612,6 +7648,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// If we inherit constructors from anything that is dependent, just
// abort processing altogether. We'll get another chance for the
// instantiations.
// FIXME: We need to ensure that any call to a constructor of this class
// is considered instantiation-dependent in this case.
return;
}
BasesToInheritFrom.push_back(Base->castAs<RecordType>());
@ -7620,18 +7658,19 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
if (BasesToInheritFrom.empty())
return;
// FIXME: Constructor templates.
// 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 [...]
// 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.
llvm::SmallSet<const Type *, 8> ExistingConstructors;
for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(),
CtorE = ClassDecl->ctor_end();
CtorIt != CtorE; ++CtorIt) {
CtorIt != CtorE; ++CtorIt)
ExistingConstructors.insert(
Context.getCanonicalType(CtorIt->getType()).getTypePtr());
}
DeclarationName CreatedCtorName =
Context.DeclarationNames.getCXXConstructorName(
@ -7663,62 +7702,71 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
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
// C++11 [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 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.
// end of the parameter-type-list, and
// FIXME: ...also constructor templates.
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) {
// Determine whether this would be a copy or move constructor for the
// derived class.
if (BaseCtorType->getNumArgs() >= 1 &&
BaseCtorType->getArgType(0)->isReferenceType() &&
Context.hasSameUnqualifiedType(
BaseCtorType->getArgType(0)->getPointeeType(),
Context.getTagDeclType(ClassDecl)))
CanBeCopyOrMove = true;
ArrayRef<QualType> ArgTypes(BaseCtorType->getArgTypes());
FunctionProtoType::ExtProtoInfo EPI = BaseCtorType->getExtProtoInfo();
// Core issue (no number yet): the ellipsis is always discarded.
if (EPI.Variadic) {
Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis);
Diag(BaseCtor->getLocation(),
diag::note_using_decl_constructor_ellipsis);
EPI.Variadic = false;
}
for (unsigned Params = BaseCtor->getMinRequiredArguments(),
MaxParams = BaseCtor->getNumParams();
Params <= MaxParams; ++Params) {
// Skip default constructors. They're never inherited.
if (params == 0)
if (Params == 0)
continue;
// Skip copy and move constructors for the same reason.
if (CanBeCopyOrMove && params == 1)
// Skip copy and move constructors for both base and derived class
// 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. When it does, this code will
// need to be delayed until after exception specifications and in-class
// member initializers are attached.
const Type *NewCtorType;
if (params == maxParams)
NewCtorType = BaseCtorType;
else {
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, ExtInfo)
.getTypePtr();
}
QualType NewCtorType =
Context.getFunctionType(Context.VoidTy, ArgTypes.slice(0, Params),
EPI);
const Type *CanonicalNewCtorType =
Context.getCanonicalType(NewCtorType);
Context.getCanonicalType(NewCtorType).getTypePtr();
// Now that we have the type, first check if the class already has a
// constructor with this signature.
// 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 (ExistingConstructors.count(CanonicalNewCtorType))
continue;
// Then we check if we have already declared an inherited constructor
// with this signature.
// C++11 [class.inhctor]p7:
// If two using-declarations declare inheriting constructors with the
// same signature, the program is ill-formed
std::pair<ConstructorToSourceMap::iterator, bool> result =
InheritedConstructors.insert(std::make_pair(
CanonicalNewCtorType,
@ -7740,35 +7788,47 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
diag::note_using_decl_constructor_conflict_previous_ctor);
Diag(PrevCtor->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.
result.first->second.second->setDeletedAsWritten();
}
continue;
}
// OK, we're there, now add the constructor.
// C++0x [class.inhctor]p8: [...] that would be performed by a
// user-written inline constructor [...]
DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0),
Context, ClassDecl, UsingLoc, DNI, NewCtorType,
/*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true,
/*ImplicitlyDeclared=*/true,
// FIXME: Due to a defect in the standard, we treat inherited
// constructors as constexpr even if that makes them ill-formed.
/*Constexpr=*/BaseCtor->isConstexpr());
/*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr());
NewCtor->setAccess(BaseCtor->getAccess());
// Build an unevaluated exception specification for this constructor.
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = NewCtor;
NewCtor->setType(Context.getFunctionType(Context.VoidTy,
ArgTypes.slice(0, Params),
EPI));
// Build up the parameter decls and add them.
SmallVector<ParmVarDecl *, 16> ParamDecls;
for (unsigned i = 0; i < params; ++i) {
ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor,
UsingLoc, UsingLoc,
/*IdentifierInfo=*/0,
BaseCtorType->getArgType(i),
/*TInfo=*/0, SC_None,
SC_None, /*DefaultArg=*/0));
for (unsigned i = 0; i < Params; ++i) {
ParmVarDecl *PD = ParmVarDecl::Create(Context, NewCtor,
UsingLoc, UsingLoc,
/*IdentifierInfo=*/0,
BaseCtorType->getArgType(i),
/*TInfo=*/0, SC_None,
SC_None, /*DefaultArg=*/0);
PD->setScopeInfo(0, i);
PD->setImplicit();
ParamDecls.push_back(PD);
}
NewCtor->setParams(ParamDecls);
NewCtor->setInheritedConstructor(BaseCtor);
if (BaseCtor->isDeleted())
NewCtor->setDeletedAsWritten();
ClassDecl->addDecl(NewCtor);
result.first->second.second = NewCtor;
@ -7777,6 +7837,35 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
}
}
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);
Constructor->setInvalidDecl();
return;
}
SourceLocation Loc = Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc));
Constructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
}
}
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
CXXRecordDecl *ClassDecl = MD->getParent();

View File

@ -10501,6 +10501,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
if (!Constructor->isUsed(false))
DefineImplicitMoveConstructor(Loc, Constructor);
}
} else if (Constructor->getInheritedConstructor()) {
if (!Constructor->isUsed(false))
DefineInheritingConstructor(Loc, Constructor);
}
MarkVTableUsed(Loc, Constructor->getParent());

View File

@ -5825,7 +5825,8 @@ bool InitializationSequence::Diagnose(Sema &S,
= cast<CXXConstructorDecl>(S.CurContext);
if (Entity.getKind() == InitializedEntity::EK_Base) {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
<< Constructor->isImplicit()
<< (Constructor->getInheritedConstructor() ? 2 :
Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*base=*/0
<< Entity.getType();
@ -5837,7 +5838,8 @@ bool InitializationSequence::Diagnose(Sema &S,
<< S.Context.getTagDeclType(BaseDecl);
} else {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
<< Constructor->isImplicit()
<< (Constructor->getInheritedConstructor() ? 2 :
Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*member=*/1
<< Entity.getName();
@ -5898,7 +5900,8 @@ bool InitializationSequence::Diagnose(Sema &S,
// initialized.
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext);
S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor)
<< Constructor->isImplicit()
<< (Constructor->getInheritedConstructor() ? 2 :
Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*const=*/1
<< Entity.getName();

View File

@ -9,49 +9,49 @@ struct B1 {
B1(int);
};
using B1::B1; // expected-error {{using declaration can not refer to class member}} expected-error {{not supported}}
using B1::B1; // expected-error {{using declaration can not refer to class member}}
// C++0x [namespace.udecl]p10:
// C++11 [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}} expected-error {{not supported}}
using B1::B1; // expected-error {{redeclaration of using decl}} expected-error {{not supported}}
using B1::B1; // expected-note {{previous using declaration}}
using B1::B1; // expected-error {{redeclaration of using decl}}
};
// C++0x [namespace.udecl]p3:
// C++11 [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}} expected-error {{not supported}}
using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}}
};
template<typename T> struct A {};
template<typename T> struct B : A<bool>, A<char> {
using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}} expected-error {{not supported}}
using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}}
};
B<bool> bb;
B<char> bc;
B<double> bd; // expected-note {{here}}
template<typename T> struct C : A<T> {
using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}} expected-error {{not supported}}
using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}}
};
C<bool> cb;
C<char> cc; // expected-note {{here}}
template<typename T> struct D : A<T> {};
template<typename T> struct E : D<T> {
using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}} expected-error {{not supported}}
using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}}
};
E<bool> eb; // expected-note {{here}}
template<typename T> struct F : D<bool> {
using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}} expected-error {{not supported}}
using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}}
};
F<bool> fb; // expected-note {{here}}

View File

@ -0,0 +1,31 @@
// 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 5{{here}}
A(int = 0, int = 0, ...); // expected-note {{here}}
};
struct B : A { // expected-note 3{{candidate}}
using A::A; // expected-warning 3{{inheriting constructor does not inherit ellipsis}} expected-note 4{{candidate}} expected-note 2{{deleted}}
};
B b0{};
// expected-error@-1 {{call to implicitly-deleted default constructor}}
// expected-note@9 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}}
B b1{1};
// FIXME: explain why the inheriting constructor was deleted
// expected-error@-2 {{call to implicitly-deleted function of 'B'}}
B b2{1,2};
// expected-error@-1 {{call to implicitly-deleted function of 'B'}}
B b3{1,2,3};
// 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'}}

View File

@ -0,0 +1,87 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
template<int> struct X {};
// Constructor characteristics are:
// - the template parameter list [FIXME]
// - the parameter-type-list
// - absence or presence of explicit
// - absence or presence of constexpr
struct A {
A(X<0>) {} // expected-note 2{{here}}
constexpr A(X<1>) {}
explicit A(X<2>) {} // expected-note 3{{here}}
explicit constexpr A(X<3>) {} // expected-note 2{{here}}
};
A a0 { X<0>{} };
A a0i = { X<0>{} };
constexpr A a0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr A a0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
A a1 { X<1>{} };
A a1i = { X<1>{} };
constexpr A a1c { X<1>{} };
constexpr A a1ic = { X<1>{} };
A a2 { X<2>{} };
A a2i = { X<2>{} }; // expected-error {{constructor is explicit}}
constexpr A a2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr A a2ic = { X<2>{} }; // expected-error {{constructor is explicit}}
A a3 { X<3>{} };
A a3i = { X<3>{} }; // expected-error {{constructor is explicit}}
constexpr A a3c { X<3>{} };
constexpr A a3ic = { X<3>{} }; // expected-error {{constructor is explicit}}
struct B : A {
using A::A; // expected-note 7{{here}}
};
B b0 { X<0>{} };
B b0i = { X<0>{} };
constexpr B b0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr B b0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
B b1 { X<1>{} };
B b1i = { X<1>{} };
constexpr B b1c { X<1>{} };
constexpr B b1ic = { X<1>{} };
B b2 { X<2>{} };
B b2i = { X<2>{} }; // expected-error {{constructor is explicit}}
constexpr B b2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr B b2ic = { X<2>{} }; // expected-error {{constructor is explicit}}
B b3 { X<3>{} };
B b3i = { X<3>{} }; // expected-error {{constructor is explicit}}
constexpr B b3c { X<3>{} };
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 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)'}}
struct ConstexprEval {
constexpr ConstexprEval(int a, const char *p) : k(p[a]) {}
char k;
};
struct ConstexprEval2 {
char k2 = 'x';
};
struct ConstexprEval3 : ConstexprEval, ConstexprEval2 {
using ConstexprEval::ConstexprEval;
};
constexpr ConstexprEval3 ce{4, "foobar"};
static_assert(ce.k == 'a', "");
static_assert(ce.k2 == 'x', "");

View File

@ -5,7 +5,7 @@ struct B1 {
B1(int, int);
};
struct D1 : B1 {
using B1::B1; // expected-error {{not supported}}
using B1::B1;
};
D1 d1a(1), d1b(1, 1);
@ -15,7 +15,7 @@ struct B2 {
explicit B2(int, int = 0, int = 0);
};
struct D2 : B2 { // expected-note 2 {{candidate constructor}}
using B2::B2; // expected-error {{not supported}}
using B2::B2;
};
D2 d2a(1), d2b(1, 1), d2c(1, 1, 1);
@ -25,18 +25,18 @@ struct B3 {
B3(void*); // expected-note {{inherited from here}}
};
struct D3 : B3 { // expected-note 2 {{candidate constructor}}
using B3::B3; // expected-note {{candidate constructor (inherited)}} expected-error {{not supported}}
using B3::B3; // expected-note {{candidate constructor (inherited)}}
};
D3 fd3() { return 1; } // expected-error {{no viable conversion}}
template<typename T> struct T1 : B1 {
using B1::B1; // expected-error {{not supported}}
using B1::B1;
};
template<typename T> struct T2 : T1<T> {
using T1<int>::T1; // expected-error {{not supported}}
using T1<int>::T1;
};
template<typename T> struct T3 : T1<int> {
using T1<T>::T1; // expected-error {{not supported}}
using T1<T>::T1;
};
struct U {
friend T1<int>::T1(int);

View File

@ -0,0 +1,70 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
template<int> struct X {};
// A[n inheriting] constructor [...] has the same access as the corresponding
// constructor [in the base class].
struct A {
public:
A(X<0>) {}
protected:
A(X<1>) {}
private:
A(X<2>) {} // expected-note {{declared private here}}
friend class FA;
};
struct B : A {
using A::A; // expected-error {{private constructor}} expected-note {{implicitly declared protected here}}
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}}
struct C : B {
C(X<0> x) : B(x) {}
C(X<1> x) : B(x) {}
};
struct FB {
B b0{X<0>{}};
B b1{X<1>{}};
};
struct FA : A {
using A::A; // expected-note 2{{here}}
};
FA fa0{X<0>{}};
FA fa1{X<1>{}}; // expected-error {{calling a protected constructor}}
FA fa2{X<2>{}}; // expected-error {{calling a private constructor}}
// It is deleted if the corresponding constructor [...] is deleted.
struct G {
G(int) = delete;
};
struct H : G {
using G::G; // expected-note {{marked deleted here}}
};
H h(5); // expected-error {{call to implicitly-deleted function of 'H'}}
// Core defect: It is also deleted if multiple base constructors generate the
// same signature.
namespace DRnnnn {
struct A {
constexpr A(int, float = 0) {}
explicit A(int, int = 0) {}
A(int, int, int = 0) = delete;
};
struct B : A {
// FIXME: produce notes indicating why it was deleted
using A::A; // expected-note {{here}}
};
constexpr B b0(0, 0.0f); // ok, constexpr
B b1(0, 1); // expected-error {{call to implicitly-deleted}}
}

View File

@ -8,12 +8,12 @@ struct B2 {
B2(int); // expected-note {{conflicting constructor}}
};
struct D1 : B1, B2 {
using B1::B1; // expected-note {{inherited here}} expected-error {{not supported}}
using B2::B2; // expected-error {{already inherited constructor with the same signature}} expected-error {{not supported}}
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; // expected-error {{not supported}}
using B2::B2; // expected-error {{not supported}}
using B1::B1;
using B2::B2;
D2(int);
};
@ -22,8 +22,8 @@ template<typename T> struct B3 {
};
template<typename T> struct B4 : B3<T>, B1 {
B4();
using B3<T>::B3; // expected-note {{inherited here}} expected-error {{not supported}}
using B1::B1; // expected-error {{already inherited}} expected-error {{not supported}}
using B3<T>::B3; // expected-note {{inherited here}}
using B1::B1; // expected-error {{already inherited}}
};
B4<char> b4c;
B4<int> b4i; // expected-note {{here}}

View File

@ -0,0 +1,21 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
// expected-no-diagnostics
struct A {
constexpr A(const int&) : rval(false) {}
constexpr A(const int&&) : rval(true) {}
bool rval;
};
struct B : A {
using A::A;
};
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, "");

View File

@ -1,11 +1,18 @@
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
// XFAIL: *
// PR12219
struct A { A(int); virtual ~A(); };
struct B : A { using A::A; ~B(); };
B::~B() {}
B b(123);
// CHECK: define void @_ZN1BD0Ev
// CHECK: define void @_ZN1BD1Ev
// CHECK: define void @_ZN1BD2Ev
// CHECK: define linkonce_odr void @_ZN1BC1Ei(
// CHECK: call void @_ZN1BC2Ei(
// CHECK: define linkonce_odr void @_ZN1BC2Ei(
// CHECK: call void @_ZN1AC2Ei(