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:
|
||||
CXXTemporaryObjectExpr(const ASTContext &C,
|
||||
CXXConstructorDecl *Cons,
|
||||
TypeSourceInfo *Type,
|
||||
QualType Type,
|
||||
TypeSourceInfo *TSI,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceRange ParenOrBraceRange,
|
||||
bool HadMultipleCandidates,
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -579,6 +582,16 @@ public:
|
|||
return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal,
|
||||
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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
QualType Result = SemaRef.Context.getAutoType(
|
||||
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
|
||||
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||
NewTL.setNameLoc(TL.getNameLoc());
|
||||
return Result;
|
||||
}
|
||||
//
|
||||
// FIXME: Is this still necessary?
|
||||
if (!UseTypeSugar)
|
||||
return TransformDesugared(TLB, TL);
|
||||
|
||||
QualType Result = SemaRef.Context.getAutoType(
|
||||
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
|
||||
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,22 +4255,22 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto,
|
|||
QualType TypeToReplaceAuto) {
|
||||
if (TypeToReplaceAuto->isDependentType())
|
||||
TypeToReplaceAuto = QualType();
|
||||
return SubstituteAutoTransform(*this, TypeToReplaceAuto)
|
||||
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
|
||||
.TransformType(TypeWithAuto);
|
||||
}
|
||||
|
||||
TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
|
||||
QualType TypeToReplaceAuto) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
// 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()};
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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