зеркало из https://github.com/microsoft/clang-1.git
Implement template instantiation for template names, including both
template template parameters and dependent template names. For example, the oft-mentioned typename MetaFun::template apply<T1, T2>::type can now be instantiated, with the appropriate name lookup for "apply". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68128 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
f8c4f5469d
Коммит
de650ae96b
|
@ -99,6 +99,10 @@ public:
|
|||
/// \brief Print the template name.
|
||||
void Print(llvm::raw_ostream &OS) const;
|
||||
|
||||
/// \brief Debugging aid that dumps the template name to standard
|
||||
/// error.
|
||||
void Dump() const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
ID.AddPointer(Storage.getOpaqueValue());
|
||||
}
|
||||
|
|
|
@ -701,6 +701,8 @@ def note_typename_refers_here : Note<
|
|||
|
||||
def err_template_kw_refers_to_non_template : Error<
|
||||
"%0 following the 'template' keyword does not refer to a template">;
|
||||
def err_template_kw_refers_to_function_template : Error<
|
||||
"%0 following the 'template' keyword refers to a function template">;
|
||||
|
||||
def err_unexpected_typedef : Error<
|
||||
"unexpected type name %0: expected expression">;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -52,3 +53,12 @@ void TemplateName::Print(llvm::raw_ostream &OS) const {
|
|||
OS << DTN->getName()->getName();
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateName::Dump() const {
|
||||
std::string Result;
|
||||
{
|
||||
llvm::raw_string_ostream OS(Result);
|
||||
Print(OS);
|
||||
}
|
||||
fprintf(stderr, "%s", Result.c_str());
|
||||
}
|
||||
|
|
|
@ -1981,6 +1981,11 @@ public:
|
|||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs);
|
||||
|
||||
TemplateName
|
||||
InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs);
|
||||
|
||||
// Simple function for cloning expressions.
|
||||
template<typename T>
|
||||
OwningExprResult Clone(T *E) {
|
||||
|
|
|
@ -472,10 +472,13 @@ InstantiateTemplateSpecializationType(
|
|||
|
||||
// FIXME: We're missing the locations of the template name, '<', and
|
||||
// '>'.
|
||||
// FIXME: Need to instantiate into the template name.
|
||||
return SemaRef.CheckTemplateIdType(T->getTemplateName(),
|
||||
Loc,
|
||||
SourceLocation(),
|
||||
|
||||
TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(),
|
||||
Loc,
|
||||
TemplateArgs,
|
||||
NumTemplateArgs);
|
||||
|
||||
return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(),
|
||||
&InstantiatedTemplateArgs[0],
|
||||
InstantiatedTemplateArgs.size(),
|
||||
SourceLocation());
|
||||
|
@ -839,3 +842,72 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
|
|||
// Required to silence a GCC warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
TemplateName
|
||||
Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs) {
|
||||
if (TemplateTemplateParmDecl *TTP
|
||||
= dyn_cast_or_null<TemplateTemplateParmDecl>(
|
||||
Name.getAsTemplateDecl())) {
|
||||
assert(TTP->getDepth() == 0 &&
|
||||
"Cannot reduce depth of a template template parameter");
|
||||
assert(TTP->getPosition() < NumTemplateArgs && "Wrong # of template args");
|
||||
assert(dyn_cast_or_null<ClassTemplateDecl>(
|
||||
TemplateArgs[TTP->getPosition()].getAsDecl()) &&
|
||||
"Wrong kind of template template argument");
|
||||
ClassTemplateDecl *ClassTemplate
|
||||
= dyn_cast<ClassTemplateDecl>(
|
||||
TemplateArgs[TTP->getPosition()].getAsDecl());
|
||||
|
||||
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
|
||||
NestedNameSpecifier *NNS
|
||||
= InstantiateNestedNameSpecifier(QTN->getQualifier(),
|
||||
/*FIXME=*/SourceRange(Loc),
|
||||
TemplateArgs, NumTemplateArgs);
|
||||
if (NNS)
|
||||
return Context.getQualifiedTemplateName(NNS,
|
||||
QTN->hasTemplateKeyword(),
|
||||
ClassTemplate);
|
||||
}
|
||||
|
||||
return TemplateName(ClassTemplate);
|
||||
} else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
|
||||
NestedNameSpecifier *NNS
|
||||
= InstantiateNestedNameSpecifier(DTN->getQualifier(),
|
||||
/*FIXME=*/SourceRange(Loc),
|
||||
TemplateArgs, NumTemplateArgs);
|
||||
|
||||
if (!NNS) // FIXME: Not the best recovery strategy.
|
||||
return Name;
|
||||
|
||||
if (NNS->isDependent())
|
||||
return Context.getDependentTemplateName(NNS, DTN->getName());
|
||||
|
||||
// Somewhat redundant with ActOnDependentTemplateName.
|
||||
CXXScopeSpec SS;
|
||||
SS.setRange(SourceRange(Loc));
|
||||
SS.setScopeRep(NNS);
|
||||
TemplateTy Template;
|
||||
TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS);
|
||||
if (TNK == TNK_Non_template) {
|
||||
Diag(Loc, diag::err_template_kw_refers_to_non_template)
|
||||
<< DTN->getName();
|
||||
return Name;
|
||||
} else if (TNK == TNK_Function_template) {
|
||||
Diag(Loc, diag::err_template_kw_refers_to_non_template)
|
||||
<< DTN->getName();
|
||||
return Name;
|
||||
}
|
||||
|
||||
return Template.getAsVal<TemplateName>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FIXME: Even if we're referring to a Decl that isn't a template
|
||||
// template parameter, we may need to instantiate the outer contexts
|
||||
// of that Decl. However, this won't be needed until we implement
|
||||
// member templates.
|
||||
return Name;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
template<template<typename T> class MetaFun, typename Value>
|
||||
struct apply {
|
||||
typedef typename MetaFun<Value>::type type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct add_pointer {
|
||||
typedef T* type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct add_reference {
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
int i;
|
||||
apply<add_pointer, int>::type ip = &i;
|
||||
apply<add_reference, int>::type ir = i;
|
||||
apply<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}}
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: clang-cc -fsyntax-only %s
|
||||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
struct add_pointer {
|
||||
template<typename T>
|
||||
|
@ -10,20 +10,21 @@ struct add_pointer {
|
|||
struct add_reference {
|
||||
template<typename T>
|
||||
struct apply {
|
||||
typedef T& type;
|
||||
typedef T& type; // expected-error{{cannot form a reference to 'void'}}
|
||||
};
|
||||
};
|
||||
|
||||
template<typename MetaFun, typename T>
|
||||
struct apply1 {
|
||||
typedef typename MetaFun::template apply<T>::type type;
|
||||
typedef typename MetaFun::template apply<T>::type type; // expected-note{{in instantiation of template class 'struct add_reference::apply<void>' requested here}}
|
||||
};
|
||||
|
||||
#if 0
|
||||
// FIXME: The code below requires template instantiation for dependent
|
||||
// template-names that occur within nested-name-specifiers.
|
||||
int i;
|
||||
|
||||
apply1<add_pointer, int>::type ip = &i;
|
||||
apply1<add_reference, int>::type ir = i;
|
||||
#endif
|
||||
apply1<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}}
|
||||
|
||||
void test() {
|
||||
apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}} \
|
||||
// FIXME: expected-error{{unexpected type name 'type': expected expression}}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче