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">;
|
||||
def err_auto_var_deduction_failure : Error<
|
||||
"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<
|
||||
"new expression for type %0 has incompatible constructor argument of type %1">;
|
||||
def err_auto_different_deductions : Error<
|
||||
"'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
|
||||
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.
|
||||
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,
|
||||
SourceLocation UsingLoc,
|
||||
SourceLocation NamespcLoc,
|
||||
|
@ -4707,6 +4713,7 @@ public:
|
|||
|
||||
bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
|
||||
TypeSourceInfo *&Result);
|
||||
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
|
||||
|
||||
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
|
||||
FunctionTemplateDecl *FT2,
|
||||
|
|
|
@ -5976,9 +5976,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
|
||||
TypeSourceInfo *DeducedType = 0;
|
||||
if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
|
||||
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
|
||||
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
|
||||
<< Init->getSourceRange();
|
||||
DiagnoseAutoDeductionFailure(VDecl, Init);
|
||||
if (!DeducedType) {
|
||||
RealDecl->setInvalidDecl();
|
||||
return;
|
||||
|
|
|
@ -5829,6 +5829,54 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
|
|||
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
|
||||
/// apply in all contexts.
|
||||
static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
|
||||
|
@ -9027,9 +9075,7 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
|
|||
Expr *Init = Exprs.get()[0];
|
||||
TypeSourceInfo *DeducedType = 0;
|
||||
if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
|
||||
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
|
||||
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
|
||||
<< Init->getSourceRange();
|
||||
DiagnoseAutoDeductionFailure(VDecl, Init);
|
||||
if (!DeducedType) {
|
||||
RealDecl->setInvalidDecl();
|
||||
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
|
||||
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
|
||||
TypeSourceInfo *InitTSI = 0;
|
||||
if (Init->getType()->isVoidType() ||
|
||||
if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
|
||||
!SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI))
|
||||
SemaRef.Diag(Loc, diag) << Init->getType();
|
||||
if (!InitTSI) {
|
||||
|
|
|
@ -3422,19 +3422,36 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
|
|||
return false;
|
||||
|
||||
TemplateDeductionInfo Info(Context, Loc);
|
||||
if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
|
||||
InitType, Info, Deduced, TDF))
|
||||
return false;
|
||||
|
||||
InitListExpr * InitList = dyn_cast<InitListExpr>(Init);
|
||||
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();
|
||||
if (DeducedType.isNull())
|
||||
return false;
|
||||
|
||||
|
||||
if (InitList) {
|
||||
DeducedType = BuildStdInitializerList(DeducedType, Loc);
|
||||
if (DeducedType.isNull())
|
||||
return false;
|
||||
}
|
||||
|
||||
Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
|
||||
|
||||
|
||||
// Check that the deduced argument type is compatible with the original
|
||||
// argument type per C++ [temp.deduct.call]p4.
|
||||
if (Result &&
|
||||
if (!InitList && Result &&
|
||||
CheckOriginalCallArgDeduction(*this,
|
||||
Sema::OriginalCallArg(FuncParam,0,InitType),
|
||||
Result->getType())) {
|
||||
|
@ -3445,6 +3462,17 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
|
|||
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
|
||||
MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
|
||||
bool OnlyDeduced,
|
||||
|
|
|
@ -109,3 +109,11 @@ void argument_deduction() {
|
|||
|
||||
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 {
|
||||
|
||||
struct X1 { X1(int); };
|
||||
|
|
Loading…
Reference in New Issue