forked from OSchip/llvm-project
Auto deduction support for std::initializer_list, including for-range support. This means you can now write:
for (int i : {1, 4, 512, 23, 251}) {} llvm-svn: 148353
This commit is contained in:
parent
43144e72b5
commit
42acd4a05b
|
@ -1196,10 +1196,17 @@ def err_trailing_return_in_parens : Error<
|
||||||
"trailing return type may not be nested within parentheses">;
|
"trailing return type may not be nested within parentheses">;
|
||||||
def err_auto_var_deduction_failure : Error<
|
def err_auto_var_deduction_failure : Error<
|
||||||
"variable %0 with type %1 has incompatible initializer of type %2">;
|
"variable %0 with type %1 has incompatible initializer of type %2">;
|
||||||
|
def err_auto_var_deduction_failure_from_init_list : Error<
|
||||||
|
"cannot deduce actual type for variable %0 with type %1 from initializer list">;
|
||||||
def err_auto_new_deduction_failure : Error<
|
def err_auto_new_deduction_failure : Error<
|
||||||
"new expression for type %0 has incompatible constructor argument of type %1">;
|
"new expression for type %0 has incompatible constructor argument of type %1">;
|
||||||
def err_auto_different_deductions : Error<
|
def err_auto_different_deductions : Error<
|
||||||
"'auto' deduced as %0 in declaration of %1 and deduced as %2 in declaration of %3">;
|
"'auto' deduced as %0 in declaration of %1 and deduced as %2 in declaration of %3">;
|
||||||
|
def err_implied_std_initializer_list_not_found : Error<
|
||||||
|
"cannot deduce type of initializer list because std::initializer_list was "
|
||||||
|
"not found; include <initializer_list>">;
|
||||||
|
def err_malformed_std_initializer_list : Error<
|
||||||
|
"std::initializer_list must be a class template with a single type parameter">;
|
||||||
|
|
||||||
// C++11 override control
|
// C++11 override control
|
||||||
def override_keyword_only_allowed_on_virtual_member_functions : Error<
|
def override_keyword_only_allowed_on_virtual_member_functions : Error<
|
||||||
|
|
|
@ -2729,6 +2729,12 @@ public:
|
||||||
/// it is and Element is not NULL, assigns the element type to Element.
|
/// it is and Element is not NULL, assigns the element type to Element.
|
||||||
bool isStdInitializerList(QualType Ty, QualType *Element);
|
bool isStdInitializerList(QualType Ty, QualType *Element);
|
||||||
|
|
||||||
|
/// \brief Looks for the std::initializer_list template and instantiates it
|
||||||
|
/// with Element, or emits an error if it's not found.
|
||||||
|
///
|
||||||
|
/// \returns The instantiated template, or null on error.
|
||||||
|
QualType BuildStdInitializerList(QualType Element, SourceLocation Loc);
|
||||||
|
|
||||||
Decl *ActOnUsingDirective(Scope *CurScope,
|
Decl *ActOnUsingDirective(Scope *CurScope,
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
SourceLocation NamespcLoc,
|
SourceLocation NamespcLoc,
|
||||||
|
@ -4707,6 +4713,7 @@ public:
|
||||||
|
|
||||||
bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
|
bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
|
||||||
TypeSourceInfo *&Result);
|
TypeSourceInfo *&Result);
|
||||||
|
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
|
||||||
|
|
||||||
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
||||||
FunctionTemplateDecl *FT2,
|
FunctionTemplateDecl *FT2,
|
||||||
|
|
|
@ -5976,9 +5976,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
||||||
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
|
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
|
||||||
TypeSourceInfo *DeducedType = 0;
|
TypeSourceInfo *DeducedType = 0;
|
||||||
if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
|
if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
|
||||||
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
|
DiagnoseAutoDeductionFailure(VDecl, Init);
|
||||||
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
|
|
||||||
<< Init->getSourceRange();
|
|
||||||
if (!DeducedType) {
|
if (!DeducedType) {
|
||||||
RealDecl->setInvalidDecl();
|
RealDecl->setInvalidDecl();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -5829,6 +5829,54 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ClassTemplateDecl *LookupStdInitializerList(Sema &S, SourceLocation Loc){
|
||||||
|
NamespaceDecl *Std = S.getStdNamespace();
|
||||||
|
if (!Std) {
|
||||||
|
S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LookupResult Result(S, &S.PP.getIdentifierTable().get("initializer_list"),
|
||||||
|
Loc, Sema::LookupOrdinaryName);
|
||||||
|
if (!S.LookupQualifiedName(Result, Std)) {
|
||||||
|
S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ClassTemplateDecl *Template = Result.getAsSingle<ClassTemplateDecl>();
|
||||||
|
if (!Template) {
|
||||||
|
Result.suppressDiagnostics();
|
||||||
|
// We found something weird. Complain about the first thing we found.
|
||||||
|
NamedDecl *Found = *Result.begin();
|
||||||
|
S.Diag(Found->getLocation(), diag::err_malformed_std_initializer_list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found some template called std::initializer_list. Now verify that it's
|
||||||
|
// correct.
|
||||||
|
TemplateParameterList *Params = Template->getTemplateParameters();
|
||||||
|
if (Params->size() != 1 || !isa<TemplateTypeParmDecl>(Params->getParam(0))) {
|
||||||
|
S.Diag(Template->getLocation(), diag::err_malformed_std_initializer_list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Template;
|
||||||
|
}
|
||||||
|
|
||||||
|
QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
|
||||||
|
if (!StdInitializerList) {
|
||||||
|
StdInitializerList = LookupStdInitializerList(*this, Loc);
|
||||||
|
if (!StdInitializerList)
|
||||||
|
return QualType();
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateArgumentListInfo Args(Loc, Loc);
|
||||||
|
Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element),
|
||||||
|
Context.getTrivialTypeSourceInfo(Element,
|
||||||
|
Loc)));
|
||||||
|
return Context.getCanonicalType(
|
||||||
|
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Determine whether a using statement is in a context where it will be
|
/// \brief Determine whether a using statement is in a context where it will be
|
||||||
/// apply in all contexts.
|
/// apply in all contexts.
|
||||||
static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
|
static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
|
||||||
|
@ -9027,9 +9075,7 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
|
||||||
Expr *Init = Exprs.get()[0];
|
Expr *Init = Exprs.get()[0];
|
||||||
TypeSourceInfo *DeducedType = 0;
|
TypeSourceInfo *DeducedType = 0;
|
||||||
if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
|
if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
|
||||||
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
|
DiagnoseAutoDeductionFailure(VDecl, Init);
|
||||||
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
|
|
||||||
<< Init->getSourceRange();
|
|
||||||
if (!DeducedType) {
|
if (!DeducedType) {
|
||||||
RealDecl->setInvalidDecl();
|
RealDecl->setInvalidDecl();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1164,7 +1164,7 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
|
||||||
// Deduce the type for the iterator variable now rather than leaving it to
|
// Deduce the type for the iterator variable now rather than leaving it to
|
||||||
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
|
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
|
||||||
TypeSourceInfo *InitTSI = 0;
|
TypeSourceInfo *InitTSI = 0;
|
||||||
if (Init->getType()->isVoidType() ||
|
if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
|
||||||
!SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI))
|
!SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI))
|
||||||
SemaRef.Diag(Loc, diag) << Init->getType();
|
SemaRef.Diag(Loc, diag) << Init->getType();
|
||||||
if (!InitTSI) {
|
if (!InitTSI) {
|
||||||
|
|
|
@ -3422,19 +3422,36 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TemplateDeductionInfo Info(Context, Loc);
|
TemplateDeductionInfo Info(Context, Loc);
|
||||||
if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
|
|
||||||
InitType, Info, Deduced, TDF))
|
InitListExpr * InitList = dyn_cast<InitListExpr>(Init);
|
||||||
return false;
|
if (InitList) {
|
||||||
|
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
|
||||||
|
if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
|
||||||
|
InitList->getInit(i)->getType(),
|
||||||
|
Info, Deduced, TDF))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
|
||||||
|
InitType, Info, Deduced, TDF))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QualType DeducedType = Deduced[0].getAsType();
|
QualType DeducedType = Deduced[0].getAsType();
|
||||||
if (DeducedType.isNull())
|
if (DeducedType.isNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (InitList) {
|
||||||
|
DeducedType = BuildStdInitializerList(DeducedType, Loc);
|
||||||
|
if (DeducedType.isNull())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
|
Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
|
||||||
|
|
||||||
// Check that the deduced argument type is compatible with the original
|
// Check that the deduced argument type is compatible with the original
|
||||||
// argument type per C++ [temp.deduct.call]p4.
|
// argument type per C++ [temp.deduct.call]p4.
|
||||||
if (Result &&
|
if (!InitList && Result &&
|
||||||
CheckOriginalCallArgDeduction(*this,
|
CheckOriginalCallArgDeduction(*this,
|
||||||
Sema::OriginalCallArg(FuncParam,0,InitType),
|
Sema::OriginalCallArg(FuncParam,0,InitType),
|
||||||
Result->getType())) {
|
Result->getType())) {
|
||||||
|
@ -3445,6 +3462,17 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
|
||||||
|
if (isa<InitListExpr>(Init))
|
||||||
|
Diag(VDecl->getLocation(),
|
||||||
|
diag::err_auto_var_deduction_failure_from_init_list)
|
||||||
|
<< VDecl->getDeclName() << VDecl->getType() << Init->getSourceRange();
|
||||||
|
else
|
||||||
|
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
|
||||||
|
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
|
||||||
|
<< Init->getSourceRange();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
|
MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
|
||||||
bool OnlyDeduced,
|
bool OnlyDeduced,
|
||||||
|
|
|
@ -109,3 +109,11 @@ void argument_deduction() {
|
||||||
|
|
||||||
deduce_ref({1, 2.0}); // expected-error {{no matching function}}
|
deduce_ref({1, 2.0}); // expected-error {{no matching function}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void auto_deduction() {
|
||||||
|
auto l = {1, 2, 3, 4};
|
||||||
|
static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
|
||||||
|
auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
|
||||||
|
|
||||||
|
for (int i : {1, 2, 3, 4}) {}
|
||||||
|
}
|
||||||
|
|
|
@ -38,18 +38,6 @@ namespace std {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace integral {
|
|
||||||
|
|
||||||
void initializer_list() {
|
|
||||||
auto l = {1, 2, 3, 4};
|
|
||||||
static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
|
|
||||||
auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
|
|
||||||
|
|
||||||
for (int i : {1, 2, 3, 4}) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace objects {
|
namespace objects {
|
||||||
|
|
||||||
struct X1 { X1(int); };
|
struct X1 { X1(int); };
|
||||||
|
|
Loading…
Reference in New Issue