diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-01-18 19:19:22 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-01-18 19:19:22 +0000 |
| commit | 11255ec7659cec933e0b0415c14d50ca80cb16cd (patch) | |
| tree | 429cafd7000eed7d9e88ea3ae0a471ac8c26e4df /clang/lib | |
| parent | 0de990da16c4aeed10612da9dd752fa28de5a007 (diff) | |
| download | bcm5719-llvm-11255ec7659cec933e0b0415c14d50ca80cb16cd.tar.gz bcm5719-llvm-11255ec7659cec933e0b0415c14d50ca80cb16cd.zip | |
PR9551: Implement DR1004 (http://wg21.link/cwg1004).
This rule permits the injected-class-name of a class template to be used as
both a template type argument and a template template argument, with no extra
syntax required to disambiguate.
llvm-svn: 292426
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 57 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 8 |
2 files changed, 54 insertions, 11 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 2920ede3b5e..90de88ac332 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3657,6 +3657,39 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, TempTempParm->getDefaultArgument().getTemplateNameLoc()); } +/// Convert a template-argument that we parsed as a type into a template, if +/// possible. C++ permits injected-class-names to perform dual service as +/// template template arguments and as template type arguments. +static TemplateArgumentLoc convertTypeTemplateArgumentToTemplate(TypeLoc TLoc) { + // Extract and step over any surrounding nested-name-specifier. + NestedNameSpecifierLoc QualLoc; + if (auto ETLoc = TLoc.getAs<ElaboratedTypeLoc>()) { + if (ETLoc.getTypePtr()->getKeyword() != ETK_None) + return TemplateArgumentLoc(); + + QualLoc = ETLoc.getQualifierLoc(); + TLoc = ETLoc.getNamedTypeLoc(); + } + + // If this type was written as an injected-class-name, it can be used as a + // template template argument. + if (auto InjLoc = TLoc.getAs<InjectedClassNameTypeLoc>()) + return TemplateArgumentLoc(InjLoc.getTypePtr()->getTemplateName(), + QualLoc, InjLoc.getNameLoc()); + + // If this type was written as an injected-class-name, it may have been + // converted to a RecordType during instantiation. If the RecordType is + // *not* wrapped in a TemplateSpecializationType and denotes a class + // template specialization, it must have come from an injected-class-name. + if (auto RecLoc = TLoc.getAs<RecordTypeLoc>()) + if (auto *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(RecLoc.getDecl())) + return TemplateArgumentLoc(TemplateName(CTSD->getSpecializedTemplate()), + QualLoc, RecLoc.getNameLoc()); + + return TemplateArgumentLoc(); +} + /// \brief Check that the given template argument corresponds to the given /// template parameter. /// @@ -3863,6 +3896,17 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; } + // C++1z [temp.local]p1: (DR1004) + // When [the injected-class-name] is used [...] as a template-argument for + // a template template-parameter [...] it refers to the class template + // itself. + if (Arg.getArgument().getKind() == TemplateArgument::Type) { + TemplateArgumentLoc ConvertedArg = convertTypeTemplateArgumentToTemplate( + Arg.getTypeSourceInfo()->getTypeLoc()); + if (!ConvertedArg.getArgument().isNull()) + Arg = ConvertedArg; + } + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: llvm_unreachable("Should never see a NULL template argument here"); @@ -3976,11 +4020,11 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, /// \brief Check that the given template argument list is well-formed /// for specializing the given template. -bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, - SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs, - bool PartialTemplateArgs, - SmallVectorImpl<TemplateArgument> &Converted) { +bool Sema::CheckTemplateArgumentList( + TemplateDecl *Template, SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, + SmallVectorImpl<TemplateArgument> &Converted, + bool UpdateArgsWithConversions) { // Make a copy of the template arguments for processing. Only make the // changes at the end when successful in matching the arguments to the // template. @@ -4218,7 +4262,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // No problems found with the new argument list, propagate changes back // to caller. - TemplateArgs = std::move(NewArgs); + if (UpdateArgsWithConversions) + TemplateArgs = std::move(NewArgs); return false; } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 93e796ee966..3197647d8d8 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2640,11 +2640,9 @@ Sema::SubstituteExplicitTemplateArguments( if (Inst.isInvalid()) return TDK_InstantiationDepth; - if (CheckTemplateArgumentList(FunctionTemplate, - SourceLocation(), - ExplicitTemplateArgs, - true, - Builder) || Trap.hasErrorOccurred()) { + if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), + ExplicitTemplateArgs, true, Builder, false) || + Trap.hasErrorOccurred()) { unsigned Index = Builder.size(); if (Index >= TemplateParams->size()) Index = TemplateParams->size() - 1; |

