[cfe-commits] r58916 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp test/SemaCXX/nested-name-spec.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Sat Nov 8 09:17:31 PST 2008


Author: akirtzidis
Date: Sat Nov  8 11:17:31 2008
New Revision: 58916

URL: http://llvm.org/viewvc/llvm-project?rev=58916&view=rev
Log:
Implement Sema support for C++ nested-name-specifiers.

Added:
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/test/SemaCXX/nested-name-spec.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=58916&r1=58915&r2=58916&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Sat Nov  8 11:17:31 2008
@@ -310,10 +310,21 @@
     }
   }
 
+  bool isFileContext() const {
+    return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace;
+  }
+
   bool isCXXRecord() const {
     return DeclKind == Decl::CXXRecord;
   }
 
+  bool Encloses(DeclContext *DC) const {
+    for (; DC; DC = DC->getParent())
+      if (DC == this)
+        return true;
+    return false;
+  }
+
   const ScopedDecl *getDeclChain() const { return DeclChain; }
   ScopedDecl *getDeclChain() { return DeclChain; }
   void setDeclChain(ScopedDecl *D) { DeclChain = D; }

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=58916&r1=58915&r2=58916&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Sat Nov  8 11:17:31 2008
@@ -391,12 +391,14 @@
 /// CXXMethodDecl - Represents a static or instance method of a
 /// struct/union/class.
 class CXXMethodDecl : public FunctionDecl {
+  bool IsInlineDef : 1;
+
 protected:
   CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L,
                 IdentifierInfo *Id, QualType T,
                 bool isStatic, bool isInline, ScopedDecl *PrevDecl)
     : FunctionDecl(DK, RD, L, Id, T, (isStatic ? Static : None),
-                   isInline, PrevDecl) {}
+                   isInline, PrevDecl), IsInlineDef(false) {}
 
 public:
   static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
@@ -407,6 +409,10 @@
   bool isStatic() const { return getStorageClass() == Static; }
   bool isInstance() const { return !isStatic(); }
 
+  bool isOutOfLineDefinition() const { return !isInlineDefinition(); }
+  bool isInlineDefinition() const { return IsInlineDef; }
+  void setInlineDefinition(bool flag) { IsInlineDef = flag; }
+
   void setAccess(AccessSpecifier AS) { Access = AS; }
   AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58916&r1=58915&r2=58916&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Sat Nov  8 11:17:31 2008
@@ -1165,6 +1165,14 @@
      "types may not be defined in conditions")
 DIAG(err_typecheck_bool_condition, ERROR,
     "expression must have bool type (or be convertible to bool) ('%0' invalid)")
+DIAG(err_expected_class_or_namespace, ERROR,
+     "expected a class or namespace")
+DIAG(err_invalid_declarator_scope, ERROR,
+     "definition or redeclaration for '%0' not in a namespace enclosing '%1'")
+DIAG(err_invalid_declarator_in_function, ERROR,
+     "definition or redeclaration for '%0' not allowed inside a function")
+DIAG(err_not_tag_in_scope, ERROR,
+     "'%0' does not name a tag member in the specified scope")
 
 
 // assignment related diagnostics (also for argument passing, returning, etc).

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=58916&r1=58915&r2=58916&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Sat Nov  8 11:17:31 2008
@@ -35,7 +35,7 @@
 
 void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
   TUScope = S;
-  CurContext = Context.getTranslationUnitDecl();
+  PushDeclContext(Context.getTranslationUnitDecl());
   if (!PP.getLangOptions().ObjC1) return;
   
   // Synthesize "typedef struct objc_selector *SEL;"
@@ -81,8 +81,8 @@
 }
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
-  : PP(pp), Context(ctxt), Consumer(consumer), CurContext(0), CurBlock(0),
-    PackContext(0), IdResolver(pp.getLangOptions()) {
+  : PP(pp), Context(ctxt), Consumer(consumer), CurContext(0),PreDeclaratorDC(0),
+    CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()) {
   
   // Get IdentifierInfo objects for known functions for which we
   // do extra checking.  

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58916&r1=58915&r2=58916&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sat Nov  8 11:17:31 2008
@@ -109,6 +109,14 @@
   /// CurContext - This is the current declaration context of parsing.
   DeclContext *CurContext;
 
+  /// LexicalFileContext - The current lexical file declaration context,
+  /// the translation unit or a namespace.
+  DeclContext *LexicalFileContext;
+
+  /// PreDeclaratorDC - Keeps the declaration context before switching to the
+  /// context of a declarator's nested-name-specifier.
+  DeclContext *PreDeclaratorDC;
+
   /// CurBlock - If inside of a block definition, this contains a pointer to
   /// the active block object that represents it.
   BlockSemaInfo *CurBlock;
@@ -332,7 +340,7 @@
   virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
                              DeclTy **Elements, unsigned NumElements);
 
