diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a13eedebfa5f1e244c602874cc3b515aea45e5ac..9b741101f476f6f506b5189d09b422fbf5b2134a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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 ">; +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< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fdc525ccc9bbd3260a191b05064b912cb3b48a63..7e5b4e80f72d43c43188f0e8495ff76c34fca9d5 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0e99f7047686e49748c734177e50b34af13cb77b..61e104fd1d2c62311a2e62cdf20ab15d9f9d7377 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 13face95e95f6894c8860731fd78ed43c4d8c04b..2d47e0e3e8967dd5c7bf8fe049253aacbcb01f3c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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(); + 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(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; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 78a58964db3a7a04e74a1a1bbb87931b0447f6da..23dc7e9d20aa72f23f254888c8fa2832be519aaa 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -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(Init) && Init->getType()->isVoidType()) || !SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI)) SemaRef.Diag(Loc, diag) << Init->getType(); if (!InitTSI) { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 738e596ef3806c7264d88d1ba5fd65a43309912d..4fff827206cbd64aec0b411b124d1717e880b107 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -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(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(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, diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index a08a04806cae00a84d8c1782205c3c79749a965d..47ceaf0b83c813623491a18392beaa553d4dc50f 100644 --- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -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>::value, ""); + auto bl = {1, 2.0}; // expected-error {{cannot deduce}} + + for (int i : {1, 2, 3, 4}) {} +} diff --git a/clang/test/SemaCXX/generalized-initializers.cpp b/clang/test/SemaCXX/generalized-initializers.cpp index 2e7df9aeafe51f2a675989dec09310db83ad3114..d696650e3eb1c0dd7aae3e72eabcc4a67322c794 100644 --- a/clang/test/SemaCXX/generalized-initializers.cpp +++ b/clang/test/SemaCXX/generalized-initializers.cpp @@ -38,18 +38,6 @@ namespace std { }; } -namespace integral { - - void initializer_list() { - auto l = {1, 2, 3, 4}; - static_assert(same_type>::value, ""); - auto bl = {1, 2.0}; // expected-error {{cannot deduce}} - - for (int i : {1, 2, 3, 4}) {} - } - -} - namespace objects { struct X1 { X1(int); };