diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-12-05 18:15:24 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-12-05 18:15:24 +0000 |
commit | 72c3f314d92d65c050ee1c07b7753623c044d6c7 (patch) | |
tree | d714ab61b37fb6732d556e9f324181a41312cffa | |
parent | 8c56515a0c61b73fc2f02cc96dc3e37650d89d45 (diff) |
Representation of template type parameters and non-type template
parameters, with some semantic analysis:
- Template parameters are introduced into template parameter scope
- Complain about template parameter shadowing (except in Microsoft mode)
Note that we leak template parameter declarations like crazy, a
problem we'll remedy once we actually create proper declarations for
templates.
Next up: dependent types and value-dependent/type-dependent
expressions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60597 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 2 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 7 | ||||
-rw-r--r-- | include/clang/AST/DeclBase.h | 14 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 64 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 36 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 6 | ||||
-rw-r--r-- | include/clang/Parse/Scope.h | 25 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 12 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 2 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 18 | ||||
-rw-r--r-- | lib/AST/DeclSerialization.cpp | 25 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 6 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 11 | ||||
-rw-r--r-- | lib/AST/TypeSerialization.cpp | 23 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 51 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 116 | ||||
-rw-r--r-- | test/Parser/cxx-template-decl.cpp | 26 |
23 files changed, 448 insertions, 27 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 46a4e6f532..0d3568b127 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -46,6 +46,7 @@ namespace clang { class TranslationUnitDecl; class TypeDecl; class TypedefDecl; + class TemplateTypeParmDecl; /// ASTContext - This class holds long-lived AST nodes (such as types and /// decls) that can be referred to throughout the semantic analysis of a file. @@ -221,6 +222,7 @@ public: /// getTypedefType - Return the unique reference to the type for the /// specified typename decl. QualType getTypedefType(TypedefDecl *Decl); + QualType getTemplateTypeParmType(TemplateTypeParmDecl *Decl); QualType getObjCInterfaceType(ObjCInterfaceDecl *Decl); /// getObjCQualifiedInterfaceType - Return a diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 976d98be3a..b4a1bf83da 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -746,8 +746,8 @@ protected: /// class TypeDecl : public ScopedDecl { /// TypeForDecl - This indicates the Type object that represents this - /// TypeDecl. It is a cache maintained by ASTContext::getTypedefType and - /// ASTContext::getTagDeclType. + /// TypeDecl. It is a cache maintained by ASTContext::getTypedefType, + /// ASTContext::getTagDeclType, and ASTContext::getTemplateTypeParmType. Type *TypeForDecl; friend class ASTContext; protected: @@ -794,8 +794,7 @@ protected: /// CreateImpl - Deserialize a TypedefDecl. Called by Decl::Create. static TypedefDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C); - friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); - + friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); }; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 12ed5ff174..6d61da4698 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -63,6 +63,7 @@ public: Enum, // [DeclContext] Record, CXXRecord, // [DeclContext] + TemplateTypeParm, // ValueDecl EnumConstant, Function, // [DeclContext] @@ -74,6 +75,7 @@ public: ImplicitParam, CXXClassVar, ParmVar, + NonTypeTemplateParm, ObjCInterface, // [DeclContext] ObjCCompatibleAlias, ObjCClass, @@ -85,15 +87,15 @@ public: // For each non-leaf class, we now define a mapping to the first/last member // of the class, to allow efficient classof. - NamedFirst = Field , NamedLast = ParmVar, + NamedFirst = Field , NamedLast = NonTypeTemplateParm, FieldFirst = Field , FieldLast = ObjCAtDefsField, - ScopedFirst = Namespace , ScopedLast = ParmVar, - TypeFirst = Typedef , TypeLast = CXXRecord, + ScopedFirst = Namespace , ScopedLast = NonTypeTemplateParm, + TypeFirst = Typedef , TypeLast = TemplateTypeParm, TagFirst = Enum , TagLast = CXXRecord, RecordFirst = Record , RecordLast = CXXRecord, - ValueFirst = EnumConstant , ValueLast = ParmVar, + ValueFirst = EnumConstant , ValueLast = NonTypeTemplateParm, FunctionFirst = Function , FunctionLast = CXXConversion, - VarFirst = Var , VarLast = ParmVar + VarFirst = Var , VarLast = NonTypeTemplateParm }; /// IdentifierNamespace - According to C99 6.2.3, there are four namespaces, @@ -180,6 +182,7 @@ public: case Var: case ParmVar: case EnumConstant: + case NonTypeTemplateParm: case ObjCInterface: case ObjCCompatibleAlias: case OverloadedFunction: @@ -190,6 +193,7 @@ public: return IDNS_Ordinary; case Record: case CXXRecord: + case TemplateTypeParm: case Enum: return IDNS_Tag; case Namespace: diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 77eb8fade4..bd2ac22fbb 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -23,6 +23,70 @@ class CXXConstructorDecl; class CXXDestructorDecl; class CXXConversionDecl; +/// TemplateTypeParmDecl - Declaration of a template type parameter, +/// e.g., "T" in +/// @code +/// template<typename T> class vector; +/// @endcode +class TemplateTypeParmDecl : public TypeDecl { + /// Typename - Whether this template type parameter was declaration + /// with the 'typename' keyword. If false, it was declared with the + /// 'class' keyword. + bool Typename : 1; + + TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, bool Typename) + : TypeDecl(TemplateTypeParm, DC, L, Id, 0), Typename(Typename) { } + +public: + static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + bool Typename); + + /// wasDeclarationWithTypename - Whether this template type + /// parameter was declared with the 'typename' keyword. If not, it + /// was declared with the 'class' keyword. + bool wasDeclaredWithTypename() const { return Typename; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == TemplateTypeParm; + } + static bool classof(const TemplateTypeParmDecl *D) { return true; } + +protected: + /// EmitImpl - Serialize this TemplateTypeParmDecl. Called by Decl::Emit. + virtual void EmitImpl(llvm::Serializer& S) const; + + /// CreateImpl - Deserialize a TemplateTypeParmDecl. Called by Decl::Create. + static TemplateTypeParmDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C); + + friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); +}; + +/// NonTypeTemplateParmDecl - Declares a non-type template parameter, +/// e.g., "Size" in +/// @code +/// template<int Size> class array { }; +/// @endcode +class NonTypeTemplateParmDecl : public VarDecl { + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, + SourceLocation TSSL = SourceLocation()) + : VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, 0, TSSL) { } + +public: + static NonTypeTemplateParmDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + QualType T, SourceLocation TypeSpecStartLoc = SourceLocation()); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == NonTypeTemplateParm; + } + static bool classof(const NonTypeTemplateParmDecl *D) { return true; } +}; + /// OverloadedFunctionDecl - An instance of this class represents a /// set of overloaded functions. All of the functions have the same /// name and occur within the same scope. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index d6225e7375..411d35a5b1 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -30,6 +30,7 @@ namespace clang { class ASTContext; class Type; class TypedefDecl; + class TemplateTypeParmDecl; class TagDecl; class RecordDecl; class CXXRecordDecl; @@ -55,6 +56,7 @@ namespace clang { class ComplexType; class TagType; class TypedefType; + class TemplateTypeParmType; class FunctionType; class FunctionTypeProto; class ExtVectorType; @@ -238,6 +240,7 @@ public: Vector, ExtVector, FunctionNoProto, FunctionProto, TypeName, Tagged, ASQual, + TemplateTypeParm, ObjCInterface, ObjCQualifiedInterface, ObjCQualifiedId, TypeOfExp, TypeOfTyp, // GNU typeof extension. @@ -339,8 +342,9 @@ public: bool isObjCInterfaceType() const; // NSString or NSString<foo> bool isObjCQualifiedInterfaceType() const; // NSString<foo> bool isObjCQualifiedIdType() const; // id<foo> + bool isTemplateTypeParmType() const; // C++ template type parameter bool isOverloadType() const; // C++ overloaded function - + // Type Checking Functions: Check to see if this type is structurally the // specified type, ignoring typedefs and qualifiers, and return a pointer to // the best type we can. @@ -364,7 +368,8 @@ public: const ObjCInterfaceType *getAsObjCInterfaceType() const; const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const; const ObjCQualifiedIdType *getAsObjCQualifiedIdType() const; - + const TemplateTypeParmType *getAsTemplateTypeParmType() const; + /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC /// interface, return the interface type, otherwise return null. const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const; @@ -1174,7 +1179,30 @@ public: static bool classof(const EnumType *) { return true; } }; +class TemplateTypeParmType : public Type { + TemplateTypeParmDecl *Decl; + +protected: + TemplateTypeParmType(TemplateTypeParmDecl *D) + : Type(TemplateTypeParm, QualType(this, 0)), Decl(D) { } + + friend class ASTContext; // ASTContext creates these + +public: + TemplateTypeParmDecl *getDecl() const { return Decl; } + + virtual void getAsStringInternal(std::string &InnerString) const; + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateTypeParm; + } + static bool classof(const TemplateTypeParmType *T) { return true; } + +protected: + virtual void EmitImpl(llvm::Serializer& S) const; + static Type* CreateImpl(ASTContext& Context, llvm::Deserializer& D); + friend class Type; +}; /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for /// object oriented design. They basically correspond to C++ classes. There @@ -1462,6 +1490,10 @@ inline bool Type::isObjCQualifiedInterfaceType() const { inline bool Type::isObjCQualifiedIdType() const { return isa<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType()); } +inline bool Type::isTemplateTypeParmType() const { + return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType()); +} + inline bool Type::isOverloadType() const { if (const BuiltinType *BT = getAsBuiltinType()) return BT->getKind() == BuiltinType::Overload; diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index a85e0df324..eea6fe4b96 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -944,6 +944,12 @@ DIAG(err_ovl_ambiguous_object_call, ERROR, DIAG(err_ovl_surrogate_cand, NOTE, "conversion candidate of type %0") +/// C++ Templates Semantic Analysis +DIAG(err_template_param_shadow, ERROR, + "declaration of %0 shadows template parameter") +DIAG(note_template_param_here, NOTE, + "template parameter is declared here") + DIAG(err_unexpected_typedef, ERROR, "unexpected type name %0: expected expression") DIAG(err_unexpected_namespace, ERROR, diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h index 8cb2f7434c..5695fc0be1 100644 --- a/include/clang/Parse/Scope.h +++ b/include/clang/Parse/Scope.h @@ -87,7 +87,13 @@ private: /// BlockParent - This is a direct link to the immediately containing /// BlockScope if this scope is not one, or null if there is none. Scope *BlockParent; - + + /// TemplateParamParent - This is a direct link to the + /// immediately containing template parameter scope. In the + /// case of nested templates, template parameter scopes can have + /// other template parameter scopes as parents. + Scope *TemplateParamParent; + /// DeclsInScope - This keeps track of all declarations in this scope. When /// the declaration is added to the scope, it is set as the current /// declaration for the identifier in the IdentifierTable. When the scope is @@ -147,6 +153,9 @@ public: Scope *getBlockParent() { return BlockParent; } const Scope *getBlockParent() const { return BlockParent; } + + Scope *getTemplateParamParent() { return TemplateParamParent; } + const Scope *getTemplateParamParent() const { return TemplateParamParent; } typedef DeclSetTy::iterator decl_iterator; decl_iterator decl_begin() const { return DeclsInScope.begin(); } @@ -196,18 +205,20 @@ public: BreakParent = AnyParent->BreakParent; ContinueParent = AnyParent->ContinueParent; BlockParent = AnyParent->BlockParent; + TemplateParamParent = AnyParent->TemplateParamParent; } else { FnParent = BreakParent = ContinueParent = BlockParent = 0; + TemplateParamParent = 0; } // If this scope is a function or contains breaks/continues, remember it. - if (Flags & FnScope) FnParent = this; - if (Flags & BreakScope) BreakParent = this; - if (Flags & ContinueScope) ContinueParent = this; - if (Flags & BlockScope) BlockParent = this; - + if (Flags & FnScope) FnParent = this; + if (Flags & BreakScope) BreakParent = this; + if (Flags & ContinueScope) ContinueParent = this; + if (Flags & BlockScope) BlockParent = this; + if (Flags & TemplateParamScope) TemplateParamParent = this; DeclsInScope.clear(); - } + } }; } // end namespace clang diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e1b56ad6fb..7c8b4b1b41 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -943,6 +943,8 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) return getTypedefType(Typedef); + else if (TemplateTypeParmDecl *TP = dyn_cast<TemplateTypeParmDecl>(Decl)) + return getTemplateTypeParmType(TP); else if (ObjCInterfaceDecl *ObjCInterface = dyn_cast<ObjCInterfaceDecl>(Decl)) return getObjCInterfaceType(ObjCInterface); @@ -982,6 +984,16 @@ QualType ASTContext::getTypedefType(TypedefDecl *Decl) { return QualType(Decl->TypeForDecl, 0); } +/// getTemplateTypeParmType - Return the unique reference to the type +/// for the specified template type parameter declaration. +QualType ASTContext::getTemplateTypeParmType(TemplateTypeParmDecl *Decl) { + if (!Decl->TypeForDecl) { + Decl->TypeForDecl = new TemplateTypeParmType(Decl); + Types.push_back(Decl->TypeForDecl); + } + return QualType(Decl->TypeForDecl, 0); +} + /// getObjCInterfaceType - Return the unique reference to the type for the /// specified ObjC interface decl. QualType ASTContext::getObjCInterfaceType(ObjCInterfaceDecl *Decl) { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 5cb2a3e64f..7b5df1c194 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -239,6 +239,8 @@ void Decl::addDeclKind(Kind k) { case CXXField: nCXXFieldDecls++; break; case CXXRecord: nCXXSUC++; break; // FIXME: Statistics for C++ decls. + case TemplateTypeParm: + case NonTypeTemplateParm: case CXXMethod: case CXXConstructor: case CXXDestructor: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 6be9eaf1a3..a26803caec 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -19,7 +19,23 @@ using namespace clang; //===----------------------------------------------------------------------===// // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// - + +TemplateTypeParmDecl * +TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + bool Typename) { + void *Mem = C.getAllocator().Allocate<TemplateTypeParmDecl>(); + return new (Mem) TemplateTypeParmDecl(DC, L, Id, Typename); +} + +NonTypeTemplateParmDecl * +NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, SourceLocation TypeSpecStartLoc) { + void *Mem = C.getAllocator().Allocate<NonTypeTemplateParmDecl>(); + return new (Mem) NonTypeTemplateParmDecl(DC, L, Id, T, TypeSpecStartLoc); +} + CXXFieldDecl *CXXFieldDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, QualType T, bool Mut, Expr *BW) { diff --git a/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp index 8a4612b674..29714c0125 100644 --- a/lib/AST/DeclSerialization.cpp +++ b/lib/AST/DeclSerialization.cpp @@ -88,6 +88,10 @@ Decl* Decl::Create(Deserializer& D, ASTContext& C) { Dcl = TypedefDecl::CreateImpl(D, C); break; + case TemplateTypeParm: + Dcl = TemplateTypeParmDecl::CreateImpl(D, C); + break; + case FileScopeAsm: Dcl = FileScopeAsmDecl::CreateImpl(D, C); break; @@ -630,6 +634,27 @@ TypedefDecl* TypedefDecl::CreateImpl(Deserializer& D, ASTContext& C) { } //===----------------------------------------------------------------------===// +// TemplateTypeParmDecl Serialization. +//===----------------------------------------------------------------------===// + +void TemplateTypeParmDecl::EmitImpl(Serializer& S) const { + S.EmitBool(Typename); + ScopedDecl::EmitInRec(S); + ScopedDecl::EmitOutRec(S); +} + +TemplateTypeParmDecl * +TemplateTypeParmDecl::CreateImpl(Deserializer& D, ASTContext& C) { + bool Typename = D.ReadBool(); + void *Mem = C.getAllocator().Allocate<TemplateTypeParmDecl>(); + TemplateTypeParmDecl *decl + = new (Mem) TemplateTypeParmDecl(0, SourceLocation(), NULL, Typename); + decl->ScopedDecl::ReadInRec(D, C); + decl->ScopedDecl::ReadOutRec(D, C); + return decl; +} + +//===----------------------------------------------------------------------===// // LinkageSpec Serialization. //===----------------------------------------------------------------------===// diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index e4386eceda..a3264b010b 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -341,6 +341,12 @@ bool Expr::hasLocalSideEffect() const { /// DeclCanBeLvalue - Determine whether the given declaration can be /// an lvalue. This is a helper routine for isLvalue. static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { + // C++ [temp.param]p6: + // A non-type non-reference template-parameter is not an lvalue. + if (const NonTypeTemplateParmDecl *NTTParm + = dyn_cast<NonTypeTemplateParmDecl>(Decl)) + return NTTParm->getType()->isReferenceType(); + return isa<VarDecl>(Decl) || isa<CXXFieldDecl>(Decl) || // C++ 3.10p2: An lvalue refers to an object or function. (Ctx.getLangOptions().CPlusPlus && diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 6aa3c8eb38..303fc7e7ca 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -443,6 +443,11 @@ const ObjCQualifiedIdType *Type::getAsObjCQualifiedIdType() const { return dyn_cast<ObjCQualifiedIdType>(CanonicalType); } +const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const { + // There is no sugar for template type parameters, so just return + // the canonical type pointer if it is the right class. + return dyn_cast<TemplateTypeParmType>(CanonicalType); +} bool Type::isIntegerType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) @@ -1002,6 +1007,12 @@ void TypedefType::getAsStringInternal(std::string &InnerString) const { InnerString = getDecl()->getIdentifier()->getName() + InnerString; } +void TemplateTypeParmType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'parmname X'. + InnerString = ' ' + InnerString; + InnerString = getDecl()->getIdentifier()->getName() + InnerString; +} + void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp index db93e4b103..3bdc946de7 100644 --- a/lib/AST/TypeSerialization.cpp +++ b/lib/AST/TypeSerialization.cpp @@ -110,6 +110,10 @@ void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) { D.RegisterPtr(PtrID,TypedefType::CreateImpl(Context,D)); break; + case Type::TemplateTypeParm: + D.RegisterPtr(PtrID,TemplateTypeParmType::CreateImpl(Context, D)); + break; + case Type::VariableArray: D.RegisterPtr(PtrID,VariableArrayType::CreateImpl(Context,D)); break; @@ -272,6 +276,25 @@ Type* TypedefType::CreateImpl(ASTContext& Context, Deserializer& D) { } //===----------------------------------------------------------------------===// +// TemplateTypeParmType +//===----------------------------------------------------------------------===// + +void TemplateTypeParmType::EmitImpl(Serializer& S) const { + S.EmitPtr(getDecl()); +} + +Type* TemplateTypeParmType::CreateImpl(ASTContext& Context, Deserializer& D) { + std::vector<Type*>& Types = + const_cast<std::vector<Type*>&>(Context.getTypes()); + + TemplateTypeParmType* T = new TemplateTypeParmType(NULL); + Types.push_back(T); + + D.ReadPtr(T->Decl); // May be backpatched. + return T; +} + +//===----------------------------------------------------------------------===// // VariableArrayType //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 18cfdeaff6..fbf1120407 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -190,6 +190,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { switch (Ty.getTypeClass()) { case Type::TypeName: // typedef isn't canonical. + case Type::TemplateTypeParm:// template type parameters never generated case Type::TypeOfExp: // typeof isn't canonical. case Type::TypeOfTyp: // typeof isn't canonical. assert(0 && "Non-canonical type, shouldn't happen"); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 6bcf81d906..5801f9ecb7 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -41,7 +41,7 @@ Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) { SourceLocation TemplateLoc = ConsumeToken(); // Enter template-parameter scope. - EnterScope(Scope::TemplateParamScope|Scope::DeclScope); + EnterScope(Scope::TemplateParamScope); // Try to parse the template parameters, and the declaration if // successful. diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f23fedf2b1..bce73ccdeb 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -441,7 +441,7 @@ Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() { if (Tok.is(tok::l_brace)) { // This recovery skips the entire function body. It would be nice - // to simply call ParseFunctionDefintion() below, however Sema + // to simply call ParseFunctionDefinition() below, however Sema // assumes the declarator represents a function, not a typedef. ConsumeBrace(); SkipUntil(tok::r_brace, true); diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index cb28fca432..fd961fa2c0 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -18,5 +18,6 @@ add_clang_library(clangSema SemaNamedCast.cpp SemaOverload.cpp SemaStmt.cpp + SemaTemplate.cpp SemaType.cpp ) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ef15064638..f1d0ee2da0 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -988,6 +988,17 @@ public: bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); + //===--------------------------------------------------------------------===// + // C++ Templates [C++ 14] + // + bool isTemplateParameterDecl(Decl *D); + bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); + virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc); + virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D); + // Objective-C declarations. virtual DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4fd13c3f96..c893d27597 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -39,7 +39,8 @@ Sema::TypeTy *Sema::isTypeName(IdentifierInfo &II, Scope *S, if (IIDecl && (isa<TypedefDecl>(IIDecl) || isa<ObjCInterfaceDecl>(IIDecl) || - isa<TagDecl>(IIDecl))) + isa<TagDecl>(IIDecl) || + isa<TemplateTypeParmDecl>(IIDecl))) return IIDecl; return 0; } @@ -148,7 +149,8 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) { void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (S->decl_empty()) return; - assert((S->getFlags() & Scope::DeclScope) &&"Scope shouldn't contain decls!"); + assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && + "Scope shouldn't contain decls!"); for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); I != E; ++I) { @@ -165,7 +167,10 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { // We only want to remove the decls from the identifier decl chains for // local scopes, when inside a function/method. - if (S->getFnParent() != 0) + // However, we *always* remove template parameters, since they are + // purely lexically scoped (and can never be found by qualified + // name lookup). + if (S->getFnParent() != 0 || isa<TemplateTypeParmDecl>(D)) IdResolver.RemoveDecl(D); // Chain this decl to the containing DeclContext. @@ -863,6 +868,15 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { } } + if (PrevDecl && isTemplateParameterDecl(PrevDecl)) { + // Maybe we will complain about the shadowed template parameter. + InvalidDecl + = InvalidDecl || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), + PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. @@ -1991,7 +2005,12 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // among each other. Here they can only shadow globals, which is ok. IdentifierInfo *II = D.getIdentifier(); if (Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S)) { - if (S->isDeclScope(PrevDecl)) { + if (isTemplateParameterDecl(PrevDecl)) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } else if (S->isDeclScope(PrevDecl)) { Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II; // Recover by removing the name @@ -2250,6 +2269,13 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, PrevDecl = dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag,S)); } + if (PrevDecl && isTemplateParameterDecl(PrevDecl)) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + if (PrevDecl) { assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) && "unexpected Decl type"); @@ -2386,6 +2412,13 @@ Sema::DeclTy *Sema::ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK, PrevDecl = dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag,S)); } + if (PrevDecl && isTemplateParameterDecl(PrevDecl)) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + if (PrevDecl) { assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) && "unexpected Decl type"); @@ -2875,7 +2908,15 @@ Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl, // Verify that there isn't already something declared with this name in this // scope. - if (Decl *PrevDecl = LookupDecl(Id, Decl::IDNS_Ordinary, S)) { + Decl *PrevDecl = LookupDecl(Id, Decl::IDNS_Ordinary, S); + if (PrevDecl && isTemplateParameterDecl(PrevDecl)) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + if (PrevDecl) { // When in C++, we may get a TagDecl with the same name; in this case the // enum constant will 'hide' the tag. assert((getLangOptions().CPlusPlus || !isa<TagDecl>(PrevDecl)) && diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 9da662e476..01a453d3be 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/ |