r291190 - Add missing "original call argument has same type as deduced parameter type"

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 5 15:02:44 PST 2017


Author: rsmith
Date: Thu Jan  5 17:02:44 2017
New Revision: 291190

URL: http://llvm.org/viewvc/llvm-project?rev=291190&view=rev
Log:
Add missing "original call argument has same type as deduced parameter type"
check for deductions from elements of a braced-init-list.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=291190&r1=291189&r2=291190&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan  5 17:02:44 2017
@@ -3377,8 +3377,10 @@ def note_addrof_ovl_candidate_disabled_b
     "candidate function made ineligible by enable_if">;
 def note_ovl_candidate_deduced_mismatch : Note<
     "candidate template ignored: deduced type "
-    "%diff{$ of %ordinal0 parameter does not match adjusted type $ of argument"
-    "|of %ordinal0 parameter does not match adjusted type of argument}1,2%3">;
+    "%diff{$ of %select{|element of }4%ordinal0 parameter does not match "
+    "adjusted type $ of %select{|element of }4argument"
+    "|of %select{|element of }4%ordinal0 parameter does not match "
+    "adjusted type of %select{|element of }4argument}1,2%3">;
 def note_ovl_candidate_non_deduced_mismatch : Note<
     "candidate template ignored: could not match %diff{$ against $|types}0,1">;
 // This note is needed because the above note would sometimes print two

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=291190&r1=291189&r2=291190&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan  5 17:02:44 2017
@@ -6564,6 +6564,10 @@ public:
     /// \brief After substituting deduced template arguments, a dependent
     /// parameter type did not match the corresponding argument.
     TDK_DeducedMismatch,
+    /// \brief After substituting deduced template arguments, an element of
+    /// a dependent parameter type did not match the corresponding element
+    /// of the corresponding argument (when deducing from an initializer list).
+    TDK_DeducedMismatchNested,
     /// \brief A non-depnedent component of the parameter did not match the
     /// corresponding component of the argument.
     TDK_NonDeducedMismatch,
@@ -6602,13 +6606,14 @@ public:
   /// brief A function argument from which we performed template argument
   // deduction for a call.
   struct OriginalCallArg {
-    OriginalCallArg(QualType OriginalParamType,
-                    unsigned ArgIdx,
-                    QualType OriginalArgType)
-      : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx),
-        OriginalArgType(OriginalArgType) { }
+    OriginalCallArg(QualType OriginalParamType, bool DecomposedParam,
+                    unsigned ArgIdx, QualType OriginalArgType)
+        : OriginalParamType(OriginalParamType),
+          DecomposedParam(DecomposedParam), ArgIdx(ArgIdx),
+          OriginalArgType(OriginalArgType) {}
 
     QualType OriginalParamType;