-  DeclContext *getDCParent(DeclContext *DC);
+  DeclContext *getContainingDC(DeclContext *DC);
 
   /// Set the current declaration context until it gets popped.
   void PushDeclContext(DeclContext *DC);
@@ -441,6 +449,7 @@
 
   /// More parsing and symbol table subroutines...
   Decl *LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S,
+                   DeclContext *LookupCtx = 0,
                    bool enableLazyBuiltinCreation = true);
   ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
   ScopedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, 
@@ -773,6 +782,38 @@
                                                       SourceLocation EqualLoc,
                                                       ExprTy *AssignExprVal);
 
+  /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
+  /// global scope ('::').
+  virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
+                                                   SourceLocation CCLoc);
+
+  /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+  /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
+  /// we want to resolve "bar::". 'SS' is empty or the previously parsed
+  /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
+  /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
+  /// Returns a CXXScopeTy* object representing the C++ scope.
+  virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+                                                  const CXXScopeSpec &SS,
+                                                  SourceLocation IdLoc,
+                                                  SourceLocation CCLoc,
+                                                  const IdentifierInfo &II);
+
+  /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
+  /// scope or nested-name-specifier) is parsed, part of a declarator-id.
+  /// After this method is called, according to [C++ 3.4.3p3], names should be
+  /// looked up in the declarator-id's scope, until the declarator is parsed and
+  /// ActOnCXXExitDeclaratorScope is called.
+  /// The 'SS' should be a non-empty valid CXXScopeSpec.
+  virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
+
+  /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
+  /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
+  /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well.
+  /// Used to indicate that names should revert to being looked up in the
+  /// defining scope.
+  virtual void ActOnCXXExitDeclaratorScope(const CXXScopeSpec &SS);
+
   // ParseObjCStringLiteral - Parse Objective-C string literals.
   virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, 
                                             ExprTy **Strings,

