r294613 - [c++1z] P0091R3: Basic support for deducing class template arguments via deduction-guides.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 9 11:17:44 PST 2017
Author: rsmith
Date: Thu Feb 9 13:17:44 2017
New Revision: 294613
URL: http://llvm.org/viewvc/llvm-project?rev=294613&view=rev
Log:
[c++1z] P0091R3: Basic support for deducing class template arguments via deduction-guides.
Added:
cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/
cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp
cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
Modified:
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Initialization.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/Sema/SemaCast.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp
cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Thu Feb 9 13:17:44 2017
@@ -1470,7 +1470,8 @@ class CXXTemporaryObjectExpr : public CX
public:
CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
- TypeSourceInfo *Type,
+ QualType Type,
+ TypeSourceInfo *TSI,
ArrayRef<Expr *> Args,
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Feb 9 13:17:44 2017
@@ -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()) {
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb 9 13:17:44 2017
@@ -1849,8 +1849,8 @@ def warn_cxx98_compat_temp_copy : Warnin
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_
"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<
Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Thu Feb 9 13:17:44 2017
@@ -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 {
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Feb 9 13:17:44 2017
@@ -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);
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Thu Feb 9 13:17:44 2017
@@ -734,23 +734,23 @@ CXXBindTemporaryExpr *CXXBindTemporaryEx
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 {
Modified: cfe/trunk/lib/Sema/SemaCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCast.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCast.cpp Thu Feb 9 13:17:44 2017
@@ -2627,11 +2627,12 @@ ExprResult Sema::BuildCStyleCastExpr(Sou
}
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());
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Feb 9 13:17:44 2017
@@ -9807,16 +9807,33 @@ QualType Sema::deduceVarTypeFromInitiali
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::deduceVarTypeFromInitiali
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 *Re
}
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 *Re
}
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 *
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
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Feb 9 13:17:44 2017
@@ -8556,7 +8556,7 @@ QualType Sema::BuildStdInitializerList(Q
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
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Feb 9 13:17:44 2017
@@ -1266,15 +1266,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSour
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(TypeSour
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(TypeSour
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(TypeSour
// 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, boo
NumInits = List->getNumExprs();
}
+ // 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.
- if (AllocType->isUndeducedType()) {
- if (isa<DeducedTemplateSpecializationType>(
- AllocType->getContainedDeducedType()))
- return ExprError(Diag(TypeRange.getBegin(),
- diag::err_deduced_class_template_not_supported));
+ 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, boo
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,
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Feb 9 13:17:44 2017
@@ -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(Se
(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 In
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());
+}
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Feb 9 13:17:44 2017
@@ -4019,17 +4019,26 @@ Sema::TemplateDeductionResult Sema::Dedu
}
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
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
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
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
// 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
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 Ty
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);
}
Added: cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp?rev=294613&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp Thu Feb 9 13:17:44 2017
@@ -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}}
Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp?rev=294613&view=auto
==============================================================================
--- cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp (added)
+++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp Thu Feb 9 13:17:44 2017
@@ -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*>>);
+}
Modified: cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp Thu Feb 9 13:17:44 2017
@@ -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()};
}
Modified: cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp (original)
+++ cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp Thu Feb 9 13:17:44 2017
@@ -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}}
Added: cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp?rev=294613&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp Thu Feb 9 13:17:44 2017
@@ -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}}
+}
More information about the cfe-commits
mailing list