]> granicus.if.org Git - clang/commitdiff
While determining when to parse inline member functions of a class,
authorDouglas Gregor <dgregor@apple.com>
Sat, 16 Jan 2010 20:52:59 +0000 (20:52 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 16 Jan 2010 20:52:59 +0000 (20:52 +0000)
distinguish between nested classes (whose member functions cannot be
parsed until the innermost non-nested class is complete) and local
classes (that are defined within a function but are not necessarily
nested). The upshot of this change, which fixes PR5764, is that the
bodies of member functions of local (non-nested) classes need to be
parsed when the local class is complete (and no later), since they may
refer to function-local static variables, typedefs, enums, etc.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93653 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseDeclCXX.cpp
test/SemaTemplate/instantiate-local-class.cpp

index 90040c54bfb1ac37e9af62d332e6261b07b2c43e..a5ef817d43d02b161df8126af02cb8e990f3c3aa 100644 (file)
@@ -1398,15 +1398,35 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
                                         PP.getSourceManager(),
                                         "parsing struct/union/class body");
 
-  // Determine whether this is a top-level (non-nested) class.
-  bool TopLevelClass = ClassStack.empty() ||
-    CurScope->isInCXXInlineMethodScope();
+  // Determine whether this is a non-nested class. Note that local
+  // classes are *not* considered to be nested classes.
+  bool NonNestedClass = true;
+  if (!ClassStack.empty()) {
+    for (const Scope *S = CurScope; S; S = S->getParent()) {
+      if (S->isClassScope()) {
+        // We're inside a class scope, so this is a nested class.
+        NonNestedClass = false;
+        break;
+      }
+
+      if ((S->getFlags() & Scope::FnScope)) {
+        // If we're in a function or function template declared in the
+        // body of a class, then this is a local class rather than a
+        // nested class.
+        const Scope *Parent = S->getParent();
+        if (Parent->isTemplateParamScope())
+          Parent = Parent->getParent();
+        if (Parent->isClassScope())
+          break;
+      }
+    }
+  }
 
   // Enter a scope for the class.
   ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
 
   // Note that we are parsing a new (potentially-nested) class definition.
-  ParsingClassDefinition ParsingDef(*this, TagDecl, TopLevelClass);
+  ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass);
 
   if (TagDecl)
     Actions.ActOnTagStartDefinition(CurScope, TagDecl);
@@ -1484,7 +1504,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
   //
   // FIXME: Only function bodies and constructor ctor-initializers are
   // parsed correctly, fix the rest.
-  if (TopLevelClass) {
+  if (NonNestedClass) {
     // We are not inside a nested class. This class and its nested classes
     // are complete and we can parse the delayed portions of method
     // declarations and the lexed inline method definitions.
@@ -1666,10 +1686,10 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
 /// \brief We have just started parsing the definition of a new class,
 /// so push that class onto our stack of classes that is currently
 /// being parsed.
-void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool TopLevelClass) {
-  assert((TopLevelClass || !ClassStack.empty()) &&
+void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool NonNestedClass) {
+  assert((NonNestedClass || !ClassStack.empty()) &&
          "Nested class without outer class");
-  ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass));
+  ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass));
 }
 
 /// \brief Deallocate the given parsed class and all of its nested
index 5cb63b49ee9aeca7f27314147980f1fc9625d821..eaaae9b6ee3163676ad0cea656231e790feee22a 100644 (file)
@@ -10,3 +10,22 @@ void f0() {
 }
 
 template void f0<int>();
+
+// PR5764
+namespace PR5764 {
+  class X {
+    template <typename T>
+    void Bar() {
+      class Y {
+        Y() {}
+      };
+
+      Y y;
+    }
+  };
+
+  void test(X x) {
+    x.Bar<int>();
+  }
+}
+