+    bool DecomposedParam;
     unsigned ArgIdx;
     QualType OriginalArgType;
   };

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=291190&r1=291189&r2=291190&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Jan  5 17:02:44 2017
@@ -604,7 +604,8 @@ clang::MakeDeductionFailureInfo(ASTConte
     Result.Data = Info.Param.getOpaqueValue();
     break;
 
-  case Sema::TDK_DeducedMismatch: {
+  case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested: {
     // FIXME: Should allocate from normal heap so that we can free this later.
     auto *Saved = new (Context) DFIDeducedMismatchArgs;
     Saved->FirstArg = Info.FirstArg;
@@ -664,6 +665,7 @@ void DeductionFailureInfo::Destroy() {
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
   case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested:
   case Sema::TDK_NonDeducedMismatch:
     // FIXME: Destroy the data?
     Data = nullptr;
@@ -699,6 +701,7 @@ TemplateParameter DeductionFailureInfo::
   case Sema::TDK_TooFewArguments:
   case Sema::TDK_SubstitutionFailure:
   case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested:
   case Sema::TDK_NonDeducedMismatch:
   case Sema::TDK_CUDATargetMismatch:
     return TemplateParameter();
@@ -735,6 +738,7 @@ TemplateArgumentList *DeductionFailureIn
     return nullptr;
 
   case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested:
     return static_cast<DFIDeducedMismatchArgs*>(Data)->TemplateArgs;
 
   case Sema::TDK_SubstitutionFailure:
@@ -764,6 +768,7 @@ const TemplateArgument *DeductionFailure
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
   case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested:
   case Sema::TDK_NonDeducedMismatch:
     return &static_cast<DFIArguments*>(Data)->FirstArg;
 
@@ -791,6 +796,7 @@ const TemplateArgument *DeductionFailure
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
   case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested:
   case Sema::TDK_NonDeducedMismatch:
     return &static_cast<DFIArguments*>(Data)->SecondArg;
 
@@ -803,11 +809,14 @@ const TemplateArgument *DeductionFailure
 }
 
 llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
-  if (static_cast<Sema::TemplateDeductionResult>(Result) ==
-        Sema::TDK_DeducedMismatch)
+  switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
+  case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested:
     return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex;
 
-  return llvm::None;
+  default:
+    return llvm::None;
+  }
 }
 
 void OverloadCandidateSet::destroyCandidates() {
@@ -9682,7 +9691,8 @@ static void DiagnoseBadDeduction(Sema &S
     return;
   }
 
-  case Sema::TDK_DeducedMismatch: {
+  case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested: {
     // Format the template argument list into the argument string.
     SmallString<128> TemplateArgString;
     if (TemplateArgumentList *Args =
@@ -9695,7 +9705,8 @@ static void DiagnoseBadDeduction(Sema &S
     S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch)
         << (*DeductionFailure.getCallArgIndex() + 1)
         << *DeductionFailure.getFirstArg() << *DeductionFailure.getSecondArg()
-        << TemplateArgString;
+        << TemplateArgString
+        << (DeductionFailure.Result == Sema::TDK_DeducedMismatchNested);
     break;
   }
 
@@ -10012,6 +10023,7 @@ static unsigned RankDeductionFailure(con
 
   case Sema::TDK_SubstitutionFailure:
   case Sema::TDK_DeducedMismatch:
+  case Sema::TDK_DeducedMismatchNested:
   case Sema::TDK_NonDeducedMismatch:
   case Sema::TDK_MiscellaneousDeductionFailure:
   case Sema::TDK_CUDATargetMismatch:

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=291190&r1=291189&r2=291190&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Jan  5 17:02:44 2017
@@ -19,6 +19,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeOrdering.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/Template.h"
@@ -2856,6 +2857,36 @@ CheckOriginalCallArgDeduction(Sema &S, S
   return true;
 }
 
+/// Find the pack index for a particular parameter index in an instantiation of
+/// a function template with specific arguments.
+///
+/// \return The pack index for whichever pack produced this parameter, or -1
+///         if this was not produced by a parameter. Intended to be used as the
+///         ArgumentPackSubstitutionIndex for further substitutions.
+// FIXME: We should track this in OriginalCallArgs so we don't need to
+// reconstruct it here.
+static unsigned getPackIndexForParam(Sema &S,
+                                     FunctionTemplateDecl *FunctionTemplate,
+                                     const MultiLevelTemplateArgumentList &Args,
+                                     unsigned ParamIdx) {
+  unsigned Idx = 0;
+  for (auto *PD : FunctionTemplate->getTemplatedDecl()->parameters()) {
+    if (PD->isParameterPack()) {
+      unsigned NumExpansions =
+          S.getNumArgumentsInExpansion(PD->getType(), Args).getValueOr(1);
+      if (Idx + NumExpansions > ParamIdx)
+        return ParamIdx - Idx;
+      Idx += NumExpansions;
+    } else {
+      if (Idx == ParamIdx)
+        return -1; // Not a pack expansion
+      ++Idx;
+    }
+  }
+
+  llvm_unreachable("parameter index would not be produced from template");
+}
+
 /// \brief Finish template argument deduction for a function template,
 /// checking the deduced template arguments for completeness and forming
 /// the function template specialization.
@@ -2906,9 +2937,9 @@ Sema::FinishTemplateArgumentDeduction(Fu
   DeclContext *Owner = FunctionTemplate->getDeclContext();
   if (FunctionTemplate->getFriendObjectKind())
     Owner = FunctionTemplate->getLexicalDeclContext();
+  MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList);
   Specialization = cast_or_null<FunctionDecl>(
-                      SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner,
-                         MultiLevelTemplateArgumentList(*DeducedArgumentList)));
+      SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs));
   if (!Specialization || Specialization->isInvalidDecl())
     return TDK_SubstitutionFailure;
 
@@ -2934,19 +2965,46 @@ Sema::FinishTemplateArgumentDeduction(Fu
     //   In general, the deduction process attempts to find template argument
     //   values that will make the deduced A identical to A (after the type A
     //   is transformed as described above). [...]
+    llvm::SmallDenseMap<std::pair<unsigned, QualType>, QualType> DeducedATypes;
     for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) {
       OriginalCallArg OriginalArg = (*OriginalCallArgs)[I];
-      unsigned ParamIdx = OriginalArg.ArgIdx;
 
+      auto ParamIdx = OriginalArg.ArgIdx;
       if (ParamIdx >= Specialization->getNumParams())
+        // FIXME: This presumably means a pack ended up smaller than we
+        // expected while deducing. Should this not result in deduction
+        // failure? Can it even happen?
         continue;
 
-      QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
+      QualType DeducedA;
+      if (!OriginalArg.DecomposedParam) {
+        // P is one of the function parameters, just look up its substituted
+        // type.
+        DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
+      } else {
+        // P is a decomposed element of a parameter corresponding to a
+        // braced-init-list argument. Substitute back into P to find the
+        // deduced A.
+        QualType &CacheEntry =
+            DeducedATypes[{ParamIdx, OriginalArg.OriginalParamType}];
+        if (CacheEntry.isNull()) {
+          ArgumentPackSubstitutionIndexRAII PackIndex(
+              *this, getPackIndexForParam(*this, FunctionTemplate, SubstArgs,
+                                          ParamIdx));
+          CacheEntry =
+              SubstType(OriginalArg.OriginalParamType, SubstArgs,
+                        Specialization->getTypeSpecStartLoc(),
+                        Specialization->getDeclName());
+        }
+        DeducedA = CacheEntry;
+      }
+
       if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
         Info.FirstArg = TemplateArgument(DeducedA);
         Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
         Info.CallArgIndex = OriginalArg.ArgIdx;
-        return TDK_DeducedMismatch;
+        return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested
+                                           : TDK_DeducedMismatch;
       }
     }
   }
