return T1.getUnqualifiedType() == T2.getUnqualifiedType();
}
+ /// \brief Retrieves the "canonical" declaration of the given declaration.
+ Decl *getCanonicalDecl(Decl *D);
+
/// \brief Retrieves the "canonical" declaration of the given tag
/// declaration.
///
/// either the definition of the tag (if it is a complete type) or
/// the first declaration of that tag.
TagDecl *getCanonicalDecl(TagDecl *Tag) {
- QualType T = getTagDeclType(Tag);
- return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType)
- ->getDecl());
+ return cast<TagDecl>(getCanonicalDecl((Decl *)Tag));
}
+ /// \brief Retrieves the "canonical" declaration of
+
/// \brief Retrieves the "canonical" nested name specifier for a
/// given nested name specifier.
///
bool isDefinition() const {
return IsDefinition;
}
-
+
+ /// \brief Whether this declaration declares a type that is
+ /// dependent, i.e., a type that somehow depends on template
+ /// parameters.
+ bool isDependentType() const;
+
/// @brief Starts the definition of this tag declaration.
///
/// This method should be invoked at the beginning of the definition
/// \brief The class template specializations for this class
/// template, including explicit specializations and instantiations.
llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
+
+ /// \brief The injected-class-name type for this class template.
+ QualType InjectedClassNameType;
};
/// \brief Previous declaration of this class template.
return static_cast<CXXRecordDecl *>(TemplatedDecl);
}
+ /// \brief Retrieve the previous declaration of this template.
+ ClassTemplateDecl *getPreviousDeclaration() const {
+ return PreviousDeclaration;
+ }
+
/// Create a class template node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
return CommonPtr->Specializations;
}
+ /// \brief Retrieve the type of the injected-class-name for this
+ /// class template.
+ ///
+ /// The injected-class-name for a class template \c X is \c
+ /// X<template-args>, where \c template-args is formed from the
+ /// template arguments that correspond to the template parameters of
+ /// \c X. For example:
+ ///
+ /// \code
+ /// template<typename T, int N>
+ /// struct array {
+ /// typedef array this_type; // "array" is equivalent to "array<T, N>"
+ /// };
+ /// \endcode
+ QualType getInjectedClassNameType(ASTContext &Context);
+
// Implement isa/cast/dyncast support
static bool classof(const Decl *D)
{ return D->getKind() == ClassTemplate; }
friend class TagDecl;
protected:
- // FIXME: We'll need the user to pass in information about whether
- // this type is dependent or not, because we don't have enough
- // information to compute it here.
- TagType(TypeClass TC, TagDecl *D, QualType can)
- : Type(TC, can, /*Dependent=*/false), decl(D, 0) {}
+ TagType(TypeClass TC, TagDecl *D, QualType can);
public:
TagDecl *getDecl() const { return decl.getPointer(); }
VAT->getIndexTypeQualifier());
}
+Decl *ASTContext::getCanonicalDecl(Decl *D) {
+ if (TagDecl *Tag = dyn_cast<TagDecl>(D)) {
+ QualType T = getTagDeclType(Tag);
+ return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType)
+ ->getDecl());
+ }
+
+ if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(D)) {
+ while (Template->getPreviousDeclaration())
+ Template = Template->getPreviousDeclaration();
+ return Template;
+ }
+
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ while (Function->getPreviousDeclaration())
+ Function = Function->getPreviousDeclaration();
+ return const_cast<FunctionDecl *>(Function);
+ }
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ while (Var->getPreviousDeclaration())
+ Var = Var->getPreviousDeclaration();
+ return const_cast<VarDecl *>(Var);
+ }
+
+ return D;
+}
+
TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
// If this template name refers to a template, the canonical
// template name merely stores the template itself.
if (TemplateDecl *Template = Name.getAsTemplateDecl())
- return TemplateName(Template);
+ return TemplateName(cast<TemplateDecl>(getCanonicalDecl(Template)));
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
assert(DTN && "Non-dependent template names must refer to template decls.");
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Expr.h"
// TagDecl Implementation
//===----------------------------------------------------------------------===//
+bool TagDecl::isDependentType() const {
+ if (isa<TemplateDecl>(this))
+ return true;
+
+ if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(getDeclContext()))
+ return TD->isDependentType();
+
+ // FIXME: Tag types declared function templates are dependent types.
+ // FIXME: Look through block scopes.
+ return false;
+}
+
void TagDecl::startDefinition() {
TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType());
TagT->decl.setPointer(this);
C.Deallocate((void*)this);
}
+QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
+ if (!CommonPtr->InjectedClassNameType.isNull())
+ return CommonPtr->InjectedClassNameType;
+
+ // FIXME: n2800 14.6.1p1 should say how the template arguments
+ // corresponding to template parameter packs should be pack
+ // expansions. We already say that in 14.6.2.1p2, so it would be
+ // better to fix that redundancy.
+
+ TemplateParameterList *Params = getTemplateParameters();
+
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ llvm::SmallVector<TemplateArgument, 16> CanonTemplateArgs;
+ TemplateArgs.reserve(Params->size());
+ CanonTemplateArgs.reserve(Params->size());
+
+ for (TemplateParameterList::iterator
+ Param = Params->begin(), ParamEnd = Params->end();
+ Param != ParamEnd; ++Param) {
+ if (isa<TemplateTypeParmDecl>(*Param)) {
+ QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param));
+ TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(),
+ ParamType));
+ CanonTemplateArgs.push_back(
+ TemplateArgument((*Param)->getLocation(),
+ Context.getCanonicalType(ParamType)));
+ } else if (NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ // FIXME: Build canonical expression, too!
+ Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(),
+ NTTP->getLocation(),
+ NTTP->getType()->isDependentType(),
+ /*Value-dependent=*/true);
+ TemplateArgs.push_back(TemplateArgument(E));
+ CanonTemplateArgs.push_back(TemplateArgument(E));
+ } else {
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
+ TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP));
+ CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(),
+ Context.getCanonicalDecl(TTP)));
+ }
+ }
+
+ // FIXME: I should really move the "build-the-canonical-type" logic
+ // into ASTContext::getTemplateSpecializationType.
+ TemplateName Name = TemplateName(this);
+ QualType CanonType = Context.getTemplateSpecializationType(
+ Context.getCanonicalTemplateName(Name),
+ &CanonTemplateArgs[0],
+ CanonTemplateArgs.size());
+
+ CommonPtr->InjectedClassNameType
+ = Context.getTemplateSpecializationType(Name,
+ &TemplateArgs[0],
+ TemplateArgs.size(),
+ CanonType);
+ return CommonPtr->InjectedClassNameType;
+}
+
//===----------------------------------------------------------------------===//
// TemplateTypeParm Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
+TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
+ : Type(TC, can, D->isDependentType()), decl(D, 0) {}
+
bool RecordType::classof(const TagType *TT) {
return isa<RecordDecl>(TT->getDecl());
}
if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
// Check whether we can use this type
(void)DiagnoseUseOfDecl(IIDecl, NameLoc);
-
- T = Context.getTypeDeclType(TD);
+
+ if (getLangOptions().CPlusPlus) {
+ // C++ [temp.local]p2:
+ // Within the scope of a class template specialization or
+ // partial specialization, when the injected-class-name is
+ // not followed by a <, it is equivalent to the
+ // injected-class-name followed by the template-argument s
+ // of the class template specialization or partial
+ // specialization enclosed in <>.
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD))
+ if (RD->isInjectedClassName())
+ if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate())
+ T = Template->getInjectedClassNameType(Context);
+ }
+
+ if (T.isNull())
+ T = Context.getTypeDeclType(TD);
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
// Check whether we can use this interface.
(void)DiagnoseUseOfDecl(IIDecl, NameLoc);
PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
Invalid = true;
- // If we had a scope specifier, we better have a previous template
+ // FIXME: If we had a scope specifier, we better have a previous template
// declaration!
CXXRecordDecl *NewClass =
break;
case TemplateArgument::Declaration:
- Canonical.push_back(TemplateArgument(SourceLocation(),
- TemplateArgs[Idx].getAsDecl()));
+ Canonical.push_back(
+ TemplateArgument(SourceLocation(),
+ Context.getCanonicalDecl(TemplateArgs[Idx].getAsDecl())));
break;
case TemplateArgument::Integral:
Invalid = true;
// Add the converted template argument.
- // FIXME: Need the "canonical" template declaration!
- Converted.push_back(
- TemplateArgument(Arg.getLocation(),
- cast<DeclRefExpr>(ArgExpr)->getDecl()));
+ Decl *D
+ = Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl());
+ Converted.push_back(TemplateArgument(Arg.getLocation(), D));
continue;
}
}
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
- if (Converted)
+ if (Converted) {
+ Member = cast<NamedDecl>(Context.getCanonicalDecl(Member));
Converted->push_back(TemplateArgument(StartLoc, Member));
+ }
return false;
}
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted)
+ if (Converted) {
+ Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
return false;
}
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted)
+ if (Converted) {
+ Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
return false;
}
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted)
+ if (Converted) {
+ Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
return false;
}
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
- if (Converted)
+ if (Converted) {
+ Member = cast<NamedDecl>(Context.getCanonicalDecl(Member));
Converted->push_back(TemplateArgument(StartLoc, Member));
-
+ }
+
return false;
}
D->getLocation(), D->getIdentifier(), PrevDecl);
Record->setImplicit(D->isImplicit());
Record->setAccess(D->getAccess());
-
if (!D->isInjectedClassName())
Record->setInstantiationOfMemberClass(D);
- else
- Record->setDescribedClassTemplate(D->getDescribedClassTemplate());
Owner->addDecl(SemaRef.Context, Record);
return Record;
// RUN: clang-cc -fsyntax-only -verify %s
-
template<typename T>
struct X {
X<T*> *ptr;
};
// FIXME: EDG rejects this in their strict-conformance mode, but I
-// don't see any wording making this ill-formed.
+// don't see any wording making this ill-formed. Actually,
+// [temp.local]p2 might make it ill-formed. Are we "in the scope of
+// the class template specialization?"
X<float>::X<int> xi = x;
+
+// [temp.local]p1:
+
+// FIXME: test non-type and template template parameters
+template<typename T, typename U>
+struct X0 {
+ typedef T type;
+ typedef U U_type;
+ typedef U_type U_type2;
+
+ void f0(const X0&); // expected-note{{here}}
+ void f0(X0&);
+ void f0(const X0<T, U>&); // expected-error{{redecl}}
+
+ void f1(const X0&); // expected-note{{here}}
+ void f1(X0&);
+ void f1(const X0<type, U_type2>&); // expected-error{{redecl}}
+
+ void f2(const X0&); // expected-note{{here}}
+ void f2(X0&);
+ void f2(const ::X0<type, U_type2>&); // expected-error{{redecl}}
+};