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:
Sebastian Redl 2012-01-17 22:50:08 +00:00
parent 43144e72b5
commit 42acd4a05b
8 changed files with 107 additions and 25 deletions

View File

@ -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<

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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,

View File

@ -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}) {}
}

View File

@ -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); };