[c++1z] P0091R3: Basic support for deducing class template arguments via deduction-guides.

llvm-svn: 294613
This commit is contained in:
Richard Smith 2017-02-09 19:17:44 +00:00
parent a18ef6f1f9
commit 60437620db
17 changed files with 631 additions and 190 deletions

View File

@ -1470,7 +1470,8 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
public:
CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
QualType Type,
TypeSourceInfo *TSI,
ArrayRef<Expr *> Args,
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,

View File

@ -4115,7 +4115,10 @@ class DeducedType : public Type {
protected:
DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent,
bool IsInstantiationDependent, bool ContainsParameterPack)
: Type(TC, DeducedAsType.isNull() ? QualType(this, 0) : DeducedAsType,
: Type(TC,
// FIXME: Retain the sugared deduced type?
DeducedAsType.isNull() ? QualType(this, 0)
: DeducedAsType.getCanonicalType(),
IsDependent, IsInstantiationDependent,
/*VariablyModified=*/false, ContainsParameterPack) {
if (!DeducedAsType.isNull()) {

View File

@ -1849,8 +1849,8 @@ def warn_cxx98_compat_temp_copy : Warning<
InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore;
def err_selected_explicit_constructor : Error<
"chosen constructor is explicit in copy-initialization">;
def note_constructor_declared_here : Note<
"constructor declared here">;
def note_explicit_ctor_deduction_guide_here : Note<
"explicit %select{constructor|deduction guide}0 declared here">;
// C++11 decltype
def err_decltype_in_declarator : Error<
@ -1961,8 +1961,23 @@ def err_deduced_class_template_compound_type : Error<
"cannot %select{form pointer to|form reference to|form array of|"
"form function returning|use parentheses when declaring variable with}0 "
"deduced class template specialization type">;
def err_deduced_class_template_not_supported : Error<
"deduction of template arguments for class templates is not yet supported">;
def err_deduced_non_class_template_specialization_type : Error<
"%select{<error>|function template|variable template|alias template|"
"template template parameter|template}0 %1 requires template arguments; "
"argument deduction only allowed for class templates">;
def err_deduced_class_template_ctor_ambiguous : Error<
"ambiguous deduction for template arguments of %0">;
def err_deduced_class_template_ctor_no_viable : Error<
"no viable constructor or deduction guide for deduction of "
"template arguments of %0">;
def err_deduced_class_template_incomplete : Error<
"template %0 has no definition and no %select{|viable }1deduction guides "
"for deduction of template arguments">;
def err_deduced_class_template_deleted : Error<
"class template argument deduction for %0 selected a deleted constructor">;
def err_deduced_class_template_explicit : Error<
"class template argument deduction for %0 selected an explicit "
"%select{constructor|deduction guide}1 for copy-list-initialization">;
def err_deduction_guide_no_trailing_return_type : Error<
"deduction guide declaration without trailing return type">;
def err_deduction_guide_with_complex_decl : Error<

View File

@ -274,15 +274,18 @@ public:
/// \brief Create the initialization entity for a temporary.
static InitializedEntity InitializeTemporary(QualType Type) {
InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
Result.TypeInfo = nullptr;
return Result;
return InitializeTemporary(nullptr, Type);
}
/// \brief Create the initialization entity for a temporary.
static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) {
InitializedEntity Result(EK_Temporary, SourceLocation(),
TypeInfo->getType());
return InitializeTemporary(TypeInfo, TypeInfo->getType());
}
/// \brief Create the initialization entity for a temporary.
static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo,
QualType Type) {
InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
Result.TypeInfo = TypeInfo;
return Result;
}
@ -580,6 +583,16 @@ public:
InitLoc, LParenLoc, RParenLoc);
}
/// \brief Create an initialization from an initializer (which, for direct
/// initialization from a parenthesized list, will be a ParenListExpr).
static InitializationKind CreateForInit(SourceLocation Loc, bool DirectInit,
Expr *Init) {
if (!Init) return CreateDefault(Loc);
if (!DirectInit) return CreateCopy(Loc, Init->getLocStart());
if (isa<InitListExpr>(Init)) return CreateDirectList(Loc);
return CreateDirect(Loc, Init->getLocStart(), Init->getLocEnd());
}
/// \brief Determine the initialization kind.
InitKind getKind() const {
return Kind;

View File

@ -1760,6 +1760,8 @@ public:
// Returns true if the variable declaration is a redeclaration
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckVariableDeclarationType(VarDecl *NewVD);
bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
Expr *Init);
void CheckCompleteVariableDeclaration(VarDecl *VD);
void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
@ -4340,7 +4342,7 @@ public:
/// \brief Determine whether Ctor is an initializer-list constructor, as
/// defined in [dcl.init.list]p2.
bool isInitListConstructor(const CXXConstructorDecl *Ctor);
bool isInitListConstructor(const FunctionDecl *Ctor);
Decl *ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
@ -6767,6 +6769,10 @@ public:
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
QualType DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TInfo, const InitializedEntity &Entity,
const InitializationKind &Kind, MultiExprArg Init);
QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
QualType Type, TypeSourceInfo *TSI,
SourceRange Range, bool DirectInit,
@ -9304,7 +9310,7 @@ public:
ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr,
CastKind &Kind);
ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo,
ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type,
SourceLocation LParenLoc,
Expr *CastExpr,
SourceLocation RParenLoc);

