forked from OSchip/llvm-project
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
This commit is contained in:
parent
0de990da16
commit
11255ec765
|
@ -4350,6 +4350,9 @@ public:
|
|||
const TemplateSpecializationType *getInjectedTST() const {
|
||||
return cast<TemplateSpecializationType>(InjectedType.getTypePtr());
|
||||
}
|
||||
TemplateName getTemplateName() const {
|
||||
return getInjectedTST()->getTemplateName();
|
||||
}
|
||||
|
||||
CXXRecordDecl *getDecl() const;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue