diff options
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 11 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 51 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 14 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 116 |
5 files changed, 188 insertions, 5 deletions
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index cb28fca432d..fd961fa2c0b 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/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/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index ef150646381..f1d0ee2da01 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 4fd13c3f96b..c893d275978 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 9da662e4766..01a453d3be6 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -66,6 +66,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Check for another declaration kind with the same name. Decl *PrevDecl = LookupDecl(ClassName, Decl::IDNS_Ordinary, TUScope); + if (PrevDecl && isTemplateParameterDecl(PrevDecl)) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); @@ -742,6 +749,13 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, for (unsigned i = 0; i != NumElts; ++i) { // Check for another declaration kind with the same name. Decl *PrevDecl = LookupDecl(IdentList[i], Decl::IDNS_Ordinary, TUScope); + if (PrevDecl && isTemplateParameterDecl(PrevDecl)) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { // GCC apparently allows the following idiom: // diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp new file mode 100644 index 00000000000..749d181baf0 --- /dev/null +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -0,0 +1,116 @@ +//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/ + +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//+//===----------------------------------------------------------------------===/ + +// +// This file implements semantic analysis for C++ templates. +//+//===----------------------------------------------------------------------===/ + +#include "Sema.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Basic/LangOptions.h" + +using namespace clang; + +/// isTemplateParameterDecl - Determines whether the given declaration +/// 'D' names a template parameter. +bool Sema::isTemplateParameterDecl(Decl *D) { + return isa<TemplateTypeParmDecl>(D) || isa<NonTypeTemplateParmDecl>(D); +} + +/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining +/// that the template parameter 'PrevDecl' is being shadowed by a new +/// declaration at location Loc. Returns true to indicate that this is +/// an error, and false otherwise. +bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { + assert(isTemplateParameterDecl(PrevDecl) && "Not a template parameter"); + + // Microsoft Visual C++ permits template parameters to be shadowed. + if (getLangOptions().Microsoft) + return false; + + // C++ [temp.local]p4: + // A template-parameter shall not be redeclared within its + // scope (including nested scopes). + Diag(Loc, diag::err_template_param_shadow) + << cast<NamedDecl>(PrevDecl)->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_template_param_here); + return true; +} + +/// ActOnTypeParameter - Called when a C++ template type parameter +/// (e.g., "typename T") has been parsed. Typename specifies whether +/// the keyword "typename" was used to declare the type parameter +/// (otherwise, "class" was used), and KeyLoc is the location of the +/// "class" or "typename" keyword. ParamName is the name of the +/// parameter (NULL indicates an unnamed template parameter) and +/// ParamName is the location of the parameter name (if any). +/// If the type parameter has a default argument, it will be added +/// later via ActOnTypeParameterDefault. +Sema::DeclTy *Sema::ActOnTypeParameter(Scope *S, bool Typename, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc) { + assert(S->isTemplateParamScope() && + "Template type parameter not in template parameter scope!"); + bool Invalid = false; + + if (ParamName) { + Decl *PrevDecl = LookupDecl(ParamName, Decl::IDNS_Tag, S); + if (PrevDecl && isTemplateParameterDecl(PrevDecl)) + Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc, + PrevDecl); + } + + TemplateTypeParmDecl *Param + = TemplateTypeParmDecl::Create(Context, CurContext, + ParamNameLoc, ParamName, Typename); + if (Invalid) + Param->setInvalidDecl(); + + if (ParamName) { + // Add the template parameter into the current scope. + S->AddDecl(Param); + IdResolver.AddDecl(Param); + } + + return Param; +} + +/// ActOnNonTypeTemplateParameter - Called when a C++ non-type +/// template parameter (e.g., "int Size" in "template<int Size> +/// class Array") has been parsed. S is the current scope and D is +/// the parsed declarator. +Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D) { + QualType T = GetTypeForDeclarator(D, S); + + assert(S->isTemplateParamScope() && + "Template type parameter not in template parameter scope!"); + bool Invalid = false; + + IdentifierInfo *ParamName = D.getIdentifier(); + if (ParamName) { + Decl *PrevDecl = LookupDecl(ParamName, Decl::IDNS_Tag, S); + if (PrevDecl && isTemplateParameterDecl(PrevDecl)) + Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), + PrevDecl); + } + + NonTypeTemplateParmDecl *Param + = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), + ParamName, T); + if (Invalid) + Param->setInvalidDecl(); + + if (D.getIdentifier()) { + // Add the template parameter into the current scope. + S->AddDecl(Param); + IdResolver.AddDecl(Param); + } + return Param; +} |

