r290593 - DR1495: A partial specialization is ill-formed if it is not (strictly) more

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 27 12:11:05 PST 2016


Hi Eigen folks,

Clang (and GCC) recently implemented C++ DR 1495 (wg21.link/cwg1495), which
says that a class template partial specialization is ill-formed if it is
not more specialized than the primary template. (If we imagine the primary
template had a corresponding partial specialization, we require that the
partial specialization would always be chosen in any situation where both
match.)

This causes Clang to reject some code in Eigen:

https://bitbucket.org/eigen/eigen/src/e46c8246b284dea1690ac2
60dfe50851906138f0/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h?at=
default&fileviewer=file-view-default#TensorStorage.h-38

One way to fix this is:

-template<typename T, int Options_, typename FixedDimensions>
-class TensorStorage<T, FixedDimensions, Options_>
+template<typename T, typename FixedDimensions, int Options_>
+class TensorStorage

That is, define the primary template instead of defining a partial
specialization that doesn't actually specialize anything.

On 27 December 2016 at 10:41, Richard Smith <richard at metafoo.co.uk> wrote:

> On 27 Dec 2016 1:42 am, "Chandler Carruth via cfe-commits" <
> cfe-commits at lists.llvm.org> wrote:
>
> I suspect that this commit is responsible for a regression parsing widely
> used open source packages like Eigen.
>
> See the code in Eigen here:
> https://bitbucket.org/eigen/eigen/src/e46c8246b284dea1690ac2
> 60dfe50851906138f0/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h?at=
> default&fileviewer=file-view-default#TensorStorage.h-38
>
> I'm not claiming this code is correct, but I'm worried about how much code
> out there looks like this... Thoughts? Could we at least temporarily put
> this DR fix behind a flag or make it a warning?
>
>
> Sure, I'll downgrade it to an ExtWarn. We should also let the Eigen folks
> know.
>
> On Tue, Dec 27, 2016 at 12:07 AM Richard Smith via cfe-commits <
> cfe-commits at lists.llvm.org> wrote:
>
>> Author: rsmith
>> Date: Tue Dec 27 01:56:27 2016
>> New Revision: 290593
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=290593&view=rev
>> Log:
>> DR1495: A partial specialization is ill-formed if it is not (strictly)
>> more
>> specialized than the primary template. (Put another way, if we imagine
>> there
>> were a partial specialization matching the primary template, we should
>> never
>> select it if some other partial specialization also matches.)
>>
>> Modified:
>>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>     cfe/trunk/include/clang/Sema/Sema.h
>>     cfe/trunk/include/clang/Sema/TemplateDeduction.h
>>     cfe/trunk/lib/Sema/SemaTemplate.cpp
>>     cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
>>     cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
>>     cfe/trunk/test/CXX/drs/dr14xx.cpp
>>     cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
>>     cfe/trunk/test/SemaTemplate/class-template-spec.cpp
>>     cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
>>     cfe/trunk/www/cxx_dr_status.html
>>
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Basic/DiagnosticSemaKinds.td?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Dec 27
>> 01:56:27 2016
>> @@ -4043,6 +4043,10 @@ def err_partial_spec_args_match_primary_
>>      "%select{class|variable}0 template partial specialization does not "
>>      "specialize any template argument; to %select{declare|define}1 the "
>>      "primary template, remove the template argument list">;
>> +def err_partial_spec_not_more_specialized_than_primary : Error<
>> +    "%select{class|variable}0 template partial specialization is not "
>> +    "more specialized than the primary template">;
>> +def note_partial_spec_not_more_specialized_than_primary : Note<"%0">;
>>  def warn_partial_specs_not_deducible : Warning<
>>      "%select{class|variable}0 template partial specialization contains "
>>      "%select{a template parameter|template parameters}1 that cannot be "
>> @@ -4147,7 +4151,7 @@ def note_function_template_deduction_ins
>>    "%1">;
>>  def note_deduced_template_arg_substitution_here : Note<
>>    "during template argument deduction for %select{class|variable}0
>> template "
>> -  "partial specialization %1 %2">;
>> +  "%select{partial specialization |}1%2 %3">;
>>  def note_prior_template_arg_substitution : Note<
>>    "while substituting prior template arguments into
>> %select{non-type|template}0"
>>    " template parameter%1 %2">;
>>
>> Modified: cfe/trunk/include/clang/Sema/Sema.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Sema/Sema.h?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Sema/Sema.h (original)
>> +++ cfe/trunk/include/clang/Sema/Sema.h Tue Dec 27 01:56:27 2016
>> @@ -6697,10 +6697,16 @@ public:
>>                                    ClassTemplatePartialSpecializationDecl
>> *PS2,
>>                                    SourceLocation Loc);
>>
>> +  bool isMoreSpecializedThanPrimary(ClassTemplatePartialSpecializationDecl
>> *T,
>> +                                    sema::TemplateDeductionInfo &Info);
>> +
>>    VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpec
>> ialization(
>>        VarTemplatePartialSpecializationDecl *PS1,
>>        VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc);
>>
>> +  bool isMoreSpecializedThanPrimary(VarTemplatePartialSpecializationDecl
>> *T,
>> +                                    sema::TemplateDeductionInfo &Info);
>> +
>>    void MarkUsedTemplateParameters(const TemplateArgumentList
>> &TemplateArgs,
>>                                    bool OnlyDeduced,
>>                                    unsigned Depth,
>> @@ -6752,7 +6758,7 @@ public:
>>        /// template argument deduction for either a class template
>>        /// partial specialization or a function template. The
>>        /// Entity is either a {Class|Var}TemplatePartialSpecializationDecl
>> or
>> -      /// a FunctionTemplateDecl.
>> +      /// a TemplateDecl.
>>        DeducedTemplateArgumentSubstitution,
>>
>>        /// We are substituting prior template arguments into a new
>> @@ -6973,6 +6979,14 @@ public:
>>                            sema::TemplateDeductionInfo &DeductionInfo,
>>                            SourceRange InstantiationRange =
>> SourceRange());
>>
>> +    /// \brief Note that we are instantiating as part of template
>> +    /// argument deduction for a class template declaration.
>> +    InstantiatingTemplate(Sema &SemaRef, SourceLocation
>> PointOfInstantiation,
>> +                          TemplateDecl *Template,
>> +                          ArrayRef<TemplateArgument> TemplateArgs,
>> +                          sema::TemplateDeductionInfo &DeductionInfo,
>> +                          SourceRange InstantiationRange =
>> SourceRange());
>> +
>>      /// \brief Note that we are instantiating as part of template
>>      /// argument deduction for a class template partial
>>      /// specialization.
>>
>> Modified: cfe/trunk/include/clang/Sema/TemplateDeduction.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Sema/TemplateDeduction.h?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Sema/TemplateDeduction.h (original)
>> +++ cfe/trunk/include/clang/Sema/TemplateDeduction.h Tue Dec 27 01:56:27
>> 2016
>> @@ -79,6 +79,11 @@ public:
>>      assert(HasSFINAEDiagnostic);
>>      PD.first = SuppressedDiagnostics.front().first;
>>      PD.second.swap(SuppressedDiagnostics.front().second);
>> +    clearSFINAEDiagnostic();
>> +  }
>> +
>> +  /// \brief Discard any SFINAE diagnostics.
>> +  void clearSFINAEDiagnostic() {
>>      SuppressedDiagnostics.clear();
>>      HasSFINAEDiagnostic = false;
>>    }
>>
>> Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaT
>> emplate.cpp?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Dec 27 01:56:27 2016
>> @@ -2624,6 +2624,36 @@ makeTemplateArgumentListInfo(Sema &S, Te
>>    return TemplateArgs;
>>  }
>>
>> +template<typename PartialSpecDecl>
>> +static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl
>> *Partial) {
>> +  if (Partial->getDeclContext()->isDependentContext())
>> +    return;
>> +
>> +  // FIXME: Get the TDK from deduction in order to provide better
>> diagnostics
>> +  // for non-substitution-failure issues?
>> +  TemplateDeductionInfo Info(Partial->getLocation());
>> +  if (S.isMoreSpecializedThanPrimary(Partial, Info))
>> +    return;
>> +
>> +  auto *Template = Partial->getSpecializedTemplate();
>> +  S.Diag(Partial->getLocation(),
>> +         diag::err_partial_spec_not_more_specialized_than_primary)
>> +      << /*variable template*/isa<VarTemplateDecl>(Template);
>> +
>> +  if (Info.hasSFINAEDiagnostic()) {
>> +    PartialDiagnosticAt Diag = {SourceLocation(),
>> +                                PartialDiagnostic::NullDiagnostic()};
>> +    Info.takeSFINAEDiagnostic(Diag);
>> +    SmallString<128> SFINAEArgString;
>> +    Diag.second.EmitToString(S.getDiagnostics(), SFINAEArgString);
>> +    S.Diag(Diag.first,
>> +           diag::note_partial_spec_not_more_specialized_than_primary)
>> +      << SFINAEArgString;
>> +  }
>> +
>> +  S.Diag(Template->getLocation(), diag::note_template_decl_here);
>> +}
>> +
>>  DeclResult Sema::ActOnVarTemplateSpecialization(
>>      Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation
>> TemplateKWLoc,
>>      TemplateParameterList *TemplateParams, StorageClass SC,
>> @@ -2749,6 +2779,11 @@ DeclResult Sema::ActOnVarTemplateSpecial
>>      if (PrevPartial && PrevPartial->getInstantiatedFromMember())
>>        PrevPartial->setMemberSpecialization();
>>
>> +    // C++1z [temp.class.spec]p8: (DR1495)
>> +    //   - The specialization shall be more specialized than the primary
>> +    //     template (14.5.5.2).
>> +    checkMoreSpecializedThanPrimary(*this, Partial);
>> +
>>      // Check that all of the template parameters of the variable template
>>      // partial specialization are deducible from the template
>>      // arguments. If not, this variable template partial specialization
>> @@ -5041,7 +5076,7 @@ ExprResult Sema::CheckTemplateArgument(N
>>
>>    if (CTAK == CTAK_Deduced &&
>>        !Context.hasSameType(ParamType.getNonLValueExprType(Context),
>> -                           Arg->getType().getNonLValueExprType(Context)))
>> {
>> +                           Arg->getType())) {
>>      // C++ [temp.deduct.type]p17: (DR1770)
>>      //   If P has a form that contains <i>, and if the type of i differs
>> from
>>      //   the type of the corresponding template parameter of the
>> template named
>> @@ -5055,7 +5090,7 @@ ExprResult Sema::CheckTemplateArgument(N
>>      // itself, and so strip off references before comparing types. It's
>>      // not clear how this is supposed to work for references.
>>      Diag(StartLoc, diag::err_deduced_non_type_tem
>> plate_arg_type_mismatch)
>> -      << Arg->getType().getUnqualifiedType()
>> +      << Arg->getType()
>>        << ParamType.getUnqualifiedType();
>>      Diag(Param->getLocation(), diag::note_template_param_here);
>>      return ExprError();
>> @@ -6501,6 +6536,9 @@ Sema::ActOnClassTemplateSpecialization(S
>>        //
>>        //   -- The argument list of the specialization shall not be
>> identical
>>        //      to the implicit argument list of the primary template.
>> +      //
>> +      // This rule has since been removed, because it's redundant given
>> DR1495,
>> +      // but we keep it because it produces better diagnostics and
>> recovery.
>>        Diag(TemplateNameLoc, diag::err_partial_spec_args_ma
>> tch_primary_template)
>>          << /*class template*/0 << (TUK == TUK_Definition)
>>          << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
>> @@ -6543,6 +6581,11 @@ Sema::ActOnClassTemplateSpecialization(S
>>      if (PrevPartial && PrevPartial->getInstantiatedFromMember())
>>        PrevPartial->setMemberSpecialization();
>>
>> +    // C++1z [temp.class.spec]p8: (DR1495)
>> +    //   - The specialization shall be more specialized than the primary
>> +    //     template (14.5.5.2).
>> +    checkMoreSpecializedThanPrimary(*this, Partial);
>> +
>>      // Check that all of the template parameters of the class template
>>      // partial specialization are deducible from the template
>>      // arguments. If not, this class template partial specialization
>>
>> Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaT
>> emplateDeduction.cpp?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Tue Dec 27 01:56:27 2016
>> @@ -1972,8 +1972,14 @@ DeduceTemplateArguments(Sema &S,
>>
>>  /// \brief Determine whether two template arguments are the same.
>>  static bool isSameTemplateArg(ASTContext &Context,
>> -                              const TemplateArgument &X,
>> -                              const TemplateArgument &Y) {
>> +                              TemplateArgument X,
>> +                              const TemplateArgument &Y,
>> +                              bool PackExpansionMatchesPack = false) {
>> +  // If we're checking deduced arguments (X) against original arguments
>> (Y),
>> +  // we will have flattened packs to non-expansions in X.
>> +  if (PackExpansionMatchesPack && X.isPackExpansion() &&
>> !Y.isPackExpansion())
>> +    X = X.getPackExpansionPattern();
>> +
>>    if (X.getKind() != Y.getKind())
>>      return false;
>>
>> @@ -2016,7 +2022,7 @@ static bool isSameTemplateArg(ASTContext
>>                                          XPEnd = X.pack_end(),
>>                                             YP = Y.pack_begin();
>>             XP != XPEnd; ++XP, ++YP)
>> -        if (!isSameTemplateArg(Context, *XP, *YP))
>> +        if (!isSameTemplateArg(Context, *XP, *YP,
>> PackExpansionMatchesPack))
>>            return false;
>>
>>        return true;
>> @@ -2400,6 +2406,48 @@ FinishTemplateArgumentDeduction(
>>    return Sema::TDK_Success;
>>  }
>>
>> +/// Complete template argument deduction for a class or variable
>> template,
>> +/// when partial ordering against a partial specialization.
>> +// FIXME: Factor out duplication with partial specialization version
>> above.
>> +Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
>> +    Sema &S, TemplateDecl *Template, bool PartialOrdering,
>> +    const TemplateArgumentList &TemplateArgs,
>> +    SmallVectorImpl<DeducedTemplateArgument> &Deduced,
>> +    TemplateDeductionInfo &Info) {
>> +  // Unevaluated SFINAE context.
>> +  EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
>> +  Sema::SFINAETrap Trap(S);
>> +
>> +  Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Te
>> mplate));
>> +
>> +  // C++ [temp.deduct.type]p2:
>> +  //   [...] or if any template argument remains neither deduced nor
>> +  //   explicitly specified, template argument deduction fails.
>> +  SmallVector<TemplateArgument, 4> Builder;
>> +  if (auto Result = ConvertDeducedTemplateArguments(
>> +          S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info,
>> Builder))
>> +    return Result;
>> +
>> +  // Check that we produced the correct argument list.
>> +  TemplateParameterList *TemplateParams = Template->getTemplateParameter
>> s();
>> +  for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
>> +    TemplateArgument InstArg = Builder[I];
>> +    if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg,
>> +                           /*PackExpansionMatchesPack*/true)) {
>> +      Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
>> +      Info.FirstArg = TemplateArgs[I];
>> +      Info.SecondArg = InstArg;
>> +      return Sema::TDK_NonDeducedMismatch;
>> +    }
>> +  }
>> +
>> +  if (Trap.hasErrorOccurred())
>> +    return Sema::TDK_SubstitutionFailure;
>> +
>> +  return Sema::TDK_Success;
>> +}
>> +
>> +
>>  /// \brief Perform template argument deduction to determine whether
>>  /// the given template arguments match the given class template
>>  /// partial specialization per C++ [temp.class.spec.match].
>> @@ -4535,14 +4583,13 @@ UnresolvedSetIterator Sema::getMostSpeci
>>  /// specialized than another, P2.
>>  ///
>>  /// \tparam PartialSpecializationDecl The kind of P2, which must be a
>> -/// {Class,Var}TemplatePartialSpecializationDecl.
>> +/// {Class,Var}Template{PartialSpecialization,}Decl.
>>  /// \param T1 The injected-class-name of P1 (faked for a variable
>> template).
>>  /// \param T2 The injected-class-name of P2 (faked for a variable
>> template).
>> -/// \param Loc The location at which the comparison is required.
>>  template<typename PartialSpecializationDecl>
>>  static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
>>                                       PartialSpecializationDecl *P2,
>> -                                     SourceLocation Loc) {
>> +                                     TemplateDeductionInfo &Info) {
>>    // C++ [temp.class.order]p1:
>>    //   For two class template partial specializations, the first is at
>> least as
>>    //   specialized as the second if, given the following rewrite to two
>> @@ -4568,7 +4615,6 @@ static bool isAtLeastAsSpecializedAs(Sem
>>    // template partial specialization's template arguments, for
>>    // example.
>>    SmallVector<DeducedTemplateArgument, 4> Deduced;
>> -  TemplateDeductionInfo Info(Loc);
>>
>>    // Determine whether P1 is at least as specialized as P2.
>>    Deduced.resize(P2->getTemplateParameters()->size());
>> @@ -4579,7 +4625,8 @@ static bool isAtLeastAsSpecializedAs(Sem
>>
>>    SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
>>                                                 Deduced.end());
>> -  Sema::InstantiatingTemplate Inst(S, Loc, P2, DeducedArgs, Info);
>> +  Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2,
>> DeducedArgs,
>> +                                   Info);
>>    auto *TST1 = T1->castAs<TemplateSpecializationType>();
>>    if (FinishTemplateArgumentDeduction(
>>            S, P2, /*PartialOrdering=*/true,
>> @@ -4609,8 +4656,9 @@ Sema::getMoreSpecializedPartialSpecializ
>>    QualType PT1 = PS1->getInjectedSpecializationType();
>>    QualType PT2 = PS2->getInjectedSpecializationType();
>>
>> -  bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Loc);
>> -  bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Loc);
>> +  TemplateDeductionInfo Info(Loc);
>> +  bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
>> +  bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
>>
>>    if (Better1 == Better2)
>>      return nullptr;
>> @@ -4618,6 +4666,20 @@ Sema::getMoreSpecializedPartialSpecializ
>>    return Better1 ? PS1 : PS2;
>>  }
>>
>> +bool Sema::isMoreSpecializedThanPrimary(
>> +    ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo
>> &Info) {
>> +  ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
>> +  QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
>> +  QualType PartialT = Spec->getInjectedSpecializationType();
>> +  if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary,
>> Info))
>> +    return false;
>> +  if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
>> +    Info.clearSFINAEDiagnostic();
>> +    return false;
>> +  }
>> +  return true;
>> +}
>> +
>>  VarTemplatePartialSpecializationDecl *
>>  Sema::getMoreSpecializedPartialSpecialization(
>>      VarTemplatePartialSpecializationDecl *PS1,
>> @@ -4634,8 +4696,9 @@ Sema::getMoreSpecializedPartialSpecializ
>>    QualType PT2 = Context.getTemplateSpecializationType(
>>        CanonTemplate, PS2->getTemplateArgs().asArray());
>>
>> -  bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Loc);
>> -  bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Loc);
>> +  TemplateDeductionInfo Info(Loc);
>> +  bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
>> +  bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
>>
>>    if (Better1 == Better2)
>>      return nullptr;
>> @@ -4643,6 +4706,30 @@ Sema::getMoreSpecializedPartialSpecializ
>>    return Better1 ? PS1 : PS2;
>>  }
>>
>> +bool Sema::isMoreSpecializedThanPrimary(
>> +    VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo
>> &Info) {
>> +  TemplateDecl *Primary = Spec->getSpecializedTemplate();
>> +  // FIXME: Cache the injected template arguments rather than recomputing
>> +  // them for each partial specialization.
>> +  SmallVector<TemplateArgument, 8> PrimaryArgs;
>> +  Context.getInjectedTemplateArgs(Primary->getTemplateParameters(),
>> +                                  PrimaryArgs);
>> +
>> +  TemplateName CanonTemplate =
>> +      Context.getCanonicalTemplateName(TemplateName(Primary));
>> +  QualType PrimaryT = Context.getTemplateSpecializationType(
>> +      CanonTemplate, PrimaryArgs);
>> +  QualType PartialT = Context.getTemplateSpecializationType(
>> +      CanonTemplate, Spec->getTemplateArgs().asArray());
>> +  if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary,
>> Info))
>> +    return false;
>> +  if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
>> +    Info.clearSFINAEDiagnostic();
>> +    return false;
>> +  }
>> +  return true;
>> +}
>> +
>>  static void
>>  MarkUsedTemplateParameters(ASTContext &Ctx,
>>                             const TemplateArgument &TemplateArg,
>>
>> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaT
>> emplateInstantiate.cpp?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Dec 27 01:56:27
>> 2016
>> @@ -279,6 +279,17 @@ Sema::InstantiatingTemplate::Instantiati
>>
>>  Sema::InstantiatingTemplate::InstantiatingTemplate(
>>      Sema &SemaRef, SourceLocation PointOfInstantiation,
>> +    TemplateDecl *Template,
>> +    ArrayRef<TemplateArgument> TemplateArgs,
>> +    sema::TemplateDeductionInfo &DeductionInfo, SourceRange
>> InstantiationRange)
>> +    : InstantiatingTemplate(
>> +          SemaRef,
>> +          ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitu
>> tion,
>> +          PointOfInstantiation, InstantiationRange, Template, nullptr,
>> +          TemplateArgs, &DeductionInfo) {}
>> +
>> +Sema::InstantiatingTemplate::InstantiatingTemplate(
>> +    Sema &SemaRef, SourceLocation PointOfInstantiation,
>>      ClassTemplatePartialSpecializationDecl *PartialSpec,
>>      ArrayRef<TemplateArgument> TemplateArgs,
>>      sema::TemplateDeductionInfo &DeductionInfo, SourceRange
>> InstantiationRange)
>> @@ -497,8 +508,12 @@ void Sema::PrintInstantiationStack() {
>>        } else {
>>          bool IsVar = isa<VarTemplateDecl>(Active->Entity) ||
>>                       isa<VarTemplateSpecializationDecl>(Active->Entity);
>> +        bool IsTemplate = false;
>>          TemplateParameterList *Params;
>> -        if (auto *D = dyn_cast<ClassTemplatePartialSpecializationDecl>(
>> +        if (auto *D = dyn_cast<TemplateDecl>(Active->Entity)) {
>> +          IsTemplate = true;
>> +          Params = D->getTemplateParameters();
>> +        } else if (auto *D = dyn_cast<ClassTemplatePartialS
>> pecializationDecl>(
>>                         Active->Entity)) {
>>            Params = D->getTemplateParameters();
>>          } else if (auto *D = dyn_cast<VarTemplatePartialSpe
>> cializationDecl>(
>> @@ -510,7 +525,7 @@ void Sema::PrintInstantiationStack() {
>>
>>          Diags.Report(Active->PointOfInstantiation,
>>                       diag::note_deduced_template_arg_substitution_here)
>> -          << IsVar << cast<NamedDecl>(Active->Entity)
>> +          << IsVar << IsTemplate << cast<NamedDecl>(Active->Entity)
>>            << getTemplateArgumentBindingsText(Params,
>> Active->TemplateArgs,
>>                                               Active->NumTemplateArgs)
>>            << Active->InstantiationRange;
>>
>> Modified: cfe/trunk/test/CXX/drs/dr14xx.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/
>> dr14xx.cpp?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/test/CXX/drs/dr14xx.cpp (original)
>> +++ cfe/trunk/test/CXX/drs/dr14xx.cpp Tue Dec 27 01:56:27 2016
>> @@ -342,4 +342,32 @@ namespace dr1490 {  // dr1490: 3.7 c++11
>>    char s[4]{"abc"};                   // Ok
>>    std::initializer_list<char>{"abc"}; // expected-error {{expected
>> unqualified-id}}}
>>  } // dr190
>> +
>> +namespace dr1495 { // dr1495: 4.0
>> +  // Deduction succeeds in both directions.
>> +  template<typename T, typename U> struct A {}; // expected-note
>> {{template is declared here}}
>> +  template<typename T, typename U> struct A<U, T> {}; // expected-error
>> {{class template partial specialization is not more specialized}}
>> +
>> +  // Primary template is more specialized.
>> +  template<typename, typename...> struct B {}; // expected-note
>> {{template is declared here}}
>> +  template<typename ...Ts> struct B<Ts...> {}; // expected-error {{not
>> more specialized}}
>> +
>> +  // Deduction fails in both directions.
>> +  template<int, typename, typename ...> struct C {}; // expected-note
>> {{template is declared here}}
>> +  template<typename ...Ts> struct C<0, Ts...> {}; // expected-error
>> {{not more specialized}}
>> +
>> +#if __cplusplus >= 201402L
>> +  // Deduction succeeds in both directions.
>> +  template<typename T, typename U> int a; // expected-note {{template is
>> declared here}}
>> +  template<typename T, typename U> int a<U, T>; // expected-error
>> {{variable template partial specialization is not more specialized}}
>> +
>> +  // Primary template is more specialized.
>> +  template<typename, typename...> int b; // expected-note {{template is
>> declared here}}
>> +  template<typename ...Ts> int b<Ts...>; // expected-error {{not more
>> specialized}}
>> +
>> +  // Deduction fails in both directions.
>> +  template<int, typename, typename ...> int c; // expected-note
>> {{template is declared here}}
>> +  template<typename ...Ts> int c<0, Ts...>; // expected-error {{not more
>> specialized}}
>> +#endif
>> +}
>>  #endif
>>
>> Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expan
>> sion.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/
>> temp.decls/temp.variadic/fixed-expansion.cpp?rev=290593&r1=
>> 290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
>> (original)
>> +++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
>> Tue Dec 27 01:56:27 2016
>> @@ -108,10 +108,10 @@ namespace PR9021b {
>>
>>  namespace PartialSpecialization {
>>    template<typename T, typename U, typename V = U>
>> -  struct X0; // expected-note{{template is declared here}}
>> +  struct X0; // expected-note 2{{template is declared here}}
>>
>>    template<typename ...Ts>
>> -  struct X0<Ts...> {
>> +  struct X0<Ts...> { // expected-error {{class template partial
>> specialization is not more specialized than the primary template}}
>>    };
>>
>>    X0<int> x0i; // expected-error{{too few template arguments for class
>> template 'X0'}}
>>
>> Modified: cfe/trunk/test/SemaTemplate/class-template-spec.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTempl
>> ate/class-template-spec.cpp?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
>> +++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Tue Dec 27
>> 01:56:27 2016
>> @@ -167,10 +167,16 @@ namespace PR16519 {
>>    // expected-warning at -2 {{variadic templates are a C++11 extension}}
>>  #endif
>>
>> -  template<typename T, T ...N, T ...Extra> struct
>> __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> {
>> +  // Note that the following seemingly-equivalent template parameter
>> list is
>> +  // not OK; it would result in a partial specialization that is not more
>> +  // specialized than the primary template. (See NTTPTypeVsPartialOrder
>> below.)
>> +  //
>> +  //    template<typename T, T ...N, T ...Extra>
>> +  template<typename T, T ...N, typename integer_sequence<T,
>> N...>::value_type ...Extra>
>>  #if __cplusplus <= 199711L
>> -  // expected-warning at -2 2 {{variadic templates are a C++11 extension}}
>> +  // expected-warning at -2 2{{variadic templates are a C++11 extension}}
>>  #endif
>> +  struct __make_integer_sequence_impl<integer_sequence<T, N...>,
>> Extra...> {
>>      typedef integer_sequence<T, N..., sizeof...(N) + N..., Extra...>
>> type;
>>    };
>>
>> @@ -193,6 +199,25 @@ namespace PR16519 {
>>  #endif
>>  }
>>
>> +namespace NTTPTypeVsPartialOrder {
>> +  struct X { typedef int value_type; };
>> +  template<typename T> struct Y { typedef T value_type; };
>> +
>> +  template<typename T, typename T::value_type N> struct A; //
>> expected-note {{template}}
>> +  template<int N> struct A<X, N> {};
>> +  template<typename T, T N> struct A<Y<T>, N> {}; // expected-error
>> {{not more specialized}} expected-note {{'T' vs 'typename
>> Y<type-parameter-0-0>::value_type'}}
>> +  A<X, 0> ax;
>> +  A<Y<int>, 0> ay;
>> +
>> +
>> +  template<int, typename T, typename T::value_type> struct B; //
>> expected-note {{template}}
>> +  template<typename T, typename T::value_type N> struct B<0, T, N>; //
>> expected-note {{matches}}
>> +  template<int N> struct B<0, X, N> {};
>> +  template<typename T, T N> struct B<0, Y<T>, N> {}; // expected-error
>> {{not more specialized}} expected-note {{'T' vs 'typename
>> Y<type-parameter-0-0>::value_type'}} expected-note {{matches}}
>> +  B<0, X, 0> bx;
>> +  B<0, Y<int>, 0> by; // expected-error {{ambiguous}}
>> +}
>> +
>>  namespace DefaultArgVsPartialSpec {
>>    // Check that the diagnostic points at the partial specialization, not
>> just at
>>    // the default argument.
>>
>> Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTempl
>> ate/temp_arg_nontype.cpp?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original)
>> +++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Tue Dec 27 01:56:27
>> 2016
>> @@ -367,11 +367,11 @@ namespace PR17696 {
>>
>>  namespace partial_order_different_types {
>>    // These are unordered because the type of the final argument doesn't
>> match.
>> -  // FIXME: The second partial specialization should actually be rejected
>> -  // because it's not more specialized than the primary template.
>> -  template<int, int, typename T, typename, T> struct A;
>> +  template<int, int, typename T, typename, T> struct A; // expected-note
>> {{here}}
>>    template<int N, typename T, typename U, T V> struct A<0, N, T, U, V>
>> {}; // expected-note {{matches}}
>>    template<typename T, typename U, U V> struct A<0, 0, T, U, V> {}; //
>> expected-note {{matches}}
>> +  // expected-error at -1 {{not more specialized than the primary}}
>> +  // expected-note at -2 {{deduced non-type template argument does not
>> have the same type as the corresponding template parameter ('U' vs
>> 'type-parameter-0-0')}}
>>    A<0, 0, int, int, 0> a; // expected-error {{ambiguous partial
>> specializations}}
>>  }
>>
>> @@ -389,18 +389,22 @@ namespace partial_order_references {
>>    int N;
>>    A<0, 0, N> a;
>>
>> -  // FIXME: These should all be rejected as they are not more
>> specialized than
>> -  // the primary template (they can never be used due to the type
>> mismatch).
>> -  template<int, int &R> struct B; // expected-note {{template}}
>> +  template<int, int &R> struct B; // expected-note 2{{template}}
>>    template<const int &R> struct B<0, R> {};
>> +  // expected-error at -1 {{not more specialized than the primary}}
>> +  // expected-note at -2 {{'const int' vs 'int &'}}
>>    B<0, N> b; // expected-error {{undefined}}
>>
>> -  template<int, const int &R> struct C; // expected-note {{template}}
>> +  template<int, const int &R> struct C; // expected-note 2{{template}}
>>    template<int &R> struct C<0, R> {};
>> +  // expected-error at -1 {{not more specialized than the primary}}
>> +  // expected-note at -2 {{'int' vs 'const int &'}}
>>    C<0, N> c; // expected-error {{undefined}}
>>
>> -  template<int, const int &R> struct D; // expected-note {{template}}
>> +  template<int, const int &R> struct D; // expected-note 2{{template}}
>>    template<int N> struct D<0, N> {};
>> +  // expected-error at -1 {{not more specialized than the primary}}
>> +  // expected-note at -2 {{'int' vs 'const int &'}}
>>    extern const int K = 5;
>>    D<0, K> d; // expected-error {{undefined}}
>>  }
>>
>> Modified: cfe/trunk/www/cxx_dr_status.html
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_sta
>> tus.html?rev=290593&r1=290592&r2=290593&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/www/cxx_dr_status.html (original)
>> +++ cfe/trunk/www/cxx_dr_status.html Tue Dec 27 01:56:27 2016
>> @@ -4195,7 +4195,7 @@ and <I>POD class</I></td>
>>      <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defect
>> s.html#692">692</a></td>
>>      <td>C++11</td>
>>      <td>Partial ordering of variadic class template partial
>> specializations</td>
>> -    <td class="none" align="center">Unknown</td>
>> +    <td class="none" align="center">No</td>
>>    </tr>
>>    <tr id="693">
>>      <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defect
>> s.html#693">693</a></td>
>> @@ -8785,7 +8785,7 @@ and <I>POD class</I></td>
>>      <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defect
>> s.html#1495">1495</a></td>
>>      <td>CD3</td>
>>      <td>Partial specialization of variadic class template</td>
>> -    <td class="none" align="center">Unknown</td>
>> +    <td class="svn" align="center">SVN</td>
>>    </tr>
>>    <tr id="1496">
>>      <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defect
>> s.html#1496">1496</a></td>
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20161227/6b8af8d4/attachment-0001.html>


More information about the cfe-commits mailing list