forked from OSchip/llvm-project
[c++1z] P0091R3: Basic support for deducing class template arguments via deduction-guides.
llvm-svn: 294613
This commit is contained in:
parent
a18ef6f1f9
commit
60437620db
|
@ -1470,7 +1470,8 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
|
||||||
public:
|
public:
|
||||||
CXXTemporaryObjectExpr(const ASTContext &C,
|
CXXTemporaryObjectExpr(const ASTContext &C,
|
||||||
CXXConstructorDecl *Cons,
|
CXXConstructorDecl *Cons,
|
||||||
TypeSourceInfo *Type,
|
QualType Type,
|
||||||
|
TypeSourceInfo *TSI,
|
||||||
ArrayRef<Expr *> Args,
|
ArrayRef<Expr *> Args,
|
||||||
SourceRange ParenOrBraceRange,
|
SourceRange ParenOrBraceRange,
|
||||||
bool HadMultipleCandidates,
|
bool HadMultipleCandidates,
|
||||||
|
|
|
@ -4115,7 +4115,10 @@ class DeducedType : public Type {
|
||||||
protected:
|
protected:
|
||||||
DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent,
|
DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent,
|
||||||
bool IsInstantiationDependent, bool ContainsParameterPack)
|
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,
|
IsDependent, IsInstantiationDependent,
|
||||||
/*VariablyModified=*/false, ContainsParameterPack) {
|
/*VariablyModified=*/false, ContainsParameterPack) {
|
||||||
if (!DeducedAsType.isNull()) {
|
if (!DeducedAsType.isNull()) {
|
||||||
|
|
|
@ -1849,8 +1849,8 @@ def warn_cxx98_compat_temp_copy : Warning<
|
||||||
InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore;
|
InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore;
|
||||||
def err_selected_explicit_constructor : Error<
|
def err_selected_explicit_constructor : Error<
|
||||||
"chosen constructor is explicit in copy-initialization">;
|
"chosen constructor is explicit in copy-initialization">;
|
||||||
def note_constructor_declared_here : Note<
|
def note_explicit_ctor_deduction_guide_here : Note<
|
||||||
"constructor declared here">;
|
"explicit %select{constructor|deduction guide}0 declared here">;
|
||||||
|
|
||||||
// C++11 decltype
|
// C++11 decltype
|
||||||
def err_decltype_in_declarator : Error<
|
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|"
|
"cannot %select{form pointer to|form reference to|form array of|"
|
||||||
"form function returning|use parentheses when declaring variable with}0 "
|
"form function returning|use parentheses when declaring variable with}0 "
|
||||||
"deduced class template specialization type">;
|
"deduced class template specialization type">;
|
||||||
def err_deduced_class_template_not_supported : Error<
|
def err_deduced_non_class_template_specialization_type : Error<
|
||||||
"deduction of template arguments for class templates is not yet supported">;
|
"%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<
|
def err_deduction_guide_no_trailing_return_type : Error<
|
||||||
"deduction guide declaration without trailing return type">;
|
"deduction guide declaration without trailing return type">;
|
||||||
def err_deduction_guide_with_complex_decl : Error<
|
def err_deduction_guide_with_complex_decl : Error<
|
||||||
|
|
|
@ -274,15 +274,18 @@ public:
|
||||||
|
|
||||||
/// \brief Create the initialization entity for a temporary.
|
/// \brief Create the initialization entity for a temporary.
|
||||||
static InitializedEntity InitializeTemporary(QualType Type) {
|
static InitializedEntity InitializeTemporary(QualType Type) {
|
||||||
InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
|
return InitializeTemporary(nullptr, Type);
|
||||||
Result.TypeInfo = nullptr;
|
|
||||||
return Result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Create the initialization entity for a temporary.
|
/// \brief Create the initialization entity for a temporary.
|
||||||
static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) {
|
static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) {
|
||||||
InitializedEntity Result(EK_Temporary, SourceLocation(),
|
return InitializeTemporary(TypeInfo, TypeInfo->getType());
|
||||||
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;
|
Result.TypeInfo = TypeInfo;
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -579,6 +582,16 @@ public:
|
||||||
return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal,
|
return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal,
|
||||||
InitLoc, LParenLoc, RParenLoc);
|
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.
|
/// \brief Determine the initialization kind.
|
||||||
InitKind getKind() const {
|
InitKind getKind() const {
|
||||||
|
|
|
@ -1760,6 +1760,8 @@ public:
|
||||||
// Returns true if the variable declaration is a redeclaration
|
// Returns true if the variable declaration is a redeclaration
|
||||||
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
|
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
|
||||||
void CheckVariableDeclarationType(VarDecl *NewVD);
|
void CheckVariableDeclarationType(VarDecl *NewVD);
|
||||||
|
bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
|
||||||
|
Expr *Init);
|
||||||
void CheckCompleteVariableDeclaration(VarDecl *VD);
|
void CheckCompleteVariableDeclaration(VarDecl *VD);
|
||||||
void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
|
void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
|
||||||
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
|
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
|
||||||
|
@ -4340,7 +4342,7 @@ public:
|
||||||
|
|
||||||
/// \brief Determine whether Ctor is an initializer-list constructor, as
|
/// \brief Determine whether Ctor is an initializer-list constructor, as
|
||||||
/// defined in [dcl.init.list]p2.
|
/// defined in [dcl.init.list]p2.
|
||||||
bool isInitListConstructor(const CXXConstructorDecl *Ctor);
|
bool isInitListConstructor(const FunctionDecl *Ctor);
|
||||||
|
|
||||||
Decl *ActOnUsingDirective(Scope *CurScope,
|
Decl *ActOnUsingDirective(Scope *CurScope,
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
|
@ -6767,6 +6769,10 @@ public:
|
||||||
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
|
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
|
||||||
bool Diagnose = true);
|
bool Diagnose = true);
|
||||||
|
|
||||||
|
QualType DeduceTemplateSpecializationFromInitializer(
|
||||||
|
TypeSourceInfo *TInfo, const InitializedEntity &Entity,
|
||||||
|
const InitializationKind &Kind, MultiExprArg Init);
|
||||||
|
|
||||||
QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
|
QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
|
||||||
QualType Type, TypeSourceInfo *TSI,
|
QualType Type, TypeSourceInfo *TSI,
|
||||||
SourceRange Range, bool DirectInit,
|
SourceRange Range, bool DirectInit,
|
||||||
|
@ -9304,7 +9310,7 @@ public:
|
||||||
ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr,
|
ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr,
|
||||||
CastKind &Kind);
|
CastKind &Kind);
|
||||||
|
|
||||||
ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo,
|
ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type,
|
||||||
SourceLocation LParenLoc,
|
SourceLocation LParenLoc,
|
||||||
Expr *CastExpr,
|
Expr *CastExpr,
|
||||||
SourceLocation RParenLoc);
|
SourceLocation RParenLoc);
|
||||||
|
|
|
@ -734,23 +734,23 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C,
|
||||||
|
|
||||||
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
|
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
|
||||||
CXXConstructorDecl *Cons,
|
CXXConstructorDecl *Cons,
|
||||||
TypeSourceInfo *Type,
|
QualType Type,
|
||||||
|
TypeSourceInfo *TSI,
|
||||||
ArrayRef<Expr*> Args,
|
ArrayRef<Expr*> Args,
|
||||||
SourceRange ParenOrBraceRange,
|
SourceRange ParenOrBraceRange,
|
||||||
bool HadMultipleCandidates,
|
bool HadMultipleCandidates,
|
||||||
bool ListInitialization,
|
bool ListInitialization,
|
||||||
bool StdInitListInitialization,
|
bool StdInitListInitialization,
|
||||||
bool ZeroInitialization)
|
bool ZeroInitialization)
|
||||||
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
|
: CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type,
|
||||||
Type->getType().getNonReferenceType(),
|
TSI->getTypeLoc().getBeginLoc(),
|
||||||
Type->getTypeLoc().getBeginLoc(),
|
|
||||||
Cons, false, Args,
|
Cons, false, Args,
|
||||||
HadMultipleCandidates,
|
HadMultipleCandidates,
|
||||||
ListInitialization,
|
ListInitialization,
|
||||||
StdInitListInitialization,
|
StdInitListInitialization,
|
||||||
ZeroInitialization,
|
ZeroInitialization,
|
||||||
CXXConstructExpr::CK_Complete, ParenOrBraceRange),
|
CXXConstructExpr::CK_Complete, ParenOrBraceRange),
|
||||||
Type(Type) {
|
Type(TSI) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
|
SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
|
||||||
|
|
|
@ -2627,11 +2627,12 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
|
ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
|
||||||
|
QualType Type,
|
||||||
SourceLocation LPLoc,
|
SourceLocation LPLoc,
|
||||||
Expr *CastExpr,
|
Expr *CastExpr,
|
||||||
SourceLocation RPLoc) {
|
SourceLocation RPLoc) {
|
||||||
assert(LPLoc.isValid() && "List-initialization shouldn't get here.");
|
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.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
|
||||||
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
|
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
|
||||||
|
|
||||||
|
|
|
@ -9807,16 +9807,33 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
|
||||||
DeducedType *Deduced = Type->getContainedDeducedType();
|
DeducedType *Deduced = Type->getContainedDeducedType();
|
||||||
assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type");
|
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)) {
|
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();
|
return QualType();
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayRef<Expr *> DeduceInits = Init;
|
|
||||||
if (DirectInit) {
|
if (DirectInit) {
|
||||||
if (auto *PL = dyn_cast<ParenListExpr>(Init))
|
if (auto *IL = dyn_cast<InitListExpr>(Init))
|
||||||
DeduceInits = PL->exprs();
|
|
||||||
else if (auto *IL = dyn_cast<InitListExpr>(Init))
|
|
||||||
DeduceInits = IL->inits();
|
DeduceInits = IL->inits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9902,6 +9919,36 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
|
||||||
return DeducedType;
|
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
|
/// AddInitializerToDecl - Adds the initializer Init to the
|
||||||
/// declaration dcl. If DirectInit is true, this is C++ direct
|
/// declaration dcl. If DirectInit is true, this is C++ direct
|
||||||
/// initialization rather than copy initialization.
|
/// initialization rather than copy initialization.
|
||||||
|
@ -9941,32 +9988,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||||
}
|
}
|
||||||
Init = Res.get();
|
Init = Res.get();
|
||||||
|
|
||||||
QualType DeducedType = deduceVarTypeFromInitializer(
|
if (DeduceVariableDeclarationType(VDecl, DirectInit, Init))
|
||||||
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())
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10085,15 +10107,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
|
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
|
||||||
InitializationKind Kind =
|
InitializationKind Kind = InitializationKind::CreateForInit(
|
||||||
DirectInit
|
VDecl->getLocation(), DirectInit, Init);
|
||||||
? CXXDirectInit
|
|
||||||
? InitializationKind::CreateDirect(VDecl->getLocation(),
|
|
||||||
Init->getLocStart(),
|
|
||||||
Init->getLocEnd())
|
|
||||||
: InitializationKind::CreateDirectList(VDecl->getLocation())
|
|
||||||
: InitializationKind::CreateCopy(VDecl->getLocation(),
|
|
||||||
Init->getLocStart());
|
|
||||||
|
|
||||||
MultiExprArg Args = Init;
|
MultiExprArg Args = Init;
|
||||||
if (CXXDirectInit)
|
if (CXXDirectInit)
|
||||||
|
@ -10417,13 +10432,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++11 [dcl.spec.auto]p3
|
if (Type->isUndeducedType() &&
|
||||||
if (Type->isUndeducedType()) {
|
DeduceVariableDeclarationType(Var, false, nullptr))
|
||||||
Diag(Var->getLocation(), diag::err_auto_var_requires_init)
|
|
||||||
<< Var->getDeclName() << Type;
|
|
||||||
Var->setInvalidDecl();
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// C++11 [class.static.data]p3: A static data member can be declared with
|
// C++11 [class.static.data]p3: A static data member can be declared with
|
||||||
// the constexpr specifier; if so, its declaration shall specify
|
// the constexpr specifier; if so, its declaration shall specify
|
||||||
|
|
|
@ -8556,7 +8556,7 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
|
||||||
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
|
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) {
|
bool Sema::isInitListConstructor(const FunctionDecl *Ctor) {
|
||||||
// C++ [dcl.init.list]p2:
|
// C++ [dcl.init.list]p2:
|
||||||
// A constructor is an initializer-list constructor if its first parameter
|
// A constructor is an initializer-list constructor if its first parameter
|
||||||
// is of type std::initializer_list<E> or reference to possibly cv-qualified
|
// is of type std::initializer_list<E> or reference to possibly cv-qualified
|
||||||
|
|
|
@ -1266,15 +1266,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
|
||||||
RParenLoc);
|
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();
|
bool ListInitialization = LParenLoc.isInvalid();
|
||||||
assert((!ListInitialization ||
|
assert((!ListInitialization ||
|
||||||
(Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) &&
|
(Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) &&
|
||||||
|
@ -1282,13 +1273,34 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
|
||||||
SourceRange FullRange = SourceRange(TyBeginLoc,
|
SourceRange FullRange = SourceRange(TyBeginLoc,
|
||||||
ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc);
|
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:
|
// C++ [expr.type.conv]p1:
|
||||||
// If the expression list is a single expression, the type conversion
|
// If the expression list is a single expression, the type conversion
|
||||||
// expression is equivalent (in definedness, and if defined in meaning) to the
|
// expression is equivalent (in definedness, and if defined in meaning) to the
|
||||||
// corresponding cast expression.
|
// corresponding cast expression.
|
||||||
if (Exprs.size() == 1 && !ListInitialization) {
|
if (Exprs.size() == 1 && !ListInitialization) {
|
||||||
Expr *Arg = Exprs[0];
|
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
|
// 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))
|
diag::err_invalid_incomplete_type_use, FullRange))
|
||||||
return ExprError();
|
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);
|
InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
|
||||||
ExprResult Result = InitSeq.Perform(*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.
|
// is sometimes handled by initialization and sometimes not.
|
||||||
QualType ResultType = Result.get()->getType();
|
QualType ResultType = Result.get()->getType();
|
||||||
Result = CXXFunctionalCastExpr::Create(
|
Result = CXXFunctionalCastExpr::Create(
|
||||||
Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo,
|
Context, ResultType, Expr::getValueKindForType(Ty), TInfo,
|
||||||
CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc);
|
CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1665,13 +1671,38 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
||||||
NumInits = List->getNumExprs();
|
NumInits = List->getNumExprs();
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
// C++11 [expr.new]p15:
|
||||||
if (AllocType->isUndeducedType()) {
|
// A new-expression that creates an object of type T initializes that
|
||||||
if (isa<DeducedTemplateSpecializationType>(
|
// object as follows:
|
||||||
AllocType->getContainedDeducedType()))
|
InitializationKind Kind
|
||||||
return ExprError(Diag(TypeRange.getBegin(),
|
// - If the new-initializer is omitted, the object is default-
|
||||||
diag::err_deduced_class_template_not_supported));
|
// 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)
|
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
|
||||||
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
|
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
|
||||||
<< AllocType << TypeRange);
|
<< AllocType << TypeRange);
|
||||||
|
@ -1958,23 +1989,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
||||||
else
|
else
|
||||||
InitType = AllocType;
|
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 Entity
|
||||||
= InitializedEntity::InitializeNew(StartLoc, InitType);
|
= InitializedEntity::InitializeNew(StartLoc, InitType);
|
||||||
InitializationSequence InitSeq(*this, Entity, Kind,
|
InitializationSequence InitSeq(*this, Entity, Kind,
|
||||||
|
|
|
@ -5914,7 +5914,8 @@ PerformConstructorInitialization(Sema &S,
|
||||||
S.MarkFunctionReferenced(Loc, Constructor);
|
S.MarkFunctionReferenced(Loc, Constructor);
|
||||||
|
|
||||||
CurInit = new (S.Context) CXXTemporaryObjectExpr(
|
CurInit = new (S.Context) CXXTemporaryObjectExpr(
|
||||||
S.Context, Constructor, TSInfo,
|
S.Context, Constructor,
|
||||||
|
Entity.getType().getNonLValueExprType(S.Context), TSInfo,
|
||||||
ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
|
ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
|
||||||
IsListInitialization, IsStdInitListInitialization,
|
IsListInitialization, IsStdInitListInitialization,
|
||||||
ConstructorInitRequiresZeroInit);
|
ConstructorInitRequiresZeroInit);
|
||||||
|
@ -6982,7 +6983,7 @@ InitializationSequence::Perform(Sema &S,
|
||||||
Kind.getRange().getBegin());
|
Kind.getRange().getBegin());
|
||||||
|
|
||||||
CurInit = new (S.Context) CXXScalarValueInitExpr(
|
CurInit = new (S.Context) CXXScalarValueInitExpr(
|
||||||
TSInfo->getType().getNonLValueExprType(S.Context), TSInfo,
|
Entity.getType().getNonLValueExprType(S.Context), TSInfo,
|
||||||
Kind.getRange().getEnd());
|
Kind.getRange().getEnd());
|
||||||
} else {
|
} else {
|
||||||
CurInit = new (S.Context) ImplicitValueInitExpr(Step->Type);
|
CurInit = new (S.Context) ImplicitValueInitExpr(Step->Type);
|
||||||
|
@ -7755,7 +7756,8 @@ bool InitializationSequence::Diagnose(Sema &S,
|
||||||
(void)Ovl;
|
(void)Ovl;
|
||||||
assert(Ovl == OR_Success && "Inconsistent overload resolution");
|
assert(Ovl == OR_Success && "Inconsistent overload resolution");
|
||||||
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8219,3 +8221,215 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
|
||||||
|
|
||||||
return Result;
|
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());
|
||||||
|
}
|
||||||
|
|
|
@ -4019,17 +4019,26 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// Substitute the 'auto' type specifier within a type for a given replacement
|
/// Substitute the 'auto' specifier or deduced template specialization type
|
||||||
/// type.
|
/// specifier within a type for a given replacement type.
|
||||||
class SubstituteAutoTransform :
|
class SubstituteDeducedTypeTransform :
|
||||||
public TreeTransform<SubstituteAutoTransform> {
|
public TreeTransform<SubstituteDeducedTypeTransform> {
|
||||||
QualType Replacement;
|
QualType Replacement;
|
||||||
bool UseAutoSugar;
|
bool UseTypeSugar;
|
||||||
public:
|
public:
|
||||||
SubstituteAutoTransform(Sema &SemaRef, QualType Replacement,
|
SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
|
||||||
bool UseAutoSugar = true)
|
bool UseTypeSugar = true)
|
||||||
: TreeTransform<SubstituteAutoTransform>(SemaRef),
|
: TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
|
||||||
Replacement(Replacement), UseAutoSugar(UseAutoSugar) {}
|
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) {
|
QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) {
|
||||||
// If we're building the type pattern to deduce against, don't wrap the
|
// If we're building the type pattern to deduce against, don't wrap the
|
||||||
|
@ -4039,21 +4048,29 @@ namespace {
|
||||||
// auto &&lref = lvalue;
|
// auto &&lref = lvalue;
|
||||||
// must transform into "rvalue reference to T" not "rvalue reference to
|
// 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.
|
// auto type deduced as T" in order for [temp.deduct.call]p3 to apply.
|
||||||
if (!UseAutoSugar) {
|
//
|
||||||
assert(isa<TemplateTypeParmType>(Replacement) &&
|
// FIXME: Is this still necessary?
|
||||||
"unexpected unsugared replacement kind");
|
if (!UseTypeSugar)
|
||||||
QualType Result = Replacement;
|
return TransformDesugared(TLB, TL);
|
||||||
TemplateTypeParmTypeLoc NewTL =
|
|
||||||
TLB.push<TemplateTypeParmTypeLoc>(Result);
|
QualType Result = SemaRef.Context.getAutoType(
|
||||||
NewTL.setNameLoc(TL.getNameLoc());
|
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
|
||||||
return Result;
|
auto NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||||
} else {
|
NewTL.setNameLoc(TL.getNameLoc());
|
||||||
QualType Result = SemaRef.Context.getAutoType(
|
return Result;
|
||||||
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
|
}
|
||||||
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
|
|
||||||
NewTL.setNameLoc(TL.getNameLoc());
|
QualType TransformDeducedTemplateSpecializationType(
|
||||||
return Result;
|
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) {
|
ExprResult TransformLambdaExpr(LambdaExpr *E) {
|
||||||
|
@ -4104,7 +4121,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||||
|
|
||||||
if (!DependentDeductionDepth &&
|
if (!DependentDeductionDepth &&
|
||||||
(Type.getType()->isDependentType() || Init->isTypeDependent())) {
|
(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");
|
assert(!Result.isNull() && "substituting DependentTy can't fail");
|
||||||
return DAR_Succeeded;
|
return DAR_Succeeded;
|
||||||
}
|
}
|
||||||
|
@ -4127,7 +4144,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||||
return DAR_FailedAlreadyDiagnosed;
|
return DAR_FailedAlreadyDiagnosed;
|
||||||
// FIXME: Support a non-canonical deduced type for 'auto'.
|
// FIXME: Support a non-canonical deduced type for 'auto'.
|
||||||
Deduced = Context.getCanonicalType(Deduced);
|
Deduced = Context.getCanonicalType(Deduced);
|
||||||
Result = SubstituteAutoTransform(*this, Deduced).Apply(Type);
|
Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
|
||||||
if (Result.isNull())
|
if (Result.isNull())
|
||||||
return DAR_FailedAlreadyDiagnosed;
|
return DAR_FailedAlreadyDiagnosed;
|
||||||
return DAR_Succeeded;
|
return DAR_Succeeded;
|
||||||
|
@ -4152,7 +4169,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||||
Loc, Loc, TemplParamPtr, Loc, nullptr);
|
Loc, Loc, TemplParamPtr, Loc, nullptr);
|
||||||
|
|
||||||
QualType FuncParam =
|
QualType FuncParam =
|
||||||
SubstituteAutoTransform(*this, TemplArg, /*UseAutoSugar*/false)
|
SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
|
||||||
.Apply(Type);
|
.Apply(Type);
|
||||||
assert(!FuncParam.isNull() &&
|
assert(!FuncParam.isNull() &&
|
||||||
"substituting template parameter for 'auto' failed");
|
"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.
|
// might acquire a matching type in the instantiation.
|
||||||
auto DeductionFailed = [&]() -> DeduceAutoResult {
|
auto DeductionFailed = [&]() -> DeduceAutoResult {
|
||||||
if (Init->isTypeDependent()) {
|
if (Init->isTypeDependent()) {
|
||||||
Result = SubstituteAutoTransform(*this, QualType()).Apply(Type);
|
Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
|
||||||
assert(!Result.isNull() && "substituting DependentTy can't fail");
|
assert(!Result.isNull() && "substituting DependentTy can't fail");
|
||||||
return DAR_Succeeded;
|
return DAR_Succeeded;
|
||||||
}
|
}
|
||||||
|
@ -4215,7 +4232,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||||
return DAR_FailedAlreadyDiagnosed;
|
return DAR_FailedAlreadyDiagnosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type);
|
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
|
||||||
if (Result.isNull())
|
if (Result.isNull())
|
||||||
return DAR_FailedAlreadyDiagnosed;
|
return DAR_FailedAlreadyDiagnosed;
|
||||||
|
|
||||||
|
@ -4238,22 +4255,22 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto,
|
||||||
QualType TypeToReplaceAuto) {
|
QualType TypeToReplaceAuto) {
|
||||||
if (TypeToReplaceAuto->isDependentType())
|
if (TypeToReplaceAuto->isDependentType())
|
||||||
TypeToReplaceAuto = QualType();
|
TypeToReplaceAuto = QualType();
|
||||||
return SubstituteAutoTransform(*this, TypeToReplaceAuto)
|
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
|
||||||
.TransformType(TypeWithAuto);
|
.TransformType(TypeWithAuto);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
|
TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
|
||||||
QualType TypeToReplaceAuto) {
|
QualType TypeToReplaceAuto) {
|
||||||
if (TypeToReplaceAuto->isDependentType())
|
if (TypeToReplaceAuto->isDependentType())
|
||||||
TypeToReplaceAuto = QualType();
|
TypeToReplaceAuto = QualType();
|
||||||
return SubstituteAutoTransform(*this, TypeToReplaceAuto)
|
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
|
||||||
.TransformType(TypeWithAuto);
|
.TransformType(TypeWithAuto);
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
|
QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
|
||||||
QualType TypeToReplaceAuto) {
|
QualType TypeToReplaceAuto) {
|
||||||
return SubstituteAutoTransform(*this, TypeToReplaceAuto,
|
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto,
|
||||||
/*UseAutoSugar*/ false)
|
/*UseTypeSugar*/ false)
|
||||||
.TransformType(TypeWithAuto);
|
.TransformType(TypeWithAuto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}}
|
|
@ -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*>>);
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
// RUN: %clang_cc1 -std=c++1z -verify %s
|
// RUN: %clang_cc1 -std=c++1z -verify %s
|
||||||
|
// expected-no-diagnostics
|
||||||
|
|
||||||
namespace std_example {
|
namespace std_example {
|
||||||
template<typename T, typename U = int> struct S {
|
template<typename T, typename U = int> struct S {
|
||||||
|
@ -10,5 +11,5 @@ namespace std_example {
|
||||||
using type = short;
|
using type = short;
|
||||||
operator type();
|
operator type();
|
||||||
};
|
};
|
||||||
S x{A()}; // expected-error {{not yet supported}}
|
S x{A()};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
|
// 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.
|
// Make sure we still correctly parse cases where a template can appear without arguments.
|
||||||
namespace template_template_arg {
|
namespace template_template_arg {
|
||||||
|
@ -18,7 +24,7 @@ namespace template_template_arg {
|
||||||
template<typename = ::A> struct YCCD {}; // expected-error {{requires template arguments}}
|
template<typename = ::A> struct YCCD {}; // expected-error {{requires template arguments}}
|
||||||
|
|
||||||
// FIXME: replacing the invalid type with 'int' here is horrible
|
// 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}}
|
template<typename T = A> struct G { }; // expected-error {{requires template arguments}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +33,7 @@ namespace injected_class_name {
|
||||||
A(T);
|
A(T);
|
||||||
void f(int) {
|
void f(int) {
|
||||||
A a = 1;
|
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);
|
void f(T);
|
||||||
};
|
};
|
||||||
|
@ -46,8 +52,8 @@ struct member {
|
||||||
|
|
||||||
operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}}
|
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 x; // FIXME: We deduce A<int> from the initializer despite this not being a definition!
|
||||||
static A y = 0; // expected-error {{not yet supported}}
|
static constexpr A y = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace in_typedef {
|
namespace in_typedef {
|
||||||
|
@ -67,18 +73,18 @@ namespace stmt {
|
||||||
// simple-declaration or cast. We also permit it in conditions,
|
// simple-declaration or cast. We also permit it in conditions,
|
||||||
// for-range-declarations, member-declarations for static data members, and
|
// for-range-declarations, member-declarations for static data members, and
|
||||||
// new-expressions, because not doing so would be bizarre.
|
// new-expressions, because not doing so would be bizarre.
|
||||||
A local = 0; // expected-error {{not yet supported}}
|
A local = 0;
|
||||||
static A local_static = 0; // expected-error {{not yet supported}}
|
static A local_static = 0;
|
||||||
static thread_local A thread_local_static = 0; // expected-error {{not yet supported}}
|
static thread_local A thread_local_static = 0;
|
||||||
if (A a = 0) {} // expected-error {{not yet supported}}
|
if (A a = 0) {}
|
||||||
if (A a = 0; a) {} // expected-error {{not yet supported}}
|
if (A a = 0; a) {}
|
||||||
switch (A a = 0) {} // expected-error {{not yet supported}}
|
switch (A a = 0) {} // expected-warning {{no case matching constant switch condition '0'}}
|
||||||
switch (A a = 0; a) {} // expected-error {{not yet supported}}
|
switch (A a = 0; a) {} // expected-warning {{no case matching constant switch condition '0'}}
|
||||||
for (A a = 0; a; /**/) {} // expected-error {{not yet supported}}
|
for (A a = 0; a; /**/) {}
|
||||||
for (/**/; A a = 0; /**/) {} // expected-error {{not yet supported}}
|
for (/**/; A a = 0; /**/) {}
|
||||||
while (A a = 0) {} // expected-error {{not yet supported}}
|
while (A a = 0) {}
|
||||||
int arr[3];
|
int arr[3];
|
||||||
for (A a : arr) {} // expected-error {{not yet supported}}
|
for (A a : arr) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
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{{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);
|
||||||
(void)A{n}; // expected-error {{not yet supported}}
|
(void)A{n};
|
||||||
(void)new A(n); // expected-error {{not yet supported}}
|
(void)new A(n);
|
||||||
(void)new A{n}; // expected-error {{not yet supported}}
|
(void)new A{n};
|
||||||
// FIXME: We should diagnose the lack of an initializer here.
|
// 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}}
|
auto k() -> A; // expected-error{{requires template arguments}}
|
||||||
|
|
||||||
A a; // expected-error {{requires an initializer}}
|
A a; // FIXME: This is (technically) syntactically invalid.
|
||||||
A b = 0; // expected-error {{not yet supported}}
|
A b = 0;
|
||||||
const A c = 0; // expected-error {{not yet supported}}
|
const A c = 0;
|
||||||
A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
|
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 *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 &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 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 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 (*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 {
|
namespace typename_specifier {
|
||||||
struct F {};
|
struct F {};
|
||||||
|
|
||||||
void e() {
|
void e() {
|
||||||
(void) typename ::A(0); // expected-error {{not yet supported}}
|
(void) typename ::A(0);
|
||||||
(void) typename ::A{0}; // expected-error {{not yet supported}}
|
(void) typename ::A{0};
|
||||||
new typename ::A(0); // expected-error {{not yet supported}}
|
new typename ::A(0);
|
||||||
new typename ::A{0}; // expected-error {{not yet supported}}
|
new typename ::A{0};
|
||||||
typename ::A a = 0; // expected-error {{not yet supported}}
|
typename ::A a = 0;
|
||||||
const typename ::A b = 0; // expected-error {{not yet supported}}
|
const typename ::A b = 0;
|
||||||
if (typename ::A a = 0) {} // expected-error {{not yet supported}}
|
if (typename ::A a = 0) {}
|
||||||
for (typename ::A a = 0; typename ::A b = 0; /**/) {} // expected-error 2{{not yet supported}}
|
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}}
|
||||||
(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}}
|
typename ::A a = 0;
|
||||||
const typename ::A b = 0; // expected-error {{not yet supported}}
|
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 (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 *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 &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 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 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 (*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}}
|
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() {
|
template<typename T> void f() {
|
||||||
(void) typename T::A(0); // expected-error {{not yet supported}}
|
(void) typename T::A(0); // expected-error {{no viable}}
|
||||||
(void) typename T::A{0}; // expected-error {{not yet supported}}
|
(void) typename T::A{0}; // expected-error {{no viable}}
|
||||||
new typename T::A(0); // expected-error {{not yet supported}}
|
new typename T::A(0); // expected-error {{no viable}}
|
||||||
new typename T::A{0}; // expected-error {{not yet supported}}
|
new typename T::A{0}; // expected-error {{no viable}}
|
||||||
typename T::A a = 0; // expected-error {{not yet supported}}
|
typename T::A a = 0; // expected-error {{no viable}}
|
||||||
const typename T::A b = 0; // expected-error {{not yet supported}}
|
const typename T::A b = 0; // expected-error {{no viable}}
|
||||||
if (typename T::A a = 0) {} // expected-error {{not yet supported}}
|
if (typename T::A a = 0) {} // expected-error {{no viable}}
|
||||||
for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error 2{{not yet supported}}
|
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}}
|
||||||
{(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 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 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 (*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}}
|
template void f<X>(); // expected-note {{instantiation of}}
|
||||||
|
|
||||||
|
|
|
@ -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}}
|
||||||
|
}
|
Loading…
Reference in New Issue