diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Driver/Tools.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 85 |
4 files changed, 112 insertions, 10 deletions
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 8ed12d72b40..2a367bb29aa 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -6020,6 +6020,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_assume_sane_operator_new)) CmdArgs.push_back("-fno-assume-sane-operator-new"); + // -frelaxed-template-template-args is off by default, as it is a severe + // breaking change until a corresponding change to template partial ordering + // is provided. + if (Args.hasFlag(options::OPT_frelaxed_template_template_args, + options::OPT_fno_relaxed_template_template_args, false)) + CmdArgs.push_back("-frelaxed-template-template-args"); + // -fsized-deallocation is off by default, as it is an ABI-breaking change for // most platforms. if (Args.hasFlag(options::OPT_fsized_deallocation, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index ae4417c93c2..a0682e26e70 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1960,6 +1960,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (!Opts.NoBuiltin) getAllNoBuiltinFuncValues(Args, Opts.NoBuiltinFuncs); Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin); + Opts.RelaxedTemplateTemplateArgs = + Args.hasArg(OPT_frelaxed_template_template_args); Opts.SizedDeallocation = Args.hasArg(OPT_fsized_deallocation); Opts.AlignedAllocation = Args.hasFlag(OPT_faligned_allocation, OPT_fno_aligned_allocation, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index ec2f5988145..facc5d1b375 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -5585,6 +5585,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return Arg; } +static void DiagnoseTemplateParameterListArityMismatch( + Sema &S, TemplateParameterList *New, TemplateParameterList *Old, + Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc); + /// \brief Check a template argument against its corresponding /// template template parameter. /// @@ -5601,6 +5605,9 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, return false; } + if (Template->isInvalidDecl()) + return true; + // C++0x [temp.arg.template]p1: // A template-argument for a template template-parameter shall be // the name of a class template or an alias template, expressed as an @@ -5628,6 +5635,25 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, if (Param->isExpandedParameterPack()) Params = Param->getExpansionTemplateParameters(ArgumentPackIndex); + // C++1z [temp.arg.template]p3: (DR 150) + // A template-argument matches a template template-parameter P when P + // is at least as specialized as the template-argument A. + if (getLangOpts().RelaxedTemplateTemplateArgs) { + // Quick check for the common case: + // If P contains a parameter pack, then A [...] matches P if each of A's + // template parameters matches the corresponding template parameter in + // the template-parameter-list of P. + if (TemplateParameterListsAreEqual( + Template->getTemplateParameters(), Params, false, + TPL_TemplateTemplateArgumentMatch, Arg.getLocation())) + return false; + + if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, + Arg.getLocation())) + return false; + // FIXME: Produce better diagnostics for deduction failures. + } + return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Params, true, @@ -5839,7 +5865,7 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, return false; } - // Check that both are parameter packs are neither are parameter packs. + // Check that both are parameter packs or neither are parameter packs. // However, if we are matching a template template argument to a // template template parameter, the template template parameter can have // a parameter pack where the template template argument does not. diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index df796072f59..68b9853bdf6 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1898,11 +1898,11 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, return NumberOfArgumentsMustMatch ? Sema::TDK_TooFewArguments : Sema::TDK_Success; - if (Args[ArgIdx].isPackExpansion()) { - // FIXME: We follow the logic of C++0x [temp.deduct.type]p22 here, - // but applied to pack expansions that are template arguments. + // C++1z [temp.deduct.type]p9: + // During partial ordering, if Ai was originally a pack expansion [and] + // Pi is not a pack expansion, template argument deduction fails. + if (Args[ArgIdx].isPackExpansion()) return Sema::TDK_MiscellaneousDeductionFailure; - } // Perform deduction for this Pi/Ai pair. if (Sema::TemplateDeductionResult Result @@ -1965,7 +1965,8 @@ DeduceTemplateArguments(Sema &S, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced) { return DeduceTemplateArguments(S, TemplateParams, ParamList.asArray(), - ArgList.asArray(), Info, Deduced, false); + ArgList.asArray(), Info, Deduced, + /*NumberOfArgumentsMustMatch*/false); } /// \brief Determine whether two template arguments are the same. @@ -4581,13 +4582,13 @@ UnresolvedSetIterator Sema::getMostSpecialized( /// Determine whether one partial specialization, P1, is at least as /// specialized than another, P2. /// -/// \tparam PartialSpecializationDecl The kind of P2, which must be a -/// {Class,Var}Template{PartialSpecialization,}Decl. +/// \tparam TemplateLikeDecl The kind of P2, which must be a +/// TemplateDecl or {Class,Var}TemplatePartialSpecializationDecl. /// \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). -template<typename PartialSpecializationDecl> +template<typename TemplateLikeDecl> static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, - PartialSpecializationDecl *P2, + TemplateLikeDecl *P2, TemplateDeductionInfo &Info) { // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as @@ -4729,6 +4730,72 @@ bool Sema::isMoreSpecializedThanPrimary( return true; } +bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( + TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc) { + // C++1z [temp.arg.template]p4: (DR 150) + // A template template-parameter P is at least as specialized as a + // template template-argument A if, given the following rewrite to two + // function templates... + + // Rather than synthesize function templates, we merely perform the + // equivalent partial ordering by performing deduction directly on + // the template parameter lists of the template template parameters. + // + // Given an invented class template X with the template parameter list of + // A (including default arguments): + TemplateName X = Context.getCanonicalTemplateName(TemplateName(AArg)); + TemplateParameterList *A = AArg->getTemplateParameters(); + + // - Each function template has a single function parameter whose type is + // a specialization of X with template arguments corresponding to the + // template parameters from the respective function template + SmallVector<TemplateArgument, 8> AArgs; + Context.getInjectedTemplateArgs(A, AArgs); + + // Check P's arguments against A's parameter list. This will fill in default + // template arguments as needed. AArgs are already correct by construction. + // We can't just use CheckTemplateIdType because that will expand alias + // templates. + SmallVector<TemplateArgument, 4> PArgs; + { + SFINAETrap Trap(*this); + + Context.getInjectedTemplateArgs(P, PArgs); + TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); + for (unsigned I = 0, N = P->size(); I != N; ++I) { + // Unwrap packs that getInjectedTemplateArgs wrapped around pack + // expansions, to form an "as written" argument list. + TemplateArgument Arg = PArgs[I]; + if (Arg.getKind() == TemplateArgument::Pack) { + assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion()); + Arg = *Arg.pack_begin(); + } + PArgList.addArgument(getTrivialTemplateArgumentLoc( + Arg, QualType(), P->getParam(I)->getLocation())); + } + PArgs.clear(); + + // C++1z [temp.arg.template]p3: + // If the rewrite produces an invalid type, then P is not at least as + // specialized as A. + if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, PArgs) || + Trap.hasErrorOccurred()) + return false; + } + + QualType AType = Context.getTemplateSpecializationType(X, AArgs); + QualType PType = Context.getTemplateSpecializationType(X, PArgs); + + SmallVector<DeducedTemplateArgument, 4> Deduced; + Deduced.resize(A->size()); + + // ... the function template corresponding to P is at least as specialized + // as the function template corresponding to A according to the partial + // ordering rules for function templates. + TemplateDeductionInfo Info(Loc, A->getDepth()); + return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info); +} + static void MarkUsedTemplateParameters(ASTContext &Ctx, const TemplateArgument &TemplateArg, |