r292426 - PR9551: Implement DR1004 (http://wg21.link/cwg1004).
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 18 11:19:23 PST 2017
Author: rsmith
Date: Wed Jan 18 13:19:22 2017
New Revision: 292426
URL: http://llvm.org/viewvc/llvm-project?rev=292426&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/test/CXX/drs/dr10xx.cpp
cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp
cfe/trunk/www/cxx_dr_status.html
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=292426&r1=292425&r2=292426&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Jan 18 13:19:22 2017
@@ -4350,6 +4350,9 @@ public:
const TemplateSpecializationType *getInjectedTST() const {
return cast<TemplateSpecializationType>(InjectedType.getTypePtr());
}
+ TemplateName getTemplateName() const {
+ return getInjectedTST()->getTemplateName();
+ }
CXXRecordDecl *getDecl() const;
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=292426&r1=292425&r2=292426&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan 18 13:19:22 2017
@@ -6114,12 +6114,17 @@ public:
/// \param Converted Will receive the converted, canonicalized template
/// arguments.
///
+ /// \param UpdateArgsWithConversions If \c true, update \p TemplateArgs to
+ /// contain the converted forms of the template arguments as written.
+ /// Otherwise, \p TemplateArgs will not be modified.
+ ///
/// \returns true if an error occurred, false otherwise.
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted);
+ SmallVectorImpl<TemplateArgument> &Converted,
+ bool UpdateArgsWithConversions = true);
bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
TemplateArgumentLoc &Arg,
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=292426&r1=292425&r2=292426&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jan 18 13:19:22 2017
@@ -3657,6 +3657,39 @@ Sema::SubstDefaultTemplateArgumentIfAvai
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(NamedDe
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
/// \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(Tem
// 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;
}
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=292426&r1=292425&r2=292426&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Jan 18 13:19:22 2017
@@ -2640,11 +2640,9 @@ Sema::SubstituteExplicitTemplateArgument
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;
Modified: cfe/trunk/test/CXX/drs/dr10xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr10xx.cpp?rev=292426&r1=292425&r2=292426&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr10xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr10xx.cpp Wed Jan 18 13:19:22 2017
@@ -12,6 +12,29 @@ namespace std {
};
}
+namespace dr1004 { // dr1004: 5
+ template<typename> struct A {};
+ template<typename> struct B1 {};
+ template<template<typename> class> struct B2 {};
+ template<typename X> void f(); // expected-note {{[with X = dr1004::A<int>]}}
+ template<template<typename> class X> void f(); // expected-note {{[with X = A]}}
+ template<template<typename> class X> void g(); // expected-note {{[with X = A]}}
+ template<typename X> void g(); // expected-note {{[with X = dr1004::A<int>]}}
+ struct C : A<int> {
+ B1<A> b1a;
+ B2<A> b2a;
+ void h() {
+ f<A>(); // expected-error {{ambiguous}}
+ g<A>(); // expected-error {{ambiguous}}
+ }
+ };
+
+ // FIXME: Is this example (from the standard) really OK, or does name lookup
+ // of "T::template A" name the constructor?
+ template<class T, template<class> class U = T::template A> struct Third { };
+ Third<A<int> > t;
+}
+
namespace dr1048 { // dr1048: 3.6
struct A {};
const A f();
Modified: cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp?rev=292426&r1=292425&r2=292426&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp Wed Jan 18 13:19:22 2017
@@ -1,12 +1,55 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
-// C++0x [temp.local]p1:
+// C++1z [temp.local]p1:
// Like normal (non-template) classes, class templates have an
-// injected-class-name (Clause 9). The injected-class-name can be used with
-// or without a template-argument-list. When it is used without
-// a template-argument-list, it is equivalent to the injected-class-name
-// followed by the template-parameters of the class template enclosed in <>.
+// injected-class-name (Clause 9). The injected-class-name can
+// be used as a template-name or a type-name.
+
+template<typename> char id;
+
+template<typename> struct TempType {};
+template<template<typename> class> struct TempTemp {};
+
+template<typename> void use(int&); // expected-note {{invalid explicitly-specified argument}} expected-note {{no known conversion}}
+template<template<typename> class> void use(float&); // expected-note 2{{no known conversion}}
+template<int> void use(char&); // expected-note 2{{invalid explicitly-specified argument}}
+
+template<typename T> struct A {
+ template<typename> struct C {};
+ struct B : C<T> {
+ // When it is used with a template-argument-list,
+ A<int> *aint;
+ typename B::template C<int> *cint;
+
+ // as a template-argument for a template template-parameter,
+ TempTemp<A> a_as_temp;
+ TempTemp<B::template C> c_as_temp;
+
+ // or as the final identifier in the elaborated-type-specifier of a friend
+ // class template declaration,
+ template<typename U> friend struct A;
+ // it refers to the class template itself.
+
+ // Otherwise, it is equivalent to the template-name followed by the
+ // template-parameters of the class template enclosed in <>.
+ A *aT;
+ typename B::C *cT;
+ TempType<A> a_as_type;
+ TempType<typename B::C> c_as_type;
+ friend struct A;
+ friend struct B::C;
+
+ void f(T &t) {
+ use<A>(t); // expected-error {{no matching function}}
+ if constexpr (&id<T> != &id<int>)
+ use<B::template C>(t); // expected-error {{no matching function}}
+ }
+ };
+};
+
+template struct A<int>;
+template struct A<float>;
+template struct A<char>; // expected-note {{instantiation of}}
template <typename T> struct X0 {
X0();
Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=292426&r1=292425&r2=292426&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Wed Jan 18 13:19:22 2017
@@ -1937,7 +1937,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#316">316</a></td>
<td>NAD</td>
<td>Injected-class-name of template used as template template parameter</td>
- <td class="none" align="center">Superseded by <a href="#1004">1004</a></td>
+ <td class="svn" align="center">Superseded by <a href="#1004">1004</a></td>
</tr>
<tr id="317">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#317">317</a></td>
@@ -5839,7 +5839,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1004">1004</a></td>
<td>C++11</td>
<td>Injected-class-names as arguments for template template parameters</td>
- <td class="none" align="center">Unknown</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr id="1005">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1005">1005</a></td>
More information about the cfe-commits
mailing list