QualType getTypenameType(NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
QualType Canon = QualType());
+ QualType getTypenameType(NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon = QualType());
/// getObjCQualifiedInterfaceType - Return a
/// ObjCQualifiedInterfaceType type for the given interface decl and
class NestedNameSpecifier : public llvm::FoldingSetNode {
/// \brief The nested name specifier that precedes this nested name
/// specifier.
- NestedNameSpecifier *Prefix;
+ ///
+ /// The pointer is the nested-name-specifier that precedes this
+ /// one. The integer stores one of the first four values of type
+ /// SpecifierKind.
+ llvm::PointerIntPair<NestedNameSpecifier *, 2> Prefix;
/// \brief The last component in the nested name specifier, which
/// can be an identifier, a declaration, or a type.
/// When the pointer is NULL, this specifier represents the global
/// specifier '::'. Otherwise, the pointer is one of
/// IdentifierInfo*, Namespace*, or Type*, depending on the kind of
- /// specifier. The integer stores one ofthe first four values of
- /// type SpecifierKind.
- llvm::PointerIntPair<void*, 2> Specifier;
+ /// specifier as encoded within the prefix.
+ void* Specifier;
public:
/// \brief The kind of specifier that completes this nested name
private:
/// \brief Builds the global specifier.
- NestedNameSpecifier() : Prefix(0), Specifier(0, 0) { }
+ NestedNameSpecifier() : Prefix(0, 0), Specifier(0) { }
/// \brief Copy constructor used internally to clone nested name
/// specifiers.
/// \brief Either find or insert the given nested name specifier
/// mockup in the given context.
- static NestedNameSpecifier *FindOrInsert(ASTContext &Context, const NestedNameSpecifier &Mockup);
+ static NestedNameSpecifier *FindOrInsert(ASTContext &Context,
+ const NestedNameSpecifier &Mockup);
public:
/// \brief Builds a specifier combining a prefix and an identifier.
/// nested name specifier that represents "foo::bar::", the current
/// specifier will contain "bar::" and the prefix will contain
/// "foo::".
- NestedNameSpecifier *getPrefix() const { return Prefix; }
+ NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); }
/// \brief Determine what kind of nested name specifier is stored.
SpecifierKind getKind() const {
- if (Specifier.getPointer() == 0)
+ if (Specifier == 0)
return Global;
- return (SpecifierKind)Specifier.getInt();
+ return (SpecifierKind)Prefix.getInt();
}
/// \brief Retrieve the identifier stored in this nested name
/// specifier.
IdentifierInfo *getAsIdentifier() const {
- if (Specifier.getInt() == Identifier)
- return (IdentifierInfo *)Specifier.getPointer();
+ if (Prefix.getInt() == Identifier)
+ return (IdentifierInfo *)Specifier;
return 0;
}
/// \brief Retrieve the namespace stored in this nested name
/// specifier.
NamespaceDecl *getAsNamespace() const {
- if (Specifier.getInt() == Namespace)
- return (NamespaceDecl *)Specifier.getPointer();
+ if (Prefix.getInt() == Namespace)
+ return (NamespaceDecl *)Specifier;
return 0;
}
/// \brief Retrieve the type stored in this nested name specifier.
Type *getAsType() const {
- if (Specifier.getInt() == TypeSpec ||
- Specifier.getInt() == TypeSpecWithTemplate)
- return (Type *)Specifier.getPointer();
+ if (Prefix.getInt() == TypeSpec ||
+ Prefix.getInt() == TypeSpecWithTemplate)
+ return (Type *)Specifier;
return 0;
}
void print(llvm::raw_ostream &OS) const;
void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddPointer(Prefix);
- ID.AddPointer(Specifier.getPointer());
- ID.AddInteger(Specifier.getInt());
+ ID.AddPointer(Prefix.getOpaqueValue());
+ ID.AddPointer(Specifier);
}
void Destroy(ASTContext &Context);
bool isDependent() const;
/// \brief Print the template name.
- void print(llvm::raw_ostream &OS) const;
+ ///
+ /// \param OS the output stream to which the template name will be
+ /// printed.
+ ///
+ /// \param SuppressNNS if true, don't print the
+ /// nested-name-specifier that precedes the template name (if it has
+ /// one).
+ void print(llvm::raw_ostream &OS, bool SuppressNNS = false) const;
/// \brief Debugging aid that dumps the template name to standard
/// error.
#define LLVM_CLANG_AST_TYPE_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/Bitcode/SerializationFwd.h"
using llvm::isa;
/// \brief The nested name specifier containing the qualifier.
NestedNameSpecifier *NNS;
+ typedef llvm::PointerUnion<const IdentifierInfo *,
+ const TemplateSpecializationType *> NameType;
+
/// \brief The type that this typename specifier refers to.
- /// FIXME: Also need to represent the "template simple-template-id" case.
- const IdentifierInfo *Name;
+ NameType Name;
TypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name,
QualType CanonType)
"TypenameType requires a dependent nested-name-specifier");
}
+ TypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty,
+ QualType CanonType)
+ : Type(Typename, CanonType, true), NNS(NNS), Name(Ty) {
+ assert(NNS->isDependent() &&
+ "TypenameType requires a dependent nested-name-specifier");
+ }
+
friend class ASTContext; // ASTContext creates these
public:
/// \brief Retrieve the qualification on this type.
NestedNameSpecifier *getQualifier() const { return NNS; }
- /// \brief Retrieve the type named by the typename specifier.
- const IdentifierInfo *getName() const { return Name; }
+ /// \brief Retrieve the type named by the typename specifier as an
+ /// identifier.
+ ///
+ /// This routine will return a non-NULL identifier pointer when the
+ /// form of the original typename was terminated by an identifier,
+ /// e.g., "typename T::type".
+ const IdentifierInfo *getIdentifier() const {
+ return Name.dyn_cast<const IdentifierInfo *>();
+ }
+
+ /// \brief Retrieve the type named by the typename specifier as a
+ /// type specialization.
+ const TemplateSpecializationType *getTemplateId() const {
+ return Name.dyn_cast<const TemplateSpecializationType *>();
+ }
virtual void getAsStringInternal(std::string &InnerString) const;
}
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
- const IdentifierInfo *Name) {
+ NameType Name) {
ID.AddPointer(NNS);
- ID.AddPointer(Name);
+ ID.AddPointer(Name.getOpaqueValue());
}
static bool classof(const Type *T) {
"template|<unused>|refers to a template template parameter}1">;
def err_id_after_template_in_nested_name_spec : Error<
"expected template name after 'template' keyword in nested name specifier">;
+def err_id_after_template_in_typename_spec : Error<
+ "expected template name after 'template' keyword in typename specifier">;
def err_less_after_template_name_in_nested_name_spec : Error<
"expected '<' after 'template %0' in nested name specifier">;
def err_two_right_angle_brackets_need_space : Error<
def err_expected_qualified_after_typename : Error<
"expected a qualified name after 'typename'">;
+def err_typename_refers_to_non_type_template : Error<
+ "typename specifier refers to a non-template">;
+def err_expected_type_name_after_typename : Error<
+ "expected an identifier or template-id after '::'">;
// Language specific pragmas
// - Generic warnings
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Bitcode/SerializationFwd.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
#include <string>
#include <cassert>
static bool isPod() { return true; }
};
+// Provide PointerLikeTypeTraits for IdentifierInfo pointers, which
+// are not guaranteed to be 8-byte aligned.
+template<>
+class PointerLikeTypeTraits<clang::IdentifierInfo*> {
+public:
+ static inline void *getAsVoidPointer(clang::IdentifierInfo* P) {
+ return P;
+ }
+ static inline clang::IdentifierInfo *getFromVoidPointer(void *P) {
+ return static_cast<clang::IdentifierInfo*>(P);
+ }
+ enum { NumLowBitsAvailable = 1 };
+};
+
+template<>
+class PointerLikeTypeTraits<const clang::IdentifierInfo*> {
+public:
+ static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) {
+ return P;
+ }
+ static inline const clang::IdentifierInfo *getFromVoidPointer(const void *P) {
+ return static_cast<const clang::IdentifierInfo*>(P);
+ }
+ enum { NumLowBitsAvailable = 1 };
+};
+
} // end namespace llvm
#endif
}
/// \brief Called when the parser has parsed a C++ typename
- /// specifier, e.g., "typename T::type".
+ /// specifier that ends in an identifier, e.g., "typename T::type".
///
/// \param TypenameLoc the location of the 'typename' keyword
/// \param SS the nested-name-specifier following the typename (e.g., 'T::').
return TypeResult();
}
+ /// \brief Called when the parser has parsed a C++ typename
+ /// specifier that ends in a template-id, e.g.,
+ /// "typename MetaFun::template apply<T1, T2>".
+ ///
+ /// \param TypenameLoc the location of the 'typename' keyword
+ /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
+ /// \param TemplateLoc the location of the 'template' keyword, if any.
+ /// \param Ty the type that the typename specifier refers to.
+ virtual TypeResult
+ ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc, TypeTy *Ty) {
+ return TypeResult();
+ }
+
//===----------------------- Obj-C Declarations -------------------------===//
// ActOnStartClassInterface - this action is called immediately after parsing
return QualType(T, 0);
}
+QualType
+ASTContext::getTypenameType(NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon) {
+ assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+
+ if (Canon.isNull()) {
+ NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+ QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
+ if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
+ const TemplateSpecializationType *CanonTemplateId
+ = CanonType->getAsTemplateSpecializationType();
+ assert(CanonTemplateId &&
+ "Canonical type must also be a template specialization type");
+ Canon = getTypenameType(CanonNNS, CanonTemplateId);
+ }
+ }
+
+ llvm::FoldingSetNodeID ID;
+ TypenameType::Profile(ID, NNS, TemplateId);
+
+ void *InsertPos = 0;
+ TypenameType *T
+ = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
+ T = new (*this) TypenameType(NNS, TemplateId, Canon);
+ Types.push_back(T);
+ TypenameTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
+}
+
/// CmpProtocolNames - Comparison predicate for sorting protocols
/// alphabetically.
static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
NestedNameSpecifier *NNS
= Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
if (!NNS) {
- NNS = new (Context) NestedNameSpecifier(Mockup);
+ NNS = new (Context, 4) NestedNameSpecifier(Mockup);
Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos);
}
assert(Prefix && Prefix->isDependent() && "Prefix must be dependent");
NestedNameSpecifier Mockup;
- Mockup.Prefix = Prefix;
- Mockup.Specifier.setPointer(II);
- Mockup.Specifier.setInt(Identifier);
+ Mockup.Prefix.setPointer(Prefix);
+ Mockup.Prefix.setInt(Identifier);
+ Mockup.Specifier = II;
return FindOrInsert(Context, Mockup);
}
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
"Broken nested name specifier");
NestedNameSpecifier Mockup;
- Mockup.Prefix = Prefix;
- Mockup.Specifier.setPointer(NS);
- Mockup.Specifier.setInt(Namespace);
+ Mockup.Prefix.setPointer(Prefix);
+ Mockup.Prefix.setInt(Namespace);
+ Mockup.Specifier = NS;
return FindOrInsert(Context, Mockup);
}
bool Template, Type *T) {
assert(T && "Type cannot be NULL");
NestedNameSpecifier Mockup;
- Mockup.Prefix = Prefix;
- Mockup.Specifier.setPointer(T);
- Mockup.Specifier.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+ Mockup.Prefix.setPointer(Prefix);
+ Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+ Mockup.Specifier = T;
return FindOrInsert(Context, Mockup);
}
NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) {
if (!Context.GlobalNestedNameSpecifier)
- Context.GlobalNestedNameSpecifier = new (Context) NestedNameSpecifier();
+ Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier();
return Context.GlobalNestedNameSpecifier;
}
/// \brief Print this nested name specifier to the given output
/// stream.
void NestedNameSpecifier::print(llvm::raw_ostream &OS) const {
- if (Prefix)
- Prefix->print(OS);
+ if (getPrefix())
+ getPrefix()->print(OS);
switch (getKind()) {
case Identifier:
return true;
}
-void TemplateName::print(llvm::raw_ostream &OS) const {
+void TemplateName::print(llvm::raw_ostream &OS, bool SuppressNNS) const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
OS << Template->getIdentifier()->getName();
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
- QTN->getQualifier()->print(OS);
+ if (!SuppressNNS)
+ QTN->getQualifier()->print(OS);
if (QTN->hasTemplateKeyword())
OS << "template ";
OS << QTN->getTemplateDecl()->getIdentifier()->getName();
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
- DTN->getQualifier()->print(OS);
+ if (!SuppressNNS)
+ DTN->getQualifier()->print(OS);
OS << "template ";
OS << DTN->getName()->getName();
}
llvm::raw_string_ostream OS(MyString);
OS << "typename ";
NNS->print(OS);
- OS << Name->getName();
+
+ if (const IdentifierInfo *Ident = getIdentifier())
+ OS << Ident->getName();
+ else if (const TemplateSpecializationType *Spec = getTemplateId()) {
+ Spec->getTemplateName().print(OS, true);
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Spec->getArgs(), Spec->getNumArgs());
+ }
}
if (InnerString.empty())
// typename-specifier:
// 'typename' '::' [opt] nested-name-specifier identifier
// 'typename' '::' [opt] nested-name-specifier template [opt]
- // simple-template-id [TODO]
+ // simple-template-id
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS);
// FIXME: check whether the next token is '<', first!
Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(),
Tok.getLocation());
- // FIXME: better error recovery!
- Tok.setKind(tok::annot_typename);
- Tok.setAnnotationValue(Ty.get());
- Tok.setAnnotationEndLoc(Tok.getLocation());
- Tok.setLocation(TypenameLoc);
- PP.AnnotateCachedTokens(Tok);
- return true;
- }
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Function_template) {
+ Diag(Tok, diag::err_typename_refers_to_non_type_template)
+ << Tok.getAnnotationRange();
+ return false;
+ }
- return false;
+ if (AnnotateTemplateIdTokenAsType(0))
+ return false;
+
+ assert(Tok.is(tok::annot_typename) &&
+ "AnnotateTemplateIdTokenAsType isn't working properly");
+ Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(),
+ Tok.getAnnotationValue());
+ } else {
+ Diag(Tok, diag::err_expected_type_name_after_typename)
+ << SS.getRange();
+ return false;
+ }
+
+ // FIXME: better error recovery!
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Ty.get());
+ Tok.setAnnotationEndLoc(Tok.getLocation());
+ Tok.setLocation(TypenameLoc);
+ PP.AnnotateCachedTokens(Tok);
+ return true;
}
CXXScopeSpec SS;
virtual TypeResult
ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
const IdentifierInfo &II, SourceLocation IdLoc);
+
+ /// \brief Called when the parser has parsed a C++ typename
+ /// specifier that ends in a template-id, e.g.,
+ /// "typename MetaFun::template apply<T1, T2>".
+ ///
+ /// \param TypenameLoc the location of the 'typename' keyword
+ /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
+ /// \param TemplateLoc the location of the 'template' keyword, if any.
+ /// \param Ty the type that the typename specifier refers to.
+ virtual TypeResult
+ ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc, TypeTy *Ty);
+
QualType CheckTypenameType(NestedNameSpecifier *NNS,
const IdentifierInfo &II,
SourceRange Range);
return T.getAsOpaquePtr();
}
+Sema::TypeResult
+Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc, TypeTy *Ty) {
+ QualType T = QualType::getFromOpaquePtr(Ty);
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ const TemplateSpecializationType *TemplateId
+ = T->getAsTemplateSpecializationType();
+ assert(TemplateId && "Expected a template specialization type");
+
+ if (NNS->isDependent())
+ return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
+
+ return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+}
+
/// \brief Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type".
QualType
QualType
TemplateTypeInstantiator::
InstantiateTypenameType(const TypenameType *T, unsigned Quals) const {
+ if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
+ // When the typename type refers to a template-id, the template-id
+ // is dependent and has enough information to instantiate the
+ // result of the typename type. Since we don't care about keeping
+ // the spelling of the typename type in template instantiations,
+ // we just instantiate the template-id.
+ return InstantiateTemplateSpecializationType(TemplateId, Quals);
+ }
+
NestedNameSpecifier *NNS
= SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(),
SourceRange(Loc),
if (!NNS)
return QualType();
- return SemaRef.CheckTypenameType(NNS, *T->getName(), SourceRange(Loc));
+ return SemaRef.CheckTypenameType(NNS, *T->getIdentifier(), SourceRange(Loc));
}
QualType
}
switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- // FIXME: Implement this lookup!
- assert(false && "Cannot instantiate this nested-name-specifier");
+ case NestedNameSpecifier::Identifier: {
+ assert(Prefix &&
+ "Can't have an identifier nested-name-specifier with no prefix");
+ CXXScopeSpec SS;
+ // FIXME: The source location information is all wrong.
+ SS.setRange(Range);
+ SS.setScopeRep(Prefix);
+ return static_cast<NestedNameSpecifier *>(
+ ActOnCXXNestedNameSpecifier(0, SS,
+ Range.getEnd(),
+ Range.getEnd(),
+ *NNS->getAsIdentifier()));
break;
+ }
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::Global:
if (!T->isDependentType())
return NNS;
- // FIXME: We won't be able to perform the instantiation here when
- // the template-name is dependent, e.g., we have something like
- // "T::template apply<U>::type".
T = InstantiateType(T, TemplateArgs, NumTemplateArgs, Range.getBegin(),
DeclarationName());
if (T.isNull())
if (T->isRecordType() ||
(getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
- // Note that T.getTypePtr(), below, strips cv-qualifiers. This is
- // perfectly reasonable, since cv-qualified types in
- // nested-name-specifiers don't matter.
+ assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here");
return NestedNameSpecifier::Create(Context, Prefix,
NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
T.getTypePtr());
--- /dev/null
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename MetaFun, typename T>
+struct bind_metafun {
+ typedef typename MetaFun::template apply<T> type;
+};
+
+struct add_pointer {
+ template<typename T>
+ struct apply {
+ typedef T* type;
+ };
+};
+
+int i;
+// FIXME: if we make the declarator below a pointer (e.g., with *ip),
+// the error message isn't so good because we don't get the handy
+// 'aka' telling us that we're dealing with an int**. Should we fix
+// getDesugaredType to dig through pointers and such?
+bind_metafun<add_pointer, int>::type::type ip = &i;
+bind_metafun<add_pointer, float>::type::type fp = &i; // expected-error{{incompatible type initializing 'int *', expected 'bind_metafun<struct add_pointer, float>::type::type' (aka 'float *')}}
+
+
+template<typename T>
+struct extract_type_type {
+ typedef typename T::type::type t;
+};
+
+double d;
+extract_type_type<bind_metafun<add_pointer, double> >::t dp = &d;