diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 13 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 275 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 27 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.class.spec/p9.cpp | 26 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.variadic/deduction.cpp | 25 |
6 files changed, 244 insertions, 130 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c11ab161a5..5235607468 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3011,7 +3011,7 @@ public: bool CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, - TemplateDecl *Template, + NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, llvm::SmallVectorImpl<TemplateArgument> &Converted, @@ -3557,9 +3557,10 @@ public: /// \brief The point of instantiation within the source code. SourceLocation PointOfInstantiation; - /// \brief The template in which we are performing the instantiation, - /// for substitutions of prior template arguments. - TemplateDecl *Template; + /// \brief The template (or partial specialization) in which we are + /// performing the instantiation, for substitutions of prior template + /// arguments. + NamedDecl *Template; /// \brief The entity that is being instantiated. uintptr_t Entity; @@ -3745,14 +3746,14 @@ public: /// \brief Note that we are substituting prior template arguments into a /// non-type or template template parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, + NamedDecl *Template, NonTypeTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange); InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, + NamedDecl *Template, TemplateTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 1835899e80..419f59d588 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2160,7 +2160,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, /// template parameter. bool Sema::CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, - TemplateDecl *Template, + NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, llvm::SmallVectorImpl<TemplateArgument> &Converted, @@ -3940,6 +3940,10 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, // We can have a pack expansion of any of the bullets below. if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(ArgExpr)) ArgExpr = Expansion->getPattern(); + + // Strip off any implicit casts we added as part of type checking. + while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr)) + ArgExpr = ICE->getSubExpr(); // C++ [temp.class.spec]p8: // A non-type argument is non-specialized if it is the name of a @@ -3950,7 +3954,7 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, // specialized non-type arguments, so skip any non-specialized // arguments. if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) - if (llvm::isa<NonTypeTemplateParmDecl>(DRE->getDecl())) + if (isa<NonTypeTemplateParmDecl>(DRE->getDecl())) continue; // C++ [temp.class.spec]p9: diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 3c3f3d7889..09bfcf5c46 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1314,6 +1314,114 @@ static bool isSameTemplateArg(ASTContext &Context, return false; } +/// \brief Allocate a TemplateArgumentLoc where all locations have +/// been initialized to the given location. +/// +/// \param S The semantic analysis object. +/// +/// \param The template argument we are producing template argument +/// location information for. +/// +/// \param NTTPType For a declaration template argument, the type of +/// the non-type template parameter that corresponds to this template +/// argument. +/// +/// \param Loc The source location to use for the resulting template +/// argument. +static TemplateArgumentLoc +getTrivialTemplateArgumentLoc(Sema &S, + const TemplateArgument &Arg, + QualType NTTPType, + SourceLocation Loc) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Can't get a NULL template argument here"); + break; + + case TemplateArgument::Type: + return TemplateArgumentLoc(Arg, + S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); + + case TemplateArgument::Declaration: { + Expr *E + = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .takeAs<Expr>(); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case TemplateArgument::Integral: { + Expr *E + = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>(); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case TemplateArgument::Template: + return TemplateArgumentLoc(Arg, SourceRange(), Loc); + + case TemplateArgument::Expression: + return TemplateArgumentLoc(Arg, Arg.getAsExpr()); + + case TemplateArgument::Pack: + return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); + } + + return TemplateArgumentLoc(); +} + + +/// \brief Convert the given deduced template argument and add it to the set of +/// fully-converted template arguments. +static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, + DeducedTemplateArgument Arg, + NamedDecl *Template, + QualType NTTPType, + TemplateDeductionInfo &Info, + bool InFunctionTemplate, + llvm::SmallVectorImpl<TemplateArgument> &Output) { + if (Arg.getKind() == TemplateArgument::Pack) { + // This is a template argument pack, so check each of its arguments against + // the template parameter. + llvm::SmallVector<TemplateArgument, 2> PackedArgsBuilder; + for (TemplateArgument::pack_iterator PA = Arg.pack_begin(), + PAEnd = Arg.pack_end(); + PA != PAEnd; ++PA) { + DeducedTemplateArgument InnerArg(*PA); + InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound()); + if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template, + NTTPType, Info, + InFunctionTemplate, PackedArgsBuilder)) + return true; + } + + // Create the resulting argument pack. + TemplateArgument *PackedArgs = 0; + if (!PackedArgsBuilder.empty()) { + PackedArgs = new (S.Context) TemplateArgument[PackedArgsBuilder.size()]; + std::copy(PackedArgsBuilder.begin(), PackedArgsBuilder.end(), PackedArgs); + } + Output.push_back(TemplateArgument(PackedArgs, PackedArgsBuilder.size())); + return false; + } + + // Convert the deduced template argument into a template + // argument that we can check, almost as if the user had written + // the template argument explicitly. + TemplateArgumentLoc ArgLoc = getTrivialTemplateArgumentLoc(S, Arg, NTTPType, + Info.getLocation()); + + // Check the template argument, converting it as necessary. + return S.CheckTemplateArgument(Param, ArgLoc, + Template, + Template->getLocation(), + Template->getSourceRange().getEnd(), + Output, + InFunctionTemplate + ? (Arg.wasDeducedFromArrayBound() + ? Sema::CTAK_DeducedFromArrayBound + : Sema::CTAK_Deduced) + : Sema::CTAK_Specified); +} + /// Complete template argument deduction for a class template partial /// specialization. static Sema::TemplateDeductionResult @@ -1333,12 +1441,32 @@ FinishTemplateArgumentDeduction(Sema &S, llvm::SmallVector<TemplateArgument, 4> Builder; TemplateParameterList *PartialParams = Partial->getTemplateParameters(); for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) { + NamedDecl *Param = PartialParams->getParam(I); if (Deduced[I].isNull()) { - Info.Param = makeTemplateParameter(PartialParams->getParam(I)); + Info.Param = makeTemplateParameter(Param); return Sema::TDK_Incomplete; } - Builder.push_back(Deduced[I]); + // We have deduced this argument, so it still needs to be + // checked and converted. + + // First, for a non-type template parameter type that is + // initialized by a declaration, we need the type of the + // corresponding non-type template parameter. + QualType NTTPType; + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) + NTTPType = NTTP->getType(); + + if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], + Partial, NTTPType, Info, false, + Builder)) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + Builder.size())); + return Sema::TDK_SubstitutionFailure; + } } // Form the template argument list from the deduced template arguments. @@ -1380,23 +1508,39 @@ FinishTemplateArgumentDeduction(Sema &S, llvm::SmallVector<TemplateArgument, 4> ConvertedInstArgs; if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), - InstArgs, false, ConvertedInstArgs)) + InstArgs, false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; - for (unsigned I = 0, E = ConvertedInstArgs.size(); I != E; ++I) { + TemplateParameterList *TemplateParams + = ClassTemplate->getTemplateParameters(); + for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { TemplateArgument InstArg = ConvertedInstArgs.data()[I]; - Decl *Param = const_cast<NamedDecl *>( - ClassTemplate->getTemplateParameters()->getParam(I)); + Decl *Param = TemplateParams->getParam(I); - if (InstArg.getKind() == TemplateArgument::Expression) { + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { // When the argument is an expression, check the expression result // against the actual template parameter to get down to the canonical // template argument. - // FIXME: Variadic templates. - Expr *InstExpr = InstArg.getAsExpr(); - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + Expr *InstExpr = 0; + if (InstArg.getKind() == TemplateArgument::Expression) + InstExpr = InstArg.getAsExpr(); + else if (InstArg.getKind() == TemplateArgument::Integral) { + ExprResult InstExprFromArg + = S.BuildExpressionFromIntegralTemplateArgument(InstArg, + Info.getLocation()); + if (InstExprFromArg.isInvalid()) { + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = InstArg; + return Sema::TDK_SubstitutionFailure; + } + + InstExpr = InstExprFromArg.get(); + } + + if (InstExpr) { + // FIXME: Variadic templates. if (S.CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = Partial->getTemplateArgs()[I]; @@ -1615,109 +1759,6 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_Success; } -/// \brief Allocate a TemplateArgumentLoc where all locations have -/// been initialized to the given location. -/// -/// \param S The semantic analysis object. -/// -/// \param The template argument we are producing template argument -/// location information for. -/// -/// \param NTTPType For a declaration template argument, the type of -/// the non-type template parameter that corresponds to this template -/// argument. -/// -/// \param Loc The source location to use for the resulting template -/// argument. -static TemplateArgumentLoc -getTrivialTemplateArgumentLoc(Sema &S, - const TemplateArgument &Arg, - QualType NTTPType, - SourceLocation Loc) { - switch (Arg.getKind()) { - case TemplateArgument::Null: - llvm_unreachable("Can't get a NULL template argument here"); - break; - - case TemplateArgument::Type: - return TemplateArgumentLoc(Arg, - S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); - - case TemplateArgument::Declaration: { - Expr *E - = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) - .takeAs<Expr>(); - return TemplateArgumentLoc(TemplateArgument(E), E); - } - - case TemplateArgument::Integral: { - Expr *E - = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>(); - return TemplateArgumentLoc(TemplateArgument(E), E); - } - - case TemplateArgument::Template: - return TemplateArgumentLoc(Arg, SourceRange(), Loc); - - case TemplateArgument::Expression: - return TemplateArgumentLoc(Arg, Arg.getAsExpr()); - - case TemplateArgument::Pack: - return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); - } - - return TemplateArgumentLoc(); -} - -/// \brief Convert the given deduced template argument and add it to the set of -/// fully-converted template arguments. -static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, - DeducedTemplateArgument Arg, - FunctionTemplateDecl *FunctionTemplate, - QualType NTTPType, - TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<TemplateArgument> &Output) { - if (Arg.getKind() == TemplateArgument::Pack) { - // This is a template argument pack, so check each of its arguments against - // the template parameter. - llvm::SmallVector<TemplateArgument, 2> PackedArgsBuilder; - for (TemplateArgument::pack_iterator PA = Arg.pack_begin(), - PAEnd = Arg.pack_end(); - PA != PAEnd; ++PA) { - DeducedTemplateArgument InnerArg(*PA); - InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound()); - if (ConvertDeducedTemplateArgument(S, Param, InnerArg, FunctionTemplate, - NTTPType, Info, PackedArgsBuilder)) - return true; - } - - // Create the resulting argument pack. - TemplateArgument *PackedArgs = 0; - if (!PackedArgsBuilder.empty()) { - PackedArgs = new (S.Context) TemplateArgument[PackedArgsBuilder.size()]; - std::copy(PackedArgsBuilder.begin(), PackedArgsBuilder.end(), PackedArgs); - } - Output.push_back(TemplateArgument(PackedArgs, PackedArgsBuilder.size())); - return false; - } - - // Convert the deduced template argument into a template - // argument that we can check, almost as if the user had written - // the template argument explicitly. - TemplateArgumentLoc ArgLoc = getTrivialTemplateArgumentLoc(S, Arg, NTTPType, - Info.getLocation()); - - // Check the template argument, converting it as necessary. - return S.CheckTemplateArgument(Param, ArgLoc, - FunctionTemplate, - FunctionTemplate->getLocation(), - FunctionTemplate->getSourceRange().getEnd(), - Output, - Arg.wasDeducedFromArrayBound() - ? Sema::CTAK_DeducedFromArrayBound - : Sema::CTAK_Deduced); -} - /// \brief Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. @@ -1791,7 +1832,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I], FunctionTemplate, NTTPType, Info, - Builder)) { + true, Builder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), @@ -2953,6 +2994,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E)) E = Expansion->getPattern(); + // Skip through any implicit casts we added while type-checking. + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + E = ICE->getSubExpr(); + // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to // find other occurrences of template parameters. const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 16500d4207..5d724f3b70 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -263,7 +263,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, + NamedDecl *Template, NonTypeTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, @@ -286,7 +286,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, + NamedDecl *Template, TemplateTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, @@ -490,13 +490,19 @@ void Sema::PrintInstantiationStack() { std::string Name; if (!Parm->getName().empty()) Name = std::string(" '") + Parm->getName().str() + "'"; - + + TemplateParameterList *TemplateParams = 0; + if (TemplateDecl *Template = dyn_cast<TemplateDecl>(Active->Template)) + TemplateParams = Template->getTemplateParameters(); + else + TemplateParams = + cast<ClassTemplatePartialSpecializationDecl>(Active->Template) + ->getTemplateParameters(); Diags.Report(Active->PointOfInstantiation, diag::note_prior_template_arg_substitution) << isa<TemplateTemplateParmDecl>(Parm) << Name - << getTemplateArgumentBindingsText( - Active->Template->getTemplateParameters(), + << getTemplateArgumentBindingsText(TemplateParams, Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; @@ -504,10 +510,17 @@ void Sema::PrintInstantiationStack() { } case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: { + TemplateParameterList *TemplateParams = 0; + if (TemplateDecl *Template = dyn_cast<TemplateDecl>(Active->Template)) + TemplateParams = Template->getTemplateParameters(); + else + TemplateParams = + cast<ClassTemplatePartialSpecializationDecl>(Active->Template) + ->getTemplateParameters(); + Diags.Report(Active->PointOfInstantiation, diag::note_template_default_arg_checking) - << getTemplateArgumentBindingsText( - Active->Template->getTemplateParameters(), + << getTemplateArgumentBindingsText(TemplateParams, Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p9.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p9.cpp new file mode 100644 index 0000000000..2a3e914216 --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.class.spec/p9.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// PR8905 +template<char C1, char C2> +struct X { + static const bool value = 0; +}; + +template<int C1> +struct X<C1, C1> { + static const bool value = 1; +}; + +int check0[X<1, 2>::value == 0? 1 : -1]; +int check1[X<1, 1>::value == 1? 1 : -1]; + +template<int, int, int> struct int_values { + static const unsigned value = 0; +}; + +template<unsigned char C1, unsigned char C3> +struct int_values<C1, 12, C3> { + static const unsigned value = 1; +}; + +int check2[int_values<256, 12, 3>::value == 0? 1 : -1]; diff --git a/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp b/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp index f26b656be9..383e268054 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp @@ -23,3 +23,28 @@ namespace DeductionForInstantiation { // FIXME: Extension of explicitly-specified arguments // template void f0<short, int>(X<3, short&, int&, long&>); } + +namespace DeductionWithConversion { + template<char...> struct char_values { + static const unsigned value = 0; + }; + + template<int C1, char C3> + struct char_values<C1, 12, C3> { + static const unsigned value = 1; + }; + + int check0[char_values<1, 12, 3>::value == 1? 1 : -1]; + + template<int...> struct int_values { + static const unsigned value = 0; + }; + + template<unsigned char C1, unsigned char C3> + struct int_values<C1, 12, C3> { + static const unsigned value = 1; + }; + + int check1[int_values<256, 12, 3>::value == 0? 1 : -1]; + int check2[int_values<3, 12, 3>::value == 1? 1 : -1]; +} |