View File

@ -734,23 +734,23 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C,
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
QualType Type,
TypeSourceInfo *TSI,
ArrayRef<Expr*> Args,
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
: CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type,
TSI->getTypeLoc().getBeginLoc(),
Cons, false, Args,
HadMultipleCandidates,
ListInitialization,
StdInitListInitialization,
ZeroInitialization,
CXXConstructExpr::CK_Complete, ParenOrBraceRange),
Type(Type) {
Type(TSI) {
}
SourceLocation CXXTemporaryObjectExpr::getLocStart() const {

View File

@ -2627,11 +2627,12 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
}
ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
QualType Type,
SourceLocation LPLoc,
Expr *CastExpr,
SourceLocation RPLoc) {
assert(LPLoc.isValid() && "List-initialization shouldn't get here.");
CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
CastOperation Op(*this, Type, CastExpr);
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());

View File

@ -9807,16 +9807,33 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
DeducedType *Deduced = Type->getContainedDeducedType();
assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type");
ArrayRef<Expr*> DeduceInits = Init ? ArrayRef<Expr*>(Init) : None;
if (DirectInit) {
if (auto *PL = dyn_cast_or_null<ParenListExpr>(Init))
DeduceInits = PL->exprs();
}
if (isa<DeducedTemplateSpecializationType>(Deduced)) {
Diag(Init->getLocStart(), diag::err_deduced_class_template_not_supported);
assert(VDecl && "non-auto type for init capture deduction?");
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
InitializationKind Kind = InitializationKind::CreateForInit(
VDecl->getLocation(), DirectInit, Init);
// FIXME: Initialization should not be taking a mutable list of inits.
SmallVector<Expr*, 8> InitsCopy(DeduceInits.begin(), DeduceInits.end());
return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind,
InitsCopy);
}
// C++11 [dcl.spec.auto]p3
if (!Init) {
assert(VDecl && "no init for init capture deduction?");
Diag(VDecl->getLocation(), diag::err_auto_var_requires_init)
<< VDecl->getDeclName() << Type;
return QualType();
}
ArrayRef<Expr *> DeduceInits = Init;
if (DirectInit) {
if (auto *PL = dyn_cast<ParenListExpr>(Init))
DeduceInits = PL->exprs();
else if (auto *IL = dyn_cast<InitListExpr>(Init))
if (auto *IL = dyn_cast<InitListExpr>(Init))
DeduceInits = IL->inits();
}
@ -9902,6 +9919,36 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
return DeducedType;
}
bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
Expr *Init) {
QualType DeducedType = deduceVarTypeFromInitializer(
VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(),
VDecl->getSourceRange(), DirectInit, Init);
if (DeducedType.isNull()) {
VDecl->setInvalidDecl();
return true;
}
VDecl->setType(DeducedType);
assert(VDecl->isLinkageValid());
// In ARC, infer lifetime.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl()) {
// We never need to merge the type, because we cannot form an incomplete
// array of auto, nor deduce such a type.
MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false);
}
// Check the deduced type is valid for a variable declaration.
CheckVariableDeclarationType(VDecl);
return VDecl->isInvalidDecl();
}
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
@ -9941,32 +9988,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
}
Init = Res.get();
QualType DeducedType = deduceVarTypeFromInitializer(
VDecl, VDecl->getDeclName(), VDecl->getType(),
VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init);
if (DeducedType.isNull()) {
RealDecl->setInvalidDecl();
return;
}
VDecl->setType(DeducedType);
assert(VDecl->isLinkageValid());
// In ARC, infer lifetime.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl()) {
// We never need to merge the type, because we cannot form an incomplete
// array of auto, nor deduce such a type.
MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false);
}
// Check the deduced type is valid for a variable declaration.
CheckVariableDeclarationType(VDecl);
if (VDecl->isInvalidDecl())
if (DeduceVariableDeclarationType(VDecl, DirectInit, Init))
return;
}
@ -10085,15 +10107,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
}
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
InitializationKind Kind =
DirectInit
? CXXDirectInit
? InitializationKind::CreateDirect(VDecl->getLocation(),
Init->getLocStart(),
Init->getLocEnd())
: InitializationKind::CreateDirectList(VDecl->getLocation())
: InitializationKind::CreateCopy(VDecl->getLocation(),
Init->getLocStart());
InitializationKind Kind = InitializationKind::CreateForInit(
VDecl->getLocation(), DirectInit, Init);
MultiExprArg Args = Init;
if (CXXDirectInit)
@ -10417,13 +10432,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
return;
}
// C++11 [dcl.spec.auto]p3
if (Type->isUndeducedType()) {
Diag(Var->getLocation(), diag::err_auto_var_requires_init)
<< Var->getDeclName() << Type;
Var->setInvalidDecl();
if (Type->isUndeducedType() &&
DeduceVariableDeclarationType(Var, false, nullptr))
return;
}
// C++11 [class.static.data]p3: A static data member can be declared with
// the constexpr specifier; if so, its declaration shall specify

View File