Added: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=58916&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (added)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Sat Nov  8 11:17:31 2008
@@ -0,0 +1,131 @@
+//===--- SemaCXXScopeSpec.cpp - Semantic Analysis for C++ scope specifiers-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements C++ semantic analysis for scope specifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/Diagnostic.h"
+using namespace clang;
+
+
+namespace {
+  Decl *LookupNestedName(DeclContext *LookupCtx, bool LookInParentCtx,
+                         const IdentifierInfo &II, bool &IdIsUndeclared) {
+    IdentifierResolver::iterator
+      I = IdentifierResolver::begin(&II, LookupCtx, LookInParentCtx),
+      E = IdentifierResolver::end();
+
+    if (I == E) {
+      IdIsUndeclared = true;
+      return 0;
+    }
+    IdIsUndeclared = false;
+
+    // C++ 3.4.3p1 :
+    // During the lookup for a name preceding the :: scope resolution operator,
+    // object, function, and enumerator names are ignored. If the name found is
+    // not a class-name or namespace-name, the program is ill-formed.
+
+    for (; I != E; ++I) {
+      if (TypedefDecl *TD = dyn_cast<TypedefDecl>(*I)) {
+        if (TD->getUnderlyingType()->isRecordType())
+          break;
+        continue;
+      }
+      if (((*I)->getIdentifierNamespace()&Decl::IDNS_Tag) && !isa<EnumDecl>(*I))
+        break;    
+    }
+
+    return (I != E ? *I : 0);
+  }
+} // anonymous namespace
+
+/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
+/// global scope ('::').
+Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
+                                                     SourceLocation CCLoc) {
+  return cast<DeclContext>(Context.getTranslationUnitDecl());
+}
+
+/// ActOnCXXNestedNameSpecifier - Called during parsing of a
+/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
+/// we want to resolve "bar::". 'SS' is empty or the previously parsed
+/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
+/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
+/// Returns a CXXScopeTy* object representing the C++ scope.
+Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+                                                    const CXXScopeSpec &SS,
+                                                    SourceLocation IdLoc,
+                                                    SourceLocation CCLoc,
+                                                    const IdentifierInfo &II) {
+  DeclContext *DC = static_cast<DeclContext*>(SS.getScopeRep());
+  Decl *SD;
+  bool IdIsUndeclared;
+
+  if (DC)
+    SD = LookupNestedName(DC, false/*LookInParentCtx*/, II, IdIsUndeclared);
+  else
+    SD = LookupNestedName(CurContext, true/*LookInParent*/, II, IdIsUndeclared);
+
+  if (SD) {
+    if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+      assert(TD->getUnderlyingType()->isRecordType() &&"Invalid Scope Decl!");
+      SD = TD->getUnderlyingType()->getAsRecordType()->getDecl();
+    }
+
+    assert((isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) &&
+           "Invalid Scope Decl!");
+    return cast<DeclContext>(SD);
+  }
+
+  unsigned DiagID;
+  if (!IdIsUndeclared)
+    DiagID = diag::err_expected_class_or_namespace;
+  else if (DC)
+    DiagID = diag::err_typecheck_no_member;
+  else
+    DiagID = diag::err_undeclared_var_use;
+
+  if (DC)
+    Diag(IdLoc, DiagID, II.getName(), SS.getRange());
+  else
+    Diag(IdLoc, DiagID, II.getName());
+
+  return 0;
+}
+
+/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
+/// scope or nested-name-specifier) is parsed, part of a declarator-id.
+/// After this method is called, according to [C++ 3.4.3p3], names should be
+/// looked up in the declarator-id's scope, until the declarator is parsed and
+/// ActOnCXXExitDeclaratorScope is called.
+/// The 'SS' should be a non-empty valid CXXScopeSpec.
+void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+  assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
+  assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
+  PreDeclaratorDC = CurContext;
+  CurContext = static_cast<DeclContext*>(SS.getScopeRep());
+}
+
+/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
+/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
+/// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well.
+/// Used to indicate that names should revert to being looked up in the
+/// defining scope.
+void Sema::ActOnCXXExitDeclaratorScope(const CXXScopeSpec &SS) {
+  assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
+  assert(CurContext == static_cast<DeclContext*>(SS.getScopeRep()) &&
+         "Context imbalance!");
+  CurContext = PreDeclaratorDC;
+  PreDeclaratorDC = 0;
+}

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=58916&r1=58915&r2=58916&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Nov  8 11:17:31 2008
@@ -30,7 +30,13 @@
 
 Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S,
                                const CXXScopeSpec *SS) {
-  Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, false);
+  DeclContext *DC = 0;
+  if (SS) {
+    if (SS->isInvalid())
+      return 0;
+    DC = static_cast<DeclContext*>(SS->getScopeRep());
+  }
+  Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC, false);
 
   if (IIDecl && (isa<TypedefDecl>(IIDecl) || 
                  isa<ObjCInterfaceDecl>(IIDecl) ||
@@ -44,16 +50,16 @@
   return Ty.getAsString();
 }
 
-DeclContext *Sema::getDCParent(DeclContext *DC) {
-  // If CurContext is a ObjC method, getParent() will return NULL.
-  if (isa<ObjCMethodDecl>(DC))
-    return Context.getTranslationUnitDecl();
-
-  // A C++ inline method is parsed *after* the topmost class it was declared in
-  // is fully parsed (it's "complete").
-  // The parsing of a C++ inline method happens at the declaration context of
-  // the topmost (non-nested) class it is declared in.
+DeclContext *Sema::getContainingDC(DeclContext *DC) {
   if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
+    // A C++ out-of-line method will return to the file declaration context.
+    if (!MD->isInlineDefinition())
+      return LexicalFileContext;
+
+    // A C++ inline method is parsed *after* the topmost class it was declared in
+    // is fully parsed (it's "complete").
+    // The parsing of a C++ inline method happens at the declaration context of
+    // the topmost (non-nested) class it is declared in.
     assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record.");
     DC = MD->getParent();
     while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getParent()))
@@ -64,18 +70,25 @@
     return DC;
   }
 