@@ -3203,7 +3261,7 @@ static Sema::TemplateDeductionResult Ded
     Expr *Arg, TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
     SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
-    Optional<unsigned> ArgIdx, unsigned TDF);
+    bool DecomposedParam, unsigned ArgIdx, unsigned TDF);
 
 /// \brief Attempt template argument deduction from an initializer list
 ///        deemed to be an argument in a function call.
@@ -3211,7 +3269,8 @@ static Sema::TemplateDeductionResult Ded
     Sema &S, TemplateParameterList *TemplateParams, QualType AdjustedParamType,
     InitListExpr *ILE, TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
-    SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, unsigned TDF) {
+    SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, unsigned ArgIdx,
+    unsigned TDF) {
   // C++ [temp.deduct.call]p1: (CWG 1591)
   //   If removing references and cv-qualifiers from P gives
   //   std::initializer_list<P0> or P0[N] for some P0 and N and the argument is
@@ -3237,8 +3296,8 @@ static Sema::TemplateDeductionResult Ded
   if (ElTy->isDependentType()) {
     for (Expr *E : ILE->inits()) {
       if (auto Result = DeduceTemplateArgumentsFromCallArgument(
-              S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, None,
-              TDF))
+              S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, true,
+              ArgIdx, TDF))
         return Result;
     }
   }
@@ -3270,7 +3329,7 @@ static Sema::TemplateDeductionResult Ded
     Expr *Arg, TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
     SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
-    Optional<unsigned> ArgIdx, unsigned TDF) {
+    bool DecomposedParam, unsigned ArgIdx, unsigned TDF) {
   QualType ArgType = Arg->getType();
   QualType OrigParamType = ParamType;
 
@@ -3283,19 +3342,15 @@ static Sema::TemplateDeductionResult Ded
   //   If [...] the argument is a non-empty initializer list [...]
   if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg))
     return DeduceFromInitializerList(S, TemplateParams, ParamType, ILE, Info,
-                                     Deduced, OriginalCallArgs, TDF);
+                                     Deduced, OriginalCallArgs, ArgIdx, TDF);
 
   //   [...] the deduction process attempts to find template argument values
   //   that will make the deduced A identical to A
   //
   // Keep track of the argument type and corresponding parameter index,
   // so we can check for compatibility between the deduced A and A.
-  //
-  // FIXME: We are supposed to perform this check for the P/A pairs we extract
-  // from the initializer list case too.
-  if (ArgIdx)
-    OriginalCallArgs.push_back(
-        Sema::OriginalCallArg(OrigParamType, *ArgIdx, ArgType));
+  OriginalCallArgs.push_back(
+      Sema::OriginalCallArg(OrigParamType, DecomposedParam, ArgIdx, ArgType));
   return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
                                             ArgType, Info, Deduced, TDF);
 }