@ -8556,7 +8556,7 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
}
bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) {
bool Sema::isInitListConstructor(const FunctionDecl *Ctor) {
// C++ [dcl.init.list]p2:
// A constructor is an initializer-list constructor if its first parameter
// is of type std::initializer_list<E> or reference to possibly cv-qualified

View File

@ -1266,15 +1266,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
RParenLoc);
}
// C++1z [expr.type.conv]p1:
// If the type is a placeholder for a deduced class type, [...perform class
// template argument deduction...]
DeducedType *Deduced = Ty->getContainedDeducedType();
if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
Diag(TyBeginLoc, diag::err_deduced_class_template_not_supported);
return ExprError();
}
bool ListInitialization = LParenLoc.isInvalid();
assert((!ListInitialization ||
(Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) &&
@ -1282,13 +1273,34 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
SourceRange FullRange = SourceRange(TyBeginLoc,
ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc);
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
InitializationKind Kind =
Exprs.size()
? ListInitialization
? InitializationKind::CreateDirectList(TyBeginLoc)
: InitializationKind::CreateDirect(TyBeginLoc, LParenLoc,
RParenLoc)
: InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc);
// C++1z [expr.type.conv]p1:
// If the type is a placeholder for a deduced class type, [...perform class
// template argument deduction...]
DeducedType *Deduced = Ty->getContainedDeducedType();
if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity,
Kind, Exprs);
if (Ty.isNull())
return ExprError();
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
}
// C++ [expr.type.conv]p1:
// If the expression list is a single expression, the type conversion
// expression is equivalent (in definedness, and if defined in meaning) to the
// corresponding cast expression.
if (Exprs.size() == 1 && !ListInitialization) {
Expr *Arg = Exprs[0];
return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenLoc, Arg, RParenLoc);
}
// C++14 [expr.type.conv]p2: The expression T(), where T is a
@ -1313,12 +1325,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
diag::err_invalid_incomplete_type_use, FullRange))
return ExprError();
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
InitializationKind Kind =
Exprs.size() ? ListInitialization
? InitializationKind::CreateDirectList(TyBeginLoc)
: InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc)
: InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc);
InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs);
@ -1339,7 +1345,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
// is sometimes handled by initialization and sometimes not.
QualType ResultType = Result.get()->getType();
Result = CXXFunctionalCastExpr::Create(
Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo,
Context, ResultType, Expr::getValueKindForType(Ty), TInfo,
CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc);
}
@ -1665,13 +1671,38 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
NumInits = List->getNumExprs();
}
// C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (AllocType->isUndeducedType()) {
if (isa<DeducedTemplateSpecializationType>(
AllocType->getContainedDeducedType()))
return ExprError(Diag(TypeRange.getBegin(),
diag::err_deduced_class_template_not_supported));
// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
InitializationKind Kind
// - If the new-initializer is omitted, the object is default-
// initialized (8.5); if no initialization is performed,
// the object has indeterminate value
= initStyle == CXXNewExpr::NoInit
? InitializationKind::CreateDefault(TypeRange.getBegin())
// - Otherwise, the new-initializer is interpreted according to the
// initialization rules of 8.5 for direct-initialization.
: initStyle == CXXNewExpr::ListInit
? InitializationKind::CreateDirectList(TypeRange.getBegin())
: InitializationKind::CreateDirect(TypeRange.getBegin(),
DirectInitRange.getBegin(),
DirectInitRange.getEnd());
// C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
auto *Deduced = AllocType->getContainedDeducedType();
if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
if (ArraySize)
return ExprError(Diag(ArraySize->getExprLoc(),
diag::err_deduced_class_template_compound_type)
<< /*array*/ 2 << ArraySize->getSourceRange());
InitializedEntity Entity
= InitializedEntity::InitializeNew(StartLoc, AllocType);
AllocType = DeduceTemplateSpecializationFromInitializer(
AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits));
if (AllocType.isNull())
return ExprError();
} else if (Deduced) {
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
@ -1958,23 +1989,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
else
InitType = AllocType;
// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
InitializationKind Kind
// - If the new-initializer is omitted, the object is default-
// initialized (8.5); if no initialization is performed,
// the object has indeterminate value
= initStyle == CXXNewExpr::NoInit
? InitializationKind::CreateDefault(TypeRange.getBegin())
// - Otherwise, the new-initializer is interpreted according to the
// initialization rules of 8.5 for direct-initialization.
: initStyle == CXXNewExpr::ListInit
? InitializationKind::CreateDirectList(TypeRange.getBegin())
: InitializationKind::CreateDirect(TypeRange.getBegin(),
DirectInitRange.getBegin(),
DirectInitRange.getEnd());
InitializedEntity Entity
= InitializedEntity::InitializeNew(StartLoc, InitType);
InitializationSequence InitSeq(*this, Entity, Kind,

View File

@ -5914,7 +5914,8 @@ PerformConstructorInitialization(Sema &S,
S.MarkFunctionReferenced(Loc, Constructor);
CurInit = new (S.Context) CXXTemporaryObjectExpr(
S.Context, Constructor, TSInfo,
S.Context, Constructor,
Entity.getType().getNonLValueExprType(S.Context), TSInfo,
ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
IsListInitialization, IsStdInitListInitialization,
ConstructorInitRequiresZeroInit);
@ -6982,7 +6983,7 @@ InitializationSequence::Perform(Sema &S,
Kind.getRange().getBegin());
CurInit = new (S.Context) CXXScalarValueInitExpr(
TSInfo->getType().getNonLValueExprType(S.Context), TSInfo,
Entity.getType().getNonLValueExprType(S.Context), TSInfo,
Kind.getRange().getEnd());
} else {
CurInit = new (S.Context) ImplicitValueInitExpr(Step->Type);
@ -7755,7 +7756,8 @@ bool InitializationSequence::Diagnose(Sema &S,
(void)Ovl;
assert(Ovl == OR_Success && "Inconsistent overload resolution");
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
S.Diag(CtorDecl->getLocation(), diag::note_constructor_declared_here);
S.Diag(CtorDecl->getLocation(),
diag::note_explicit_ctor_deduction_guide_here) << false;
break;
}
}
@ -8219,3 +8221,215 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
return Result;
}
QualType Sema::DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
const InitializationKind &Kind, MultiExprArg Inits) {
auto *DeducedTST = dyn_cast<DeducedTemplateSpecializationType>(
TSInfo->getType()->getContainedDeducedType());
assert(DeducedTST && "not a deduced template specialization type");
// We can only perform deduction for class templates.
auto TemplateName = DeducedTST->getTemplateName();
auto *Template =
dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
if (!Template) {
Diag(Kind.getLocation(),
diag::err_deduced_non_class_template_specialization_type)
<< (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
if (auto *TD = TemplateName.getAsTemplateDecl())
Diag(TD->getLocation(), diag::note_template_decl_here);
return QualType();
}
// FIXME: Perform "exact type" matching first, per CWG discussion?
// Or implement this via an implied 'T(T) -> T' deduction guide?
// FIXME: Do we need/want a std::initializer_list<T> special case?
// C++1z [over.match.class.deduct]p1:
// A set of functions and function templates is formed comprising:
bool HasDefaultConstructor = false;
SmallVector<DeclAccessPair, 16> CtorsAndGuides;
CXXRecordDecl *Primary = Template->getTemplatedDecl();
bool Complete = isCompleteType(TSInfo->getTypeLoc().getEndLoc(),
Context.getTypeDeclType(Primary));
if (Complete) {
for (NamedDecl *D : LookupConstructors(Template->getTemplatedDecl())) {
// - For each constructor of the class template designated by the
// template-name, a function template [...]
auto Info = getConstructorInfo(D);
if (!Info.Constructor || Info.Constructor->isInvalidDecl())
continue;
// FIXME: Synthesize a deduction guide.
if (Info.Constructor->isDefaultConstructor())
HasDefaultConstructor = true;
}
}
// - For each deduction-guide, a function or function template [...]
DeclarationNameInfo NameInfo(
Context.DeclarationNames.getCXXDeductionGuideName(Template),
TSInfo->getTypeLoc().getEndLoc());
LookupResult Guides(*this, NameInfo, LookupOrdinaryName);
LookupQualifiedName(Guides, Template->getDeclContext());
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
auto *FD = dyn_cast<FunctionDecl>(*I);
if (FD && FD->getMinRequiredArguments() == 0)
HasDefaultConstructor = true;
CtorsAndGuides.push_back(I.getPair());
}
// FIXME: Do not diagnose inaccessible deduction guides. The standard isn't
// clear on this, but they're not found by name so access does not apply.
Guides.suppressDiagnostics();
// Figure out if this is list-initialization.
InitListExpr *ListInit =
(Inits.size() == 1 && Kind.getKind() != InitializationKind::IK_Direct)
? dyn_cast<InitListExpr>(Inits[0])
: nullptr;
// C++1z [over.match.class.deduct]p1:
// Initialization and overload resolution are performed as described in
// [dcl.init] and [over.match.ctor], [over.match.copy], or [over.match.list]
// (as appropriate for the type of initialization performed) for an object
// of a hypothetical class type, where the selected functions and function
// templates are considered to be the constructors of that class type
//
// Since we know we're initializing a class type of a type unrelated to that
// of the initializer, this reduces to something fairly reasonable.
OverloadCandidateSet Candidates(Kind.getLocation(),
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
auto tryToResolveOverload =
[&](bool OnlyListConstructors) -> OverloadingResult {
Candidates.clear();
for (DeclAccessPair Pair : CtorsAndGuides) {
NamedDecl *D = Pair.getDecl()->getUnderlyingDecl();
if (D->isInvalidDecl())
continue;
FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(D);
FunctionDecl *FD =
TD ? TD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D);
if (!FD)
continue;
// C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
// For copy-initialization, the candidate functions are all the
// converting constructors (12.3.1) of that class.
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
// The converting constructors of T are candidate functions.
if (Kind.isCopyInit() && !ListInit) {
// FIXME: if (FD->isExplicit()) continue;
// When looking for a converting constructor, deduction guides that
// could never be called with one argument are not interesting.
if (FD->getMinRequiredArguments() > 1 ||
(FD->getNumParams() == 0 && !FD->isVariadic()))
continue;
}
// C++ [over.match.list]p1.1: (first phase list initialization)
// Initially, the candidate functions are the initializer-list
// constructors of the class T
if (OnlyListConstructors && !isInitListConstructor(FD))
continue;
// C++ [over.match.list]p1.2: (second phase list initialization)
// the candidate functions are all the constructors of the class T
// C++ [over.match.ctor]p1: (all other cases)
// the candidate functions are all the constructors of the class of
// the object being initialized
// C++ [over.best.ics]p4:
// When [...] the constructor [...] is a candidate by
// - [over.match.copy] (in all cases)
// FIXME: The "second phase of [over.match.list] case can also
// theoretically happen here, but it's not clear whether we can
// ever have a parameter of the right type.
bool SuppressUserConversions = Kind.isCopyInit();
// FIXME: These are definitely wrong in the non-deduction-guide case.
if (TD)
AddTemplateOverloadCandidate(TD, Pair, /*ExplicitArgs*/ nullptr, Inits,
Candidates, SuppressUserConversions);
else
AddOverloadCandidate(FD, Pair, Inits, Candidates,
SuppressUserConversions);
}
return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
};
OverloadingResult Result = OR_No_Viable_Function;
// C++11 [over.match.list]p1, per DR1467: for list-initialization, first
// try initializer-list constructors.
if (ListInit) {
if (ListInit->getNumInits() || !HasDefaultConstructor)
Result = tryToResolveOverload(/*OnlyListConstructor*/true);
// Then unwrap the initializer list and try again considering all
// constructors.
Inits = MultiExprArg(ListInit->getInits(), ListInit->getNumInits());
}
// If list-initialization fails, or if we're doing any other kind of
// initialization, we (eventually) consider constructors.
if (Result == OR_No_Viable_Function)
Result = tryToResolveOverload(/*OnlyListConstructor*/false);
switch (Result) {
case OR_Ambiguous:
Diag(Kind.getLocation(), diag::err_deduced_class_template_ctor_ambiguous)
<< TemplateName;
// FIXME: For list-initialization candidates, it'd usually be better to
// list why they were not viable when given the initializer list itself as
// an argument.
Candidates.NoteCandidates(*this, OCD_ViableCandidates, Inits);
return QualType();
case OR_No_Viable_Function:
Diag(Kind.getLocation(),
Complete ? diag::err_deduced_class_template_ctor_no_viable
: diag::err_deduced_class_template_incomplete)
<< TemplateName << !CtorsAndGuides.empty();
Candidates.NoteCandidates(*this, OCD_AllCandidates, Inits);
return QualType();
case OR_Deleted: {
Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted)
<< TemplateName;
NoteDeletedFunction(Best->Function);
return QualType();
}
case OR_Success:
// C++ [over.match.list]p1:
// In copy-list-initialization, if an explicit constructor is chosen, the
// initialization is ill-formed.
if (Kind.isCopyInit() && ListInit &&
false /*FIXME: Best->Function->isExplicit()*/) {
bool IsDeductionGuide = !Best->Function->isImplicit();
Diag(Kind.getLocation(), diag::err_deduced_class_template_explicit)
<< TemplateName << IsDeductionGuide;
Diag(Best->Function->getLocation(),
diag::note_explicit_ctor_deduction_guide_here)
<< IsDeductionGuide;
return QualType();
}
// Make sure we didn't select an unusable deduction guide, and mark it
// as referenced.
DiagnoseUseOfDecl(Best->Function, Kind.getLocation());
MarkFunctionReferenced(Kind.getLocation(), Best->Function);
break;
}
// C++ [dcl.type.class.deduct]p1:
// The placeholder is replaced by the return type of the function selected
// by overload resolution for class template deduction.
return SubstAutoType(TSInfo->getType(), Best->Function->getReturnType());
}