+  if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))
+    return LexicalFileContext;
+
   return DC->getParent();
 }
 
 void Sema::PushDeclContext(DeclContext *DC) {
-  assert(getDCParent(DC) == CurContext &&
+  assert(getContainingDC(DC) == CurContext &&
        "The next DeclContext should be directly contained in the current one.");
   CurContext = DC;
+  if (CurContext->isFileContext())
+    LexicalFileContext = CurContext;
 }
 
 void Sema::PopDeclContext() {
   assert(CurContext && "DeclContext imbalance!");
-  CurContext = getDCParent(CurContext);
+  CurContext = getContainingDC(CurContext);
+  if (CurContext->isFileContext())
+    LexicalFileContext = CurContext;
 }
 
 /// Add this decl to the scope shadowed decl chains.
@@ -180,18 +193,20 @@
 
 /// LookupDecl - Look up the inner-most declaration in the specified
 /// namespace.
-Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI,
-                       Scope *S, bool enableLazyBuiltinCreation) {
+Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S,
+                       DeclContext *LookupCtx, bool enableLazyBuiltinCreation) {
   if (II == 0) return 0;
   unsigned NS = NSI;
   if (getLangOptions().CPlusPlus && (NS & Decl::IDNS_Ordinary))
     NS |= Decl::IDNS_Tag;
 
+  IdentifierResolver::iterator 
+    I = LookupCtx ? IdResolver.begin(II, LookupCtx, false/*LookInParentCtx*/) :
+                    IdResolver.begin(II, CurContext, true/*LookInParentCtx*/);
   // Scan up the scope chain looking for a decl that matches this identifier
   // that is in the appropriate namespace.  This search should not take long, as
   // shadowing of names is uncommon, and deep shadowing is extremely uncommon.
-  for (IdentifierResolver::iterator
-       I = IdResolver.begin(II, CurContext), E = IdResolver.end(); I != E; ++I)
+  for (; I != IdResolver.end(); ++I)
     if ((*I)->getIdentifierNamespace() & NS)
       return *I;
 
@@ -199,7 +214,8 @@
   // corresponds to a compiler builtin, create the decl object for the builtin
   // now, injecting it into translation unit scope, and return it.
   if (NS & Decl::IDNS_Ordinary) {
-    if (enableLazyBuiltinCreation) {
+    if (enableLazyBuiltinCreation &&
+        (LookupCtx == 0 || isa<TranslationUnitDecl>(LookupCtx))) {
       // If this is a builtin on this (or all) targets, create the decl.
       if (unsigned BuiltinID = II->getBuiltinID())
         return LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, S);
@@ -749,11 +765,45 @@
   while ((S->getFlags() & Scope::DeclScope) == 0)
     S = S->getParent();
   
-  // See if this is a redefinition of a variable in the same scope.
-  Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S);
+  DeclContext *DC;
+  Decl *PrevDecl;
   ScopedDecl *New;
   bool InvalidDecl = false;
  
+  // See if this is a redefinition of a variable in the same scope.
+  if (!D.getCXXScopeSpec().isSet()) {
+    DC = CurContext;
+    PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S);
+  } else { // Something like "int foo::x;"
+    DC = static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep());
+    PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S, DC);
+
+    // C++ 7.3.1.2p2:
+    // Members (including explicit specializations of templates) of a named
+    // namespace can also be defined outside that namespace by explicit
+    // qualification of the name being defined, provided that the entity being
+    // defined was already declared in the namespace and the definition appears
+    // after the point of declaration in a namespace that encloses the
+    // declarations namespace.
+    //
+    if (PrevDecl == 0) {
+      // No previous declaration in the qualifying scope.
+      Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member,
+           II->getName(), D.getCXXScopeSpec().getRange());
+    } else if (!CurContext->Encloses(DC)) {
+      // The qualifying scope doesn't enclose the original declaration.
+      // Emit diagnostic based on current scope.
+      SourceLocation L = D.getIdentifierLoc();
+      SourceRange R = D.getCXXScopeSpec().getRange();
+      if (isa<FunctionDecl>(CurContext)) {
+        Diag(L, diag::err_invalid_declarator_in_function, II->getName(), R);
+      } else {
+      Diag(L, diag::err_invalid_declarator_scope, II->getName(),
+           cast<NamedDecl>(DC)->getName(), R);
+      }
+    }
+  }
+
   // 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. 
