From 2d1c5d313cd0c229cc614e74baa4c5756a4b46f4 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Sun, 27 Apr 2008 13:50:30 +0000 Subject: [PATCH] Parsing of namespaces: -NamespaceDecl for the AST -Checks for name clashes between namespaces and tag/normal declarations. This commit doesn't implement proper name lookup for namespaces. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50321 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 60 ++++++++++++++++++ include/clang/AST/DeclBase.h | 11 +++- include/clang/Basic/DiagnosticKinds.def | 2 + include/clang/Parse/Action.h | 14 +++++ lib/AST/Decl.cpp | 21 ++++++- lib/AST/DeclSerialization.cpp | 30 ++++++++- lib/Parse/ParseDeclCXX.cpp | 20 ++++-- lib/Sema/Sema.h | 6 ++ lib/Sema/SemaDecl.cpp | 81 ++++++++++++++----------- lib/Sema/SemaDeclCXX.cpp | 77 +++++++++++++++++++++++ lib/Sema/SemaExpr.cpp | 4 ++ test/Sema/cxx-namespace.cpp | 15 +++++ 12 files changed, 294 insertions(+), 47 deletions(-) create mode 100644 test/Sema/cxx-namespace.cpp diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index d16fa6fbf1..ea9ab0cc0d 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -127,6 +127,66 @@ protected: void ReadOutRec(llvm::Deserializer& D, ASTContext& C); }; +/// NamespaceDecl - Represent a C++ namespace. +class NamespaceDecl : public ScopedDecl, public DeclContext { + SourceLocation LBracLoc, RBracLoc; + + // For extended namespace definitions: + // + // namespace A { int x; } + // namespace A { int y; } + // + // there will be one NamespaceDecl for each declaration. + // NextDeclarator points to the next extended declaration. + // OrigNamespace points to the original namespace declaration. + // OrigNamespace of the first namespace decl points to itself. + + NamespaceDecl *OrigNamespace; + + NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) + : ScopedDecl(Namespace, DC, L, Id, 0), DeclContext(Namespace) { + OrigNamespace = this; + } +public: + static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id); + + NamespaceDecl *getNextNamespace() { + return cast_or_null(getNextDeclarator()); + } + const NamespaceDecl *getNextNamespace() const { + return cast_or_null(getNextDeclarator()); + } + void setNextNamespace(NamespaceDecl *ND) { setNextDeclarator(ND); } + + NamespaceDecl *getOriginalNamespace() const { + return OrigNamespace; + } + void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; } + + SourceRange getSourceRange() const { + return SourceRange(LBracLoc, RBracLoc); + } + + SourceLocation getLBracLoc() const { return LBracLoc; } + SourceLocation getRBracLoc() const { return RBracLoc; } + void setLBracLoc(SourceLocation LBrace) { LBracLoc = LBrace; } + void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == Namespace; } + static bool classof(const NamespaceDecl *D) { return true; } + +protected: + /// EmitImpl - Serialize this NamespaceDecl. Called by Decl::Emit. + virtual void EmitImpl(llvm::Serializer& S) const; + + /// CreateImpl - Deserialize a NamespaceDecl. Called by Decl::Create. + static NamespaceDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C); + + friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); +}; + /// ValueDecl - Represent the declaration of a variable (in which case it is /// an lvalue) a function (in which case it is a function designator) or /// an enum constant. diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 84e822e921..98a72ea7f0 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -20,6 +20,7 @@ namespace clang { class TranslationUnitDecl; +class NamespaceDecl; class FunctionDecl; class ObjCMethodDecl; class EnumDecl; @@ -46,6 +47,7 @@ public: ObjCProtocol, ObjCProperty, // ScopedDecl + Namespace, // TypeDecl Typedef, // TagDecl @@ -72,7 +74,7 @@ public: // of the class, to allow efficient classof. NamedFirst = Field, NamedLast = ParmVar, FieldFirst = Field, FieldLast = ObjCIvar, - ScopedFirst = Typedef, ScopedLast = ParmVar, + ScopedFirst = Namespace, ScopedLast = ParmVar, TypeFirst = Typedef, TypeLast = Class, TagFirst = Enum , TagLast = Class, RecordFirst = Struct , RecordLast = Class, @@ -163,6 +165,8 @@ public: case Class: case Enum: return IDNS_Tag; + case Namespace: + return IdentifierNamespace(IDNS_Tag | IDNS_Ordinary); } } // global temp stats (until we have a per-module visitor) @@ -198,6 +202,7 @@ protected: /// can act as declaration contexts. These decls are: /// /// TranslationUnitDecl +/// NamespaceDecl /// FunctionDecl /// ObjCMethodDecl /// EnumDecl @@ -221,6 +226,8 @@ class DeclContext { switch(DK) { case Decl::TranslationUnit: return static_cast(const_cast(D)); + case Decl::Namespace: + return static_cast(const_cast(D)); case Decl::Function: return static_cast(const_cast(D)); case Decl::ObjCMethod: @@ -262,6 +269,7 @@ public: static bool classof(const Decl *D) { switch (D->getKind()) { case Decl::TranslationUnit: + case Decl::Namespace: case Decl::Function: case Decl::ObjCMethod: case Decl::ObjCInterface: @@ -273,6 +281,7 @@ public: } static bool classof(const DeclContext *D) { return true; } static bool classof(const TranslationUnitDecl *D) { return true; } + static bool classof(const NamespaceDecl *D) { return true; } static bool classof(const FunctionDecl *D) { return true; } static bool classof(const ObjCMethodDecl *D) { return true; } static bool classof(const EnumDecl *D) { return true; } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 6f58ae1e82..79b28cb889 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -666,6 +666,8 @@ DIAG(err_first_label, ERROR, DIAG(err_unexpected_typedef, ERROR, "unexpected type name '%0': expected expression") +DIAG(err_unexpected_namespace, ERROR, + "unexpected namespace name '%0': expected expression") DIAG(err_unexpected_typedef_ident, ERROR, "unexpected type name '%0': expected identifier") DIAG(err_undeclared_var_use, ERROR, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 75d06e3b92..f283fff22c 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -133,6 +133,20 @@ public: return Group; } + /// ActOnStartNamespaceDef - This is called at the start of a namespace + /// definition. + virtual DeclTy *ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + SourceLocation LBrace) { + return 0; + } + + /// ActOnFinishNamespaceDef - This callback is called after a namespace is + /// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef. + virtual void ActOnFinishNamespaceDef(DeclTy *Dcl,SourceLocation RBrace) { + return; + } + /// ActOnStartOfFunctionDef - This is called at the start of a function /// definition, instead of calling ActOnDeclarator. The Declarator includes /// information about formal arguments that are part of this function. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 3c7401feab..d2febb9cd3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -29,6 +29,7 @@ static unsigned nParmVars = 0; static unsigned nSUC = 0; static unsigned nEnumConst = 0; static unsigned nEnumDecls = 0; +static unsigned nNamespaces = 0; static unsigned nTypedef = 0; static unsigned nFieldDecls = 0; static unsigned nInterfaceDecls = 0; @@ -57,6 +58,7 @@ static DeclAttrMapTy *DeclAttrs = 0; const char *Decl::getDeclKindName() const { switch (DeclKind) { default: assert(0 && "Unknown decl kind!"); + case Namespace: return "Namespace"; case Typedef: return "Typedef"; case Function: return "Function"; case Var: return "Var"; @@ -85,7 +87,11 @@ void Decl::PrintStats() { fprintf(stderr, " %d decls total.\n", int(nFuncs+nVars+nParmVars+nFieldDecls+nSUC+ nEnumDecls+nEnumConst+nTypedef+nInterfaceDecls+nClassDecls+ - nMethodDecls+nProtocolDecls+nCategoryDecls+nIvarDecls)); + nMethodDecls+nProtocolDecls+nCategoryDecls+nIvarDecls+ + nNamespaces)); + fprintf(stderr, " %d namespace decls, %d each (%d bytes)\n", + nNamespaces, (int)sizeof(NamespaceDecl), + int(nNamespaces*sizeof(NamespaceDecl))); fprintf(stderr, " %d function decls, %d each (%d bytes)\n", nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl))); fprintf(stderr, " %d variable decls, %d each (%d bytes)\n", @@ -170,12 +176,14 @@ void Decl::PrintStats() { nObjCPropertyDecl*sizeof(ObjCPropertyDecl)+ nObjCPropertyImplDecl*sizeof(ObjCPropertyImplDecl)+ nLinkageSpecDecl*sizeof(LinkageSpecDecl)+ - nFileScopeAsmDecl*sizeof(FileScopeAsmDecl))); + nFileScopeAsmDecl*sizeof(FileScopeAsmDecl)+ + nNamespaces*sizeof(NamespaceDecl))); } void Decl::addDeclKind(Kind k) { switch (k) { + case Namespace: nNamespaces++; break; case Typedef: nTypedef++; break; case Function: nFuncs++; break; case Var: nVars++; break; @@ -205,12 +213,18 @@ void Decl::addDeclKind(Kind k) { //===----------------------------------------------------------------------===// // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// - + TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { void *Mem = C.getAllocator().Allocate(); return new (Mem) TranslationUnitDecl(); } +NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) NamespaceDecl(DC, L, Id); +} + VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, @@ -342,6 +356,7 @@ void Decl::Destroy(ASTContext& C) const { CASE(ObjCImplementation); CASE(ObjCProtocol); CASE(ObjCProperty); + CASE(Namespace); CASE(Typedef); CASE(Enum); CASE(EnumConstant); diff --git a/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp index 6186649e70..cbae831308 100644 --- a/lib/AST/DeclSerialization.cpp +++ b/lib/AST/DeclSerialization.cpp @@ -44,6 +44,9 @@ Decl* Decl::Create(Deserializer& D, ASTContext& C) { case TranslationUnit: return TranslationUnitDecl::CreateImpl(D, C); + case Namespace: + return NamespaceDecl::CreateImpl(D, C); + case Var: return VarDecl::CreateImpl(D, C); @@ -206,14 +209,37 @@ void TranslationUnitDecl::EmitImpl(llvm::Serializer& S) const TranslationUnitDecl* TranslationUnitDecl::CreateImpl(Deserializer& D, ASTContext& C) { void *Mem = C.getAllocator().Allocate(); - TranslationUnitDecl* decl = - new (Mem) TranslationUnitDecl(); + TranslationUnitDecl* decl = new (Mem) TranslationUnitDecl(); decl->Decl::ReadInRec(D, C); return decl; } +//===----------------------------------------------------------------------===// +// NamespaceDecl Serialization. +//===----------------------------------------------------------------------===// + +void NamespaceDecl::EmitImpl(llvm::Serializer& S) const +{ + ScopedDecl::EmitInRec(S); + S.Emit(getLBracLoc()); + S.Emit(getRBracLoc()); + ScopedDecl::EmitOutRec(S); +} + +NamespaceDecl* NamespaceDecl::CreateImpl(Deserializer& D, ASTContext& C) { + void *Mem = C.getAllocator().Allocate(); + NamespaceDecl* decl = new (Mem) NamespaceDecl(0, SourceLocation(), 0); + + decl->ScopedDecl::ReadInRec(D, C); + decl->LBracLoc = SourceLocation::ReadVal(D); + decl->RBracLoc = SourceLocation::ReadVal(D); + decl->ScopedDecl::ReadOutRec(D, C); + + return decl; +} + //===----------------------------------------------------------------------===// // VarDecl Serialization. //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 04cd254193..5d49f4dd59 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -62,17 +62,25 @@ Parser::DeclTy *Parser::ParseNamespace(unsigned Context) { // FIXME: Verify no attributes were present. // FIXME: parse this. } else if (Tok.is(tok::l_brace)) { + SourceLocation LBrace = ConsumeBrace(); - // FIXME: push a scope, push a namespace decl. - - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - // FIXME capture the decls. + + // Enter a scope for the namespace. + EnterScope(Scope::DeclScope); + + DeclTy *NamespcDecl = + Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace); + + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) ParseExternalDeclaration(); - } SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); + Actions.ActOnFinishNamespaceDef(NamespcDecl, RBrace); + + ExitScope(); + + return NamespcDecl; - // FIXME: act on this. } else { unsigned D = Ident ? diag::err_expected_lbrace : diag::err_expected_ident_lbrace; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 33d3ce4ece..37b9805d0a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -552,6 +552,12 @@ public: ExprTy *expr, TypeTy *type, SourceLocation RPLoc); + // Act on C++ namespaces + virtual DeclTy *ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + SourceLocation LBrace); + virtual void ActOnFinishNamespaceDef(DeclTy *Dcl, SourceLocation RBrace); + /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, TypeTy *Ty, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 373aaceb87..61cfa798c2 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -43,7 +43,7 @@ Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) { } void Sema::PushDeclContext(DeclContext *DC) { - assert( ( (DC->isFunctionOrMethod() && isa(CurContext)) + assert( ( (isa(DC) && isa(CurContext)) || DC->getParent() == CurContext ) && "The next DeclContext should be directly contained in the current one."); CurContext = DC; @@ -52,7 +52,7 @@ void Sema::PushDeclContext(DeclContext *DC) { void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); // If CurContext is a ObjC method, getParent() will return NULL. - CurContext = CurContext->isFunctionOrMethod() + CurContext = isa(CurContext) ? Context.getTranslationUnitDecl() : CurContext->getParent(); } @@ -1332,42 +1332,53 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, // If this is a named struct, check to see if there was a previous forward // declaration or definition. - if (TagDecl *PrevDecl = - dyn_cast_or_null(LookupDecl(Name, Decl::IDNS_Tag, S))) { + // Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up. + if (ScopedDecl *PrevDecl = + dyn_cast_or_null(LookupDecl(Name, Decl::IDNS_Tag, S))) { - // If this is a use of a previous tag, or if the tag is already declared in - // the same scope (so that the definition/declaration completes or - // rementions the tag), reuse the decl. - if (TK == TK_Reference || S->isDeclScope(PrevDecl)) { - // Make sure that this wasn't declared as an enum and now used as a struct - // or something similar. - if (PrevDecl->getKind() != Kind) { - Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_use); - } - - // If this is a use or a forward declaration, we're good. - if (TK != TK_Definition) - return PrevDecl; - - // Diagnose attempts to redefine a tag. - if (PrevDecl->isDefinition()) { - Diag(NameLoc, diag::err_redefinition, Name->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - // If this is a redefinition, recover by making this struct be - // anonymous, which will make any later references get the previous - // definition. - Name = 0; - } else { - // Okay, this is definition of a previously declared or referenced tag. - // Move the location of the decl to be the definition site. - PrevDecl->setLocation(NameLoc); - return PrevDecl; + assert((isa(PrevDecl) || isa(PrevDecl)) && + "unexpected Decl type"); + if (TagDecl *PrevTagDecl = dyn_cast(PrevDecl)) { + // If this is a use of a previous tag, or if the tag is already declared in + // the same scope (so that the definition/declaration completes or + // rementions the tag), reuse the decl. + if (TK == TK_Reference || S->isDeclScope(PrevDecl)) { + // Make sure that this wasn't declared as an enum and now used as a struct + // or something similar. + if (PrevDecl->getKind() != Kind) { + Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_use); + } + + // If this is a use or a forward declaration, we're good. + if (TK != TK_Definition) + return PrevDecl; + + // Diagnose attempts to redefine a tag. + if (PrevTagDecl->isDefinition()) { + Diag(NameLoc, diag::err_redefinition, Name->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + // If this is a redefinition, recover by making this struct be + // anonymous, which will make any later references get the previous + // definition. + Name = 0; + } else { + // Okay, this is definition of a previously declared or referenced tag. + // Move the location of the decl to be the definition site. + PrevDecl->setLocation(NameLoc); + return PrevDecl; + } } + // If we get here, this is a definition of a new struct type in a nested + // scope, e.g. "struct foo; void bar() { struct foo; }", just create a new + // type. + } else { + // The tag name clashes with a namespace name, issue an error and recover + // by making this tag be anonymous. + Diag(NameLoc, diag::err_redefinition_different_kind, Name->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + Name = 0; } - // If we get here, this is a definition of a new struct type in a nested - // scope, e.g. "struct foo; void bar() { struct foo; }", just create a new - // type. } // If there is an identifier, use the location of the identifier as the diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 251fb5e72b..827c737ad4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -17,6 +17,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" +#include "clang/Parse/Scope.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/Compiler.h" @@ -284,3 +285,79 @@ void Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, // FIXME: Attach base class to the record. } + + +//===----------------------------------------------------------------------===// +// Namespace Handling +//===----------------------------------------------------------------------===// + +/// ActOnStartNamespaceDef - This is called at the start of a namespace +/// definition. +Sema::DeclTy *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, + SourceLocation IdentLoc, + IdentifierInfo *II, + SourceLocation LBrace) { + NamespaceDecl *Namespc = + NamespaceDecl::Create(Context, CurContext, IdentLoc, II); + Namespc->setLBracLoc(LBrace); + + Scope *DeclRegionScope = NamespcScope->getParent(); + + if (II) { + // C++ [namespace.def]p2: + // The identifier in an original-namespace-definition shall not have been + // previously defined in the declarative region in which the + // original-namespace-definition appears. The identifier in an + // original-namespace-definition is the name of the namespace. Subsequently + // in that declarative region, it is treated as an original-namespace-name. + + Decl *PrevDecl = + LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, + /*enableLazyBuiltinCreation=*/false); + + if (PrevDecl && DeclRegionScope->isDeclScope(PrevDecl)) { + if (NamespaceDecl *OrigNS = dyn_cast(PrevDecl)) { + // This is an extended namespace definition. + // Attach this namespace decl to the chain of extended namespace + // definitions. + NamespaceDecl *NextNS = OrigNS; + while (NextNS->getNextNamespace()) + NextNS = NextNS->getNextNamespace(); + + NextNS->setNextNamespace(Namespc); + Namespc->setOriginalNamespace(OrigNS); + + // We won't add this decl to the current scope. We want the namespace + // name to return the original namespace decl during a name lookup. + } else { + // This is an invalid name redefinition. + Diag(Namespc->getLocation(), diag::err_redefinition_different_kind, + Namespc->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + Namespc->setInvalidDecl(); + // Continue on to push Namespc as current DeclContext and return it. + } + } else { + // This namespace name is declared for the first time. + PushOnScopeChains(Namespc, DeclRegionScope); + } + } + else { + // FIXME: Handle anonymous namespaces + } + + // Although we could have an invalid decl (i.e. the namespace name is a + // redefinition), push it as current DeclContext and try to continue parsing. + PushDeclContext(Namespc->getOriginalNamespace()); + return Namespc; +} + +/// ActOnFinishNamespaceDef - This callback is called after a namespace is +/// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef. +void Sema::ActOnFinishNamespaceDef(DeclTy *D, SourceLocation RBrace) { + Decl *Dcl = static_cast(D); + NamespaceDecl *Namespc = dyn_cast_or_null(Dcl); + assert(Namespc && "Invalid parameter, expected NamespaceDecl"); + Namespc->setRBracLoc(RBrace); + PopDeclContext(); +} diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e3298f37af..edd9284a39 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -128,6 +128,8 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, return Diag(Loc, diag::err_unexpected_typedef, II.getName()); if (isa(D)) return Diag(Loc, diag::err_unexpected_interface, II.getName()); + if (isa(D)) + return Diag(Loc, diag::err_unexpected_namespace, II.getName()); assert(0 && "Invalid decl"); abort(); @@ -2313,3 +2315,5 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, return isInvalid; } + + diff --git a/test/Sema/cxx-namespace.cpp b/test/Sema/cxx-namespace.cpp new file mode 100644 index 0000000000..c7303e3653 --- /dev/null +++ b/test/Sema/cxx-namespace.cpp @@ -0,0 +1,15 @@ +// RUN: clang -fsyntax-only -verify %s +namespace A { // expected-error {{error: previous definition is here}} + int A; + void f() { A = 0; } +} + +void f() { A = 0; } // expected-error {{error: unexpected namespace name 'A': expected expression}} +int A; // expected-error {{error: redefinition of 'A' as different kind of symbol}} +class A; // expected-error {{error: redefinition of 'A' as different kind of symbol}} + +class B; // expected-error {{error: previous definition is here}} +namespace B {} // expected-error {{error: redefinition of 'B' as different kind of symbol}} + +void C(); // expected-error {{error: previous definition is here}} +namespace C {} // expected-error {{error: redefinition of 'C' as different kind of symbol}} -- 2.40.0