@@ -3388,7 +3443,7 @@ Sema::TemplateDeductionResult Sema::Dedu
     //   ... with the type of the corresponding argument
     return DeduceTemplateArgumentsFromCallArgument(
         *this, TemplateParams, ParamType, Args[ArgIdx], Info, Deduced,
-        OriginalCallArgs, ArgIdx, /*TDF*/ 0);
+        OriginalCallArgs, /*Decomposed*/false, ArgIdx, /*TDF*/ 0);
   };
 
   // Deduce template arguments from the function parameters.
@@ -4075,7 +4130,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr
     for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
       if (DeduceTemplateArgumentsFromCallArgument(
               *this, TemplateParamsSt.get(), TemplArg, InitList->getInit(i),
-              Info, Deduced, OriginalCallArgs, None, /*TDF*/0))
+              Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
+              /*ArgIdx*/ 0, /*TDF*/ 0))
         return DeductionFailed();
     }
   } else {
@@ -4086,7 +4142,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr
 
     if (DeduceTemplateArgumentsFromCallArgument(
             *this, TemplateParamsSt.get(), FuncParam, Init, Info, Deduced,
-            OriginalCallArgs, /*ArgIdx*/0, /*TDF*/0))
+            OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
       return DeductionFailed();
   }
 
@@ -4108,8 +4164,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr
 
   // Check that the deduced argument type is compatible with the original
   // argument type per C++ [temp.deduct.call]p4.
+  QualType DeducedA = InitList ? Deduced[0].getAsType() : Result;
   for (const OriginalCallArg &OriginalArg : OriginalCallArgs) {
-    if (CheckOriginalCallArgDeduction(*this, OriginalArg, Result)) {
+    assert((bool)InitList == OriginalArg.DecomposedParam &&
+           "decomposed non-init-list in auto deduction?");
+    if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
       Result = QualType();
       return DeductionFailed();
     }

Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=291190&r1=291189&r2=291190&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp Thu Jan  5 17:02:44 2017
@@ -105,6 +105,7 @@ T deduce_ref(const std::initializer_list
 
 template<typename T, typename U> struct pair { pair(...); };
 template<typename T> void deduce_pairs(std::initializer_list<pair<T, typename T::type>>);
+// expected-note at -1 {{deduced type 'pair<[...], typename WithIntType::type>' of element of 1st parameter does not match adjusted type 'pair<[...], float>' of element of argument [with T = WithIntType]}}
 struct WithIntType { typedef int type; };
 
 template<typename ...T> void deduce_after_init_list_in_pack(void (*)(T...), T...); // expected-note {{<int, int> vs. <(no value), double>}}
@@ -123,7 +124,7 @@ void argument_deduction() {
   pair<WithIntType, int> pi;
   pair<WithIntType, float> pf;
   deduce_pairs({pi, pi, pi}); // ok
-  deduce_pairs({pi, pf, pi}); // FIXME: This should be rejected, as we fail to produce a type that exactly matches the argument type.
+  deduce_pairs({pi, pf, pi}); // expected-error {{no matching function}}
 
   deduce_after_init_list_in_pack((void(*)(int,int))0, {}, 0);
   deduce_after_init_list_in_pack((void(*)(int,int))0, {}, 0.0); // expected-error {{no matching function}}
@@ -298,9 +299,18 @@ namespace TemporaryInitListSourceRange_P
 
 namespace ParameterPackNestedInitializerLists_PR23904c3 {
   template <typename ...T>
-  void f(std::initializer_list<std::initializer_list<T>> ...tt);
+  void f(std::initializer_list<std::initializer_list<T>> ...tt); // expected-note 2{{conflicting}} expected-note {{incomplete pack}}
 
-  void foo() { f({{0}}, {{'\0'}}); }
+  void foo() {
+    f({{0}}, {{'\0'}}); // ok, T = <int, char>
+    f({{0}, {'\0'}}); // expected-error {{no match}}
+    f({{0, '\0'}}); // expected-error {{no match}}
+
+    f({{0}}, {{{}}}); // expected-error {{no match}}
+    f({{0}}, {{{}, '\0'}}); // ok, T = <int, char>
+    f({{0}, {{}}}); // ok, T = <int>
+    f({{0, {}}}); // ok, T = <int>
+  }
 }
 
 namespace update_rbrace_loc_crash {




More information about the cfe-commits mailing list