@@ -775,7 +825,7 @@
     ProcessDeclAttributes(NewTD, D);
     // Merge the decl with the existing one if appropriate. If the decl is
     // in an outer scope, it isn't the same thing.
-    if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)) {
+    if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
       NewTD = MergeTypeDefDecl(NewTD, PrevDecl);
       if (NewTD == 0) return 0;
     }
@@ -812,14 +862,14 @@
     FunctionDecl *NewFD;
     if (D.getKind() == Declarator::DK_Constructor) {
       // This is a C++ constructor declaration.
-      assert(CurContext->isCXXRecord() &&
+      assert(DC->isCXXRecord() &&
              "Constructors can only be declared in a member context");
 
       bool isInvalidDecl = CheckConstructorDeclarator(D, R, SC);
 
       // Create the new declaration
       NewFD = CXXConstructorDecl::Create(Context, 
-                                         cast<CXXRecordDecl>(CurContext),
+                                         cast<CXXRecordDecl>(DC),
                                          D.getIdentifierLoc(), II, R,
                                          isExplicit, isInline,
                                          /*isImplicitlyDeclared=*/false);
@@ -828,11 +878,11 @@
         NewFD->setInvalidDecl();
     } else if (D.getKind() == Declarator::DK_Destructor) {
       // This is a C++ destructor declaration.
-      if (CurContext->isCXXRecord()) {
+      if (DC->isCXXRecord()) {
         bool isInvalidDecl = CheckDestructorDeclarator(D, R, SC);
 
         NewFD = CXXDestructorDecl::Create(Context,
-                                          cast<CXXRecordDecl>(CurContext),
+                                          cast<CXXRecordDecl>(DC),
                                           D.getIdentifierLoc(), II, R, 
                                           isInline,
                                           /*isImplicitlyDeclared=*/false);
@@ -843,14 +893,14 @@
         Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
         // Create a FunctionDecl to satisfy the function definition parsing
         // code path.
-        NewFD = FunctionDecl::Create(Context, CurContext, D.getIdentifierLoc(),
+        NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
                                      II, R, SC, isInline, LastDeclarator,
                                      // FIXME: Move to DeclGroup...
                                    D.getDeclSpec().getSourceRange().getBegin());
         NewFD->setInvalidDecl();
       }
     } else if (D.getKind() == Declarator::DK_Conversion) {
-      if (!CurContext->isCXXRecord()) {
+      if (!DC->isCXXRecord()) {
         Diag(D.getIdentifierLoc(),
              diag::err_conv_function_not_member);
         return 0;
@@ -858,21 +908,21 @@
         bool isInvalidDecl = CheckConversionDeclarator(D, R, SC);
 
         NewFD = CXXConversionDecl::Create(Context, 
-                                          cast<CXXRecordDecl>(CurContext),
+                                          cast<CXXRecordDecl>(DC),
                                           D.getIdentifierLoc(), II, R,
                                           isInline, isExplicit);
         
         if (isInvalidDecl)
           NewFD->setInvalidDecl();
       }
-    } else if (CurContext->isCXXRecord()) {
+    } else if (DC->isCXXRecord()) {
       // This is a C++ method declaration.
-      NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
+      NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
                                     D.getIdentifierLoc(), II, R,
                                     (SC == FunctionDecl::Static), isInline,
                                     LastDeclarator);
     } else {
-      NewFD = FunctionDecl::Create(Context, CurContext,
+      NewFD = FunctionDecl::Create(Context, DC,
                                    D.getIdentifierLoc(),
                                    II, R, SC, isInline, LastDeclarator,
                                    // FIXME: Move to DeclGroup...
@@ -943,7 +993,7 @@
         llvm::SmallVector<ParmVarDecl*, 16> Params;
         for (FunctionTypeProto::arg_type_iterator ArgType = FT->arg_type_begin();
              ArgType != FT->arg_type_end(); ++ArgType) {
-          Params.push_back(ParmVarDecl::Create(Context, CurContext,
+          Params.push_back(ParmVarDecl::Create(Context, DC,
                                                SourceLocation(), 0,
                                                *ArgType, VarDecl::None,
                                                0, 0));
@@ -972,7 +1022,7 @@
     // Merge the decl with the existing one if appropriate. Since C functions
     // are in a flat namespace, make sure we consider decls in outer scopes.
     if (PrevDecl &&
-        (!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, CurContext, S))) {
+        (!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
       bool Redeclaration = false;
 
       // If C++, determine whether NewFD is an overload of PrevDecl or
@@ -1046,10 +1096,10 @@
     case DeclSpec::SCS_register:       SC = VarDecl::Register; break;
     case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
     }    
-    if (CurContext->isCXXRecord()) {
+    if (DC->isCXXRecord()) {
       assert(SC == VarDecl::Static && "Invalid storage class for member!");
       // This is a static data member for a C++ class.
-      NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
+      NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(DC),
                                       D.getIdentifierLoc(), II,
                                       R, LastDeclarator);
     } else {
@@ -1063,7 +1113,7 @@
           InvalidDecl = true;
         }
       }
-        NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(), 
+        NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), 
                                 II, R, SC, LastDeclarator,
                                 // FIXME: Move to DeclGroup...
                                 D.getDeclSpec().getSourceRange().getBegin());
@@ -1090,7 +1140,7 @@
     }
     // Merge the decl with the existing one if appropriate. If the decl is
     // in an outer scope, it isn't the same thing.
-    if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)) {
+    if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
       NewVD = MergeVarDecl(NewVD, PrevDecl);
       if (NewVD == 0) return 0;
     }
@@ -1824,6 +1874,7 @@
 /// to introduce parameters into function prototype scope.
 Sema::DeclTy *
 Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
+  // FIXME: disallow CXXScopeSpec for param declarators.
   const DeclSpec &DS = D.getDeclSpec();
   
   // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
@@ -1953,6 +2004,10 @@
     Diag(Definition->getLocation(), diag::err_previous_definition);
   }
 
+  if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+    if (isa<CXXRecordDecl>(CurContext))
+      MD->setInlineDefinition(true);
+
   PushDeclContext(FD);
     
   // Check the validity of our function parameters
@@ -2083,6 +2138,53 @@
   case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
   case DeclSpec::TST_enum:   Kind = TagDecl::TK_enum; break;
   }
