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
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 33d3ce4..37b9805 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -552,6 +552,12 @@
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 373aace..61cfa79 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -43,7 +43,7 @@
}
void Sema::PushDeclContext(DeclContext *DC) {
- assert( ( (DC->isFunctionOrMethod() && isa<TranslationUnitDecl>(CurContext))
+ assert( ( (isa<ObjCMethodDecl>(DC) && isa<TranslationUnitDecl>(CurContext))
|| DC->getParent() == CurContext ) &&
"The next DeclContext should be directly contained in the current one.");
CurContext = DC;
@@ -52,7 +52,7 @@
void Sema::PopDeclContext() {
assert(CurContext && "DeclContext imbalance!");
// If CurContext is a ObjC method, getParent() will return NULL.
- CurContext = CurContext->isFunctionOrMethod()
+ CurContext = isa<ObjCMethodDecl>(CurContext)
? Context.getTranslationUnitDecl()
: CurContext->getParent();
}
@@ -1332,42 +1332,53 @@
// 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<TagDecl>(LookupDecl(Name, Decl::IDNS_Tag, S))) {
+ // Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
+ if (ScopedDecl *PrevDecl =
+ dyn_cast_or_null<ScopedDecl>(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;
+ assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) &&
+ "unexpected Decl type");
+ if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(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 (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;
+ // 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 251fb5e..827c737 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 @@
// 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<NamespaceDecl>(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<Decl *>(D);
+ NamespaceDecl *Namespc = dyn_cast_or_null<NamespaceDecl>(Dcl);
+ assert(Namespc && "Invalid parameter, expected NamespaceDecl");
+ Namespc->setRBracLoc(RBrace);
+ PopDeclContext();
+}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e3298f3..edd9284 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -128,6 +128,8 @@
return Diag(Loc, diag::err_unexpected_typedef, II.getName());
if (isa<ObjCInterfaceDecl>(D))
return Diag(Loc, diag::err_unexpected_interface, II.getName());
+ if (isa<NamespaceDecl>(D))
+ return Diag(Loc, diag::err_unexpected_namespace, II.getName());
assert(0 && "Invalid decl");
abort();
@@ -2313,3 +2315,5 @@
return isInvalid;
}
+
+