aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h9
-rw-r--r--include/clang/AST/Decl.h7
-rw-r--r--include/clang/AST/DeclTemplate.h24
-rw-r--r--include/clang/AST/Type.h6
-rw-r--r--lib/AST/ASTContext.cpp30
-rw-r--r--lib/AST/Decl.cpp13
-rw-r--r--lib/AST/DeclTemplate.cpp59
-rw-r--r--lib/AST/Type.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp19
-rw-r--r--lib/Sema/SemaTemplate.cpp36
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp3
-rw-r--r--test/SemaTemplate/injected-class-name.cpp27
12 files changed, 206 insertions, 30 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1f24dee0f3..8b4c89b6e8 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -564,6 +564,9 @@ public:
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.
///
@@ -571,11 +574,11 @@ public:
/// 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.
///
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 90d1328c3d..79d04b338e 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -902,7 +902,12 @@ public:
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
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 5036127d3f..0853b29ab1 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -674,6 +674,9 @@ protected:
/// \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.
@@ -700,6 +703,11 @@ public:
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,
@@ -713,6 +721,22 @@ public:
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; }
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 22e36a8215..ff3d89c354 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1281,11 +1281,7 @@ class TagType : public Type {
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(); }
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 133e8c20b8..f9d648b816 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1703,11 +1703,39 @@ QualType ASTContext::getCanonicalType(QualType T) {
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.");
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 9aba33c943..621145f1af 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -14,6 +14,7 @@
#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"
@@ -505,6 +506,18 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
// 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);
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 7389b83d20..4f64f8bd50 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -120,6 +120,65 @@ void ClassTemplateDecl::Destroy(ASTContext& C) {
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
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index b5a884085b..bc439c8c89 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1000,6 +1000,9 @@ TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
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());
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index ea6913769a..d9e883f7a8 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -123,8 +123,23 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
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);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index c8fdc220d0..0c91573180 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -503,7 +503,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
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 =
@@ -749,8 +749,9 @@ static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs,
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:
@@ -1124,10 +1125,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
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;
}
}
@@ -1549,8 +1549,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
- if (Converted)
+ if (Converted) {
+ Member = cast<NamedDecl>(Context.getCanonicalDecl(Member));
Converted->push_back(TemplateArgument(StartLoc, Member));
+ }
return false;
}
@@ -1559,8 +1561,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted)
+ if (Converted) {
+ Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
return false;
}
@@ -1598,8 +1602,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted)
+ if (Converted) {
+ Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
return false;
}
@@ -1640,8 +1646,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Converted)
+ if (Converted) {
+ Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
Converted->push_back(TemplateArgument(StartLoc, Entity));
+ }
return false;
}
@@ -1670,9 +1678,11 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
- if (Converted)
+ if (Converted) {
+ Member = cast<NamedDecl>(Context.getCanonicalDecl(Member));
Converted->push_back(TemplateArgument(StartLoc, Member));
-
+ }
+
return false;
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 62c717b6d3..a075ea938d 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -273,11 +273,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
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;
diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp
index 43fb454bca..c5f826d849 100644
--- a/test/SemaTemplate/injected-class-name.cpp
+++ b/test/SemaTemplate/injected-class-name.cpp
@@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
-
template<typename T>
struct X {
X<T*> *ptr;
@@ -13,5 +12,29 @@ struct X<int***> {
};
// 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}}
+};