+
+  if (Name && SS.isNotEmpty()) {
+    DeclContext *DC = static_cast<DeclContext*>(SS.getScopeRep());
+    if (DC == 0) {
+      // Invalid C++ scope specifier.
+      Name = 0;
+      goto CreateNewDecl;
+    }
+
+    TagDecl *PrevDecl =
+          dyn_cast_or_null<TagDecl>(LookupDecl(Name, Decl::IDNS_Tag, S, DC));
+    if (PrevDecl == 0) {
+      // No tag member found.
+      Diag(NameLoc, diag::err_not_tag_in_scope, Name->getName(),
+           SS.getRange());
+      Name = 0;
+      goto CreateNewDecl;
+    }
+
+    if (PrevDecl->getTagKind() != Kind) {
+      Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
+      Diag(PrevDecl->getLocation(), diag::err_previous_use);
+      // Recover by making this an anonymous redefinition.
+      Name = 0;
+      goto CreateNewDecl;
+    }
+
+    // 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;
+      goto CreateNewDecl;
+    }
+
+    // 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;
+  }
   
   // Two code paths: a new one for structs/unions/classes where we create
   //   separate decls for forward declarations, and an old (eventually to
@@ -2090,6 +2192,8 @@
   if (Kind != TagDecl::TK_enum)
     return ActOnTagStruct(S, Kind, TK, KWLoc, Name, NameLoc, Attr);
   
+  {
+
   // If this is a named struct, check to see if there was a previous forward
   // declaration or definition.
   // Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
@@ -2147,6 +2251,10 @@
       }
     }
   }
+
+  } // subscope in which an already declared tag is handled.
+
+  CreateNewDecl:
   
   // If there is an identifier, use the location of the identifier as the
   // location of the decl, otherwise use the location of the struct/union

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58916&r1=58915&r2=58916&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Nov  8 11:17:31 2008
@@ -264,7 +264,14 @@
 /// the innermost class.
 bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
                               const CXXScopeSpec *SS) {
-  if (CXXRecordDecl *CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext))
+  CXXRecordDecl *CurDecl;
+  if (SS) {
+    DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
+    CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
+  } else
+    CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
+
+  if (CurDecl)
     return &II == CurDecl->getIdentifier();
   else
     return false;