View File

@ -4019,17 +4019,26 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
namespace {
/// Substitute the 'auto' type specifier within a type for a given replacement
/// type.
class SubstituteAutoTransform :
public TreeTransform<SubstituteAutoTransform> {
/// Substitute the 'auto' specifier or deduced template specialization type
/// specifier within a type for a given replacement type.
class SubstituteDeducedTypeTransform :
public TreeTransform<SubstituteDeducedTypeTransform> {
QualType Replacement;
bool UseAutoSugar;
bool UseTypeSugar;
public:
SubstituteAutoTransform(Sema &SemaRef, QualType Replacement,
bool UseAutoSugar = true)
: TreeTransform<SubstituteAutoTransform>(SemaRef),
Replacement(Replacement), UseAutoSugar(UseAutoSugar) {}
SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
bool UseTypeSugar = true)
: TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
Replacement(Replacement), UseTypeSugar(UseTypeSugar) {}
QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) {
assert(isa<TemplateTypeParmType>(Replacement) &&
"unexpected unsugared replacement kind");
QualType Result = Replacement;
TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) {
// If we're building the type pattern to deduce against, don't wrap the
@ -4039,21 +4048,29 @@ namespace {
// auto &&lref = lvalue;
// must transform into "rvalue reference to T" not "rvalue reference to
// auto type deduced as T" in order for [temp.deduct.call]p3 to apply.
if (!UseAutoSugar) {
assert(isa<TemplateTypeParmType>(Replacement) &&
"unexpected unsugared replacement kind");
QualType Result = Replacement;
TemplateTypeParmTypeLoc NewTL =
TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
} else {
//
// FIXME: Is this still necessary?
if (!UseTypeSugar)
return TransformDesugared(TLB, TL);
QualType Result = SemaRef.Context.getAutoType(
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
auto NewTL = TLB.push<AutoTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
QualType TransformDeducedTemplateSpecializationType(
TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
if (!UseTypeSugar)
return TransformDesugared(TLB, TL);
QualType Result = SemaRef.Context.getDeducedTemplateSpecializationType(
TL.getTypePtr()->getTemplateName(),
Replacement, Replacement.isNull());
auto NewTL = TLB.push<DeducedTemplateSpecializationTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
ExprResult TransformLambdaExpr(LambdaExpr *E) {
@ -4104,7 +4121,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (!DependentDeductionDepth &&
(Type.getType()->isDependentType() || Init->isTypeDependent())) {
Result = SubstituteAutoTransform(*this, QualType()).Apply(Type);
Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
@ -4127,7 +4144,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
// FIXME: Support a non-canonical deduced type for 'auto'.
Deduced = Context.getCanonicalType(Deduced);
Result = SubstituteAutoTransform(*this, Deduced).Apply(Type);
Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
return DAR_Succeeded;
@ -4152,7 +4169,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
Loc, Loc, TemplParamPtr, Loc, nullptr);
QualType FuncParam =
SubstituteAutoTransform(*this, TemplArg, /*UseAutoSugar*/false)
SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
.Apply(Type);
assert(!FuncParam.isNull() &&
"substituting template parameter for 'auto' failed");
@ -4167,7 +4184,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// might acquire a matching type in the instantiation.
auto DeductionFailed = [&]() -> DeduceAutoResult {
if (Init->isTypeDependent()) {
Result = SubstituteAutoTransform(*this, QualType()).Apply(Type);
Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
@ -4215,7 +4232,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type);
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
@ -4238,7 +4255,7 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
if (TypeToReplaceAuto->isDependentType())
TypeToReplaceAuto = QualType();
return SubstituteAutoTransform(*this, TypeToReplaceAuto)
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
@ -4246,14 +4263,14 @@ TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType TypeToReplaceAuto) {
if (TypeToReplaceAuto->isDependentType())
TypeToReplaceAuto = QualType();
return SubstituteAutoTransform(*this, TypeToReplaceAuto)
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
return SubstituteAutoTransform(*this, TypeToReplaceAuto,
/*UseAutoSugar*/ false)
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto,
/*UseTypeSugar*/ false)
.TransformType(TypeWithAuto);
}

View File

@ -0,0 +1,10 @@
// RUN: %clang_cc1 -std=c++1z -verify %s
template<typename T> struct A {
T t, u;
};
template<typename T> A(T, T) -> A<T>; // expected-note {{deduced conflicting types for parameter 'T'}}
template<typename T> A(A<T>) -> A<T>; // expected-note {{requires 1 argument, but 2 were provided}}
A a = A{1, 2};
A b = A{3, 4.0}; // expected-error {{no viable constructor or deduction guide}}

View File

@ -0,0 +1,43 @@
// RUN: %clang_cc1 -std=c++1z -verify %s
namespace std_example {
template <class T> struct A { // expected-note 2{{candidate}}
// FIXME: This is a bad way to diagnose redeclaration of a class member!
explicit A(const T &, ...) noexcept; // expected-note {{previous}} expected-note {{candidate}}
A(T &&, ...); // expected-error {{missing exception specification 'noexcept'}}
};
int i;
// FIXME: All but the first should be valid once we synthesize deduction guides from constructors.
A a1 = {i, i}; // expected-error {{no viable constructor or deduction guide}}
A a2{i, i}; // expected-error {{no viable constructor or deduction guide}}
A a3{0, i}; // expected-error {{no viable constructor or deduction guide}}
A a4 = {0, i}; // expected-error {{no viable constructor or deduction guide}}
template <class T> A(const T &, const T &) -> A<T &>;
template <class T> explicit A(T &&, T &&) -> A<T>;
A a5 = {0, 1}; // FIXME: Should be invalid, explicit deduction guide selected in copy-list-init
A a6{0, 1};
A a7 = {0, i}; // expected-note {{in instantiation of}}
A a8{0, i}; // expected-error {{no matching constructor}}
template <class T> struct B {
template <class U> using TA = T;
template <class U> B(U, TA<U>);
};
// FIXME: This is valid.
B b{(int *)0, (char *)0}; // expected-error {{no viable constructor or deduction guide}}
}
namespace check {
using namespace std_example;
template<typename T, typename U> constexpr bool same = false;
template<typename T> constexpr bool same<T, T> = true;
static_assert(same<decltype(a2), A<int>>);
static_assert(same<decltype(a3), A<int>>);
static_assert(same<decltype(a4), A<int>>);
static_assert(same<decltype(a6), A<int>>);
static_assert(same<decltype(b), A<char*>>);
}

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++1z -verify %s
// expected-no-diagnostics
namespace std_example {
template<typename T, typename U = int> struct S {
@ -10,5 +11,5 @@ namespace std_example {
using type = short;
operator type();
};
S x{A()}; // expected-error {{not yet supported}}
S x{A()};
}

View File

@ -1,6 +1,12 @@
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
template<typename T> struct A {}; // expected-note 35{{declared here}}
template <typename T> struct A { // expected-note 35{{declared here}}
constexpr A() {}
constexpr A(int) {}
constexpr operator int() { return 0; }
};
A() -> A<int>;
A(int) -> A<int>;
// Make sure we still correctly parse cases where a template can appear without arguments.
namespace template_template_arg {
@ -18,7 +24,7 @@ namespace template_template_arg {
template<typename = ::A> struct YCCD {}; // expected-error {{requires template arguments}}
// FIXME: replacing the invalid type with 'int' here is horrible
template <A a = A<int>()> class C { }; // expected-error {{requires template arguments}} expected-error {{not implicitly convertible to 'int'}}
template <A a = A<int>()> class C { }; // expected-error {{requires template arguments}}
template<typename T = A> struct G { }; // expected-error {{requires template arguments}}
}
@ -27,7 +33,7 @@ namespace injected_class_name {
A(T);
void f(int) {
A a = 1;
injected_class_name::A b = 1; // expected-error {{not yet supported}}
injected_class_name::A b = 1; // expected-error {{no viable constructor or deduction guide}}
}
void f(T);
};
@ -46,8 +52,8 @@ struct member {
operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}}
static A x; // expected-error {{requires an initializer}}
static A y = 0; // expected-error {{not yet supported}}
static A x; // FIXME: We deduce A<int> from the initializer despite this not being a definition!
static constexpr A y = 0;
};
namespace in_typedef {
@ -67,18 +73,18 @@ namespace stmt {
// simple-declaration or cast. We also permit it in conditions,
// for-range-declarations, member-declarations for static data members, and
// new-expressions, because not doing so would be bizarre.
A local = 0; // expected-error {{not yet supported}}
static A local_static = 0; // expected-error {{not yet supported}}
static thread_local A thread_local_static = 0; // expected-error {{not yet supported}}
if (A a = 0) {} // expected-error {{not yet supported}}
if (A a = 0; a) {} // expected-error {{not yet supported}}
switch (A a = 0) {} // expected-error {{not yet supported}}
switch (A a = 0; a) {} // expected-error {{not yet supported}}
for (A a = 0; a; /**/) {} // expected-error {{not yet supported}}
for (/**/; A a = 0; /**/) {} // expected-error {{not yet supported}}
while (A a = 0) {} // expected-error {{not yet supported}}
A local = 0;
static A local_static = 0;
static thread_local A thread_local_static = 0;
if (A a = 0) {}
if (A a = 0; a) {}
switch (A a = 0) {} // expected-warning {{no case matching constant switch condition '0'}}
switch (A a = 0; a) {} // expected-warning {{no case matching constant switch condition '0'}}
for (A a = 0; a; /**/) {}
for (/**/; A a = 0; /**/) {}
while (A a = 0) {}
int arr[3];
for (A a : arr) {} // expected-error {{not yet supported}}
for (A a : arr) {}
}
namespace std {
@ -104,12 +110,12 @@ namespace expr {
(void)(A)(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
(void)(A){n}; // expected-error{{requires template arguments; argument deduction not allowed here}}
(void)A(n); // expected-error {{not yet supported}}
(void)A{n}; // expected-error {{not yet supported}}
(void)new A(n); // expected-error {{not yet supported}}
(void)new A{n}; // expected-error {{not yet supported}}
(void)A(n);
(void)A{n};
(void)new A(n);
(void)new A{n};
// FIXME: We should diagnose the lack of an initializer here.
(void)new A; // expected-error {{not yet supported}}
(void)new A;
}
}
@ -121,55 +127,57 @@ namespace decl {
auto k() -> A; // expected-error{{requires template arguments}}
A a; // expected-error {{requires an initializer}}
A b = 0; // expected-error {{not yet supported}}
const A c = 0; // expected-error {{not yet supported}}
A a; // FIXME: This is (technically) syntactically invalid.
A b = 0;
const A c = 0;
A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
A [x, y] = 0; // expected-error {{cannot be declared with type 'A'}} expected-error {{not yet supported}}
A [x, y] = 0; // expected-error {{cannot be declared with type 'A'}} expected-error {{type 'A<int>' decomposes into 0 elements, but 2 names were provided}}
}
namespace typename_specifier {
struct F {};
void e() {
(void) typename ::A(0); // expected-error {{not yet supported}}
(void) typename ::A{0}; // expected-error {{not yet supported}}
new typename ::A(0); // expected-error {{not yet supported}}
new typename ::A{0}; // expected-error {{not yet supported}}
typename ::A a = 0; // expected-error {{not yet supported}}
const typename ::A b = 0; // expected-error {{not yet supported}}
if (typename ::A a = 0) {} // expected-error {{not yet supported}}
for (typename ::A a = 0; typename ::A b = 0; /**/) {} // expected-error 2{{not yet supported}}
(void) typename ::A(0);
(void) typename ::A{0};
new typename ::A(0);
new typename ::A{0};
typename ::A a = 0;
const typename ::A b = 0;
if (typename ::A a = 0) {}
for (typename ::A a = 0; typename ::A b = 0; /**/) {}
(void)(typename ::A)(0); // expected-error{{requires template arguments; argument deduction not allowed here}}
(void)(typename ::A){0}; // expected-error{{requires template arguments; argument deduction not allowed here}}
}
typename ::A a = 0; // expected-error {{not yet supported}}
const typename ::A b = 0; // expected-error {{not yet supported}}
typename ::A a = 0;
const typename ::A b = 0;
typename ::A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
typename ::A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
typename ::A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
typename ::A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
typename ::A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
typename ::A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
typename ::A [x, y] = 0; // expected-error {{cannot be declared with type 'typename ::A'}} expected-error {{not yet supported}}
typename ::A [x, y] = 0; // expected-error {{cannot be declared with type 'typename ::A'}} expected-error {{type 'typename ::A<int>' (aka 'A<int>') decomposes into 0}}
struct X { template<typename T> struct A {}; }; // expected-note 8{{template}}
// FIXME: We do not yet properly support class template argument deduction
// during template instantiation.
template<typename T> void f() {
(void) typename T::A(0); // expected-error {{not yet supported}}
(void) typename T::A{0}; // expected-error {{not yet supported}}
new typename T::A(0); // expected-error {{not yet supported}}
new typename T::A{0}; // expected-error {{not yet supported}}
typename T::A a = 0; // expected-error {{not yet supported}}
const typename T::A b = 0; // expected-error {{not yet supported}}
if (typename T::A a = 0) {} // expected-error {{not yet supported}}
for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error 2{{not yet supported}}
(void) typename T::A(0); // expected-error {{no viable}}
(void) typename T::A{0}; // expected-error {{no viable}}
new typename T::A(0); // expected-error {{no viable}}
new typename T::A{0}; // expected-error {{no viable}}
typename T::A a = 0; // expected-error {{no viable}}
const typename T::A b = 0; // expected-error {{no viable}}
if (typename T::A a = 0) {} // expected-error {{no viable}}
for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error 2{{no viable}}
{(void)(typename T::A)(0);} // expected-error{{refers to class template member}}
{(void)(typename T::A){0};} // expected-error{{refers to class template member}}
@ -179,7 +187,7 @@ namespace typename_specifier {
{typename T::A arr[3] = 0;} // expected-error {{refers to class template member}}
{typename T::A F::*pm = 0;} // expected-error {{refers to class template member}}
{typename T::A (*fp)() = 0;} // expected-error {{refers to class template member}}
{typename T::A [x, y] = 0;} // expected-error {{cannot be declared with type 'typename T::A'}} expected-error {{not yet supported}}
{typename T::A [x, y] = 0;} // expected-error {{cannot be declared with type 'typename T::A'}} expected-error {{no viable}}
}
template void f<X>(); // expected-note {{instantiation of}}

View File

@ -0,0 +1,84 @@
// RUN: %clang_cc1 -std=c++1z -verify %s
namespace std {
using size_t = decltype(sizeof(0));
template<typename T> struct initializer_list {
const T *p;
size_t n;
initializer_list();
};
// FIXME: This should probably not be necessary.
template<typename T> initializer_list(initializer_list<T>) -> initializer_list<T>;
}
template<typename T> constexpr bool has_type(...) { return false; }
template<typename T> constexpr bool has_type(T) { return true; }
std::initializer_list il = {1, 2, 3, 4, 5};
template<typename T> struct vector {
template<typename Iter> vector(Iter, Iter);
vector(std::initializer_list<T>);
};
template<typename T> vector(std::initializer_list<T>) -> vector<T>;
template<typename Iter> explicit vector(Iter, Iter) -> vector<typename Iter::value_type>;
template<typename T> explicit vector(std::size_t, T) -> vector<T>;
vector v1 = {1, 2, 3, 4};
static_assert(has_type<vector<int>>(v1));
struct iter { typedef char value_type; } it, end;
vector v2(it, end);
static_assert(has_type<vector<char>>(v2));
vector v3(5, 5);
static_assert(has_type<vector<int>>(v3));
template<typename ...T> struct tuple { tuple(T...); };
template<typename ...T> explicit tuple(T ...t) -> tuple<T...>;
// FIXME: Remove
template<typename ...T> tuple(tuple<T...>) -> tuple<T...>;
const int n = 4;
tuple ta = tuple{1, 'a', "foo", n};
static_assert(has_type<tuple<int, char, const char*, int>>(ta));
tuple tb{ta};
static_assert(has_type<tuple<int, char, const char*, int>>(ta));
// FIXME: This should be tuple<tuple<...>>;
tuple tc = {ta};
static_assert(has_type<tuple<int, char, const char*, int>>(ta));
tuple td = {1, 2, 3};
static_assert(has_type<tuple<int, char, const char*, int>>(ta));
// FIXME: This is a GCC extension for now; if CWG don't allow this, at least
// add a warning for it.
namespace new_expr {
tuple<int> *p = new tuple{0};
tuple<float, float> *q = new tuple(1.0f, 2.0f);
}
namespace ambiguity {
template<typename T> struct A {};
A(unsigned short) -> A<int>; // expected-note {{candidate}}
A(short) -> A<int>; // expected-note {{candidate}}
A a = 0; // expected-error {{ambiguous deduction for template arguments of 'A'}}
template<typename T> struct B {};
template<typename T> B(T(&)(int)) -> B<int>; // expected-note {{candidate function [with T = int]}}
template<typename T> B(int(&)(T)) -> B<int>; // expected-note {{candidate function [with T = int]}}
int f(int);
B b = f; // expected-error {{ambiguous deduction for template arguments of 'B'}}
}
// FIXME: Revisit this once CWG decides if attributes, and [[deprecated]] in
// particular, should be permitted here.
namespace deprecated {
template<typename T> struct A { A(int); };
[[deprecated]] A(int) -> A<void>; // expected-note {{marked deprecated here}}
A a = 0; // expected-warning {{'<deduction guide for A>' is deprecated}}
}