@@ -1253,7 +1260,7 @@
     // in that declarative region, it is treated as an original-namespace-name.
 
     Decl *PrevDecl =
-        LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope,
+        LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, 0,
                    /*enableLazyBuiltinCreation=*/false);
 
     if (PrevDecl && isDeclInScope(PrevDecl, CurContext, DeclRegionScope)) {

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=58916&r1=58915&r2=58916&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat Nov  8 11:17:31 2008
@@ -335,12 +335,21 @@
 /// ActOnIdentifierExpr - The parser read an identifier in expression context,
 /// validate it per-C99 6.5.1.  HasTrailingLParen indicates whether this
 /// identifier is used in a function call context.
+/// LookupCtx is only used for a C++ qualified-id (foo::bar) to indicate the
+/// class or namespace that the identifier must be a member of.
 Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                            IdentifierInfo &II,
                                            bool HasTrailingLParen,
                                            const CXXScopeSpec *SS) {
   // Could be enum-constant, value decl, instance variable, etc.
-  Decl *D = LookupDecl(&II, Decl::IDNS_Ordinary, S);
+  Decl *D;
+  if (SS && !SS->isEmpty()) {
+    DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
+    if (DC == 0)
+      return true;
+    D = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC);
+  } else
+    D = LookupDecl(&II, Decl::IDNS_Ordinary, S);
   
   // If this reference is in an Objective-C method, then ivar lookup happens as
   // well.
@@ -378,7 +387,11 @@
     else {
       // If this name wasn't predeclared and if this is not a function call,
       // diagnose the problem.
-      return Diag(Loc, diag::err_undeclared_var_use, II.getName());
+      if (SS && !SS->isEmpty())
+        return Diag(Loc, diag::err_typecheck_no_member,
+                    II.getName(), SS->getRange());
+      else
+        return Diag(Loc, diag::err_undeclared_var_use, II.getName());
     }
   }
   

Added: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=58916&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (added)
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Sat Nov  8 11:17:31 2008
@@ -0,0 +1,56 @@
+// RUN: clang -fsyntax-only -verify %s 
+namespace A {
+  struct C {
+    static int cx;
+  };
+  int ax;
+  void Af();
+}
+
+A:: ; // expected-error {{expected unqualified-id}}
+::A::ax::undef ex3; // expected-error {{expected a class or namespace}} expected-error {{expected '=', ',', ';', 'asm', or '__attribute__' after declarator}}
+A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-error {{expected '=', ',', ';', 'asm', or '__attribute__' after declarator}}
+
+class C2 {
+  void m();
+  int x;
+};
+
+void C2::m() {
+  x = 0;
+}
+
+namespace B {
+  void ::A::Af() {} // expected-error {{definition or redeclaration for 'Af' not in a namespace enclosing 'A'}}
+}
+
+void f1() {
+  void A::Af(); // expected-error {{definition or redeclaration for 'Af' not allowed inside a function}}  
+}
+
+void f2() {
+  A:: ; // expected-error {{expected unqualified-id}}
+  A::C::undef = 0; // expected-error {{no member named 'undef'}}
+  ::A::C::cx = 0;
+  int x = ::A::ax = A::C::cx;
+  x = sizeof(A::C);
+  x = sizeof(::A::C::cx);
+}
+
+A::C c1;
+struct A::C c2;
+struct S : public A::C {};
+struct A::undef; // expected-error {{'undef' does not name a tag member in the specified scope}}
+
+void f3() {
+  N::x = 0; // expected-error {{use of undeclared identifier 'N'}}
+  int N;
+  N::x = 0; // expected-error {{expected a class or namespace}}
+  { int A;           A::ax = 0; }
+  { enum A {};       A::ax = 0; }
+  { enum A { A };    A::ax = 0; }
+  { typedef int A;   A::ax = 0; }
+  { typedef int A(); A::ax = 0; }
+  { typedef A::C A;  A::ax = 0; } // expected-error {{no member named 'ax'}}
+  { typedef A::C A;  A::cx = 0; }
+}





More information about the cfe-commits mailing list