sepavloff updated this revision to Diff 31831.
sepavloff added a comment.

Fixed module boundary treatment.

This version must fix problems in the treatment of  annot_modulbegin and
annot_module_end. Error recover for the token annot_module_include found
in wrong context can be made as previously, just by ignoring it. To handle
token 'annot_module_end' parser bails out to upper level, where the module
end can be processed, it will complain on missing '}' etc. As for
'annot_module_start', now parser tries to recover by skipping all content
till matching 'annot_module_end'.

Also made changes according to reviewer's notes.


http://reviews.llvm.org/D11844

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseStmt.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDecl.cpp
  test/Modules/auto-module-import.m
  test/Modules/malformed.cpp
  test/Modules/misplaced.cpp

Index: test/Modules/misplaced.cpp
===================================================================
--- /dev/null
+++ test/Modules/misplaced.cpp
@@ -0,0 +1,14 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify
+
+namespace N1 {  // expected-note{{namespace 'N1' begins here}}
+#include "dummy.h"  // expected-error{{import of module 'dummy' appears within namespace 'N1'}}
+}
+
+void func1() {  // expected-note{{function 'func1' begins here}}
+#include "dummy.h"  // expected-error{{import of module 'dummy' appears within function 'func1'}}
+}
+
+struct S1 {  // expected-note{{'S1' begins here}}
+#include "dummy.h"  // expected-error{{import of module 'dummy' appears within 'S1'}}
+};
Index: test/Modules/malformed.cpp
===================================================================
--- test/Modules/malformed.cpp
+++ test/Modules/malformed.cpp
@@ -12,20 +12,14 @@
 #include STR(HEADER)
 
 // CHECK-A: While building module 'malformed_a'
+// CHECK-A: {{^}}Inputs/malformed/a1.h:1:{{.*}} error: unexpected module end
 // CHECK-A: {{^}}Inputs/malformed/a1.h:1:{{.*}} error: expected '}'
 // CHECK-A: {{^}}Inputs/malformed/a1.h:1:{{.*}} note: to match this '{'
 //
 // CHECK-A: While building module 'malformed_a'
-// CHECK-A: {{^}}Inputs/malformed/a2.h:1:{{.*}} error: extraneous closing brace
 
 // CHECK-B: While building module 'malformed_b'
-// CHECK-B: {{^}}Inputs/malformed/b1.h:2:{{.*}} error: expected '}'
-// CHECK-B: {{^}}Inputs/malformed/b1.h:1:{{.*}} note: to match this '{'
-// CHECK-B: {{^}}Inputs/malformed/b1.h:3:{{.*}} error: extraneous closing brace ('}')
-//
-// CHECK-B: While building module 'malformed_b'
-// CHECK-B: {{^}}Inputs/malformed/b2.h:1:{{.*}} error: redefinition of 'g'
-// CHECK-B: {{^}}Inputs/malformed/b2.h:1:{{.*}} note: previous definition is here
+// CHECK-B: {{^}}Inputs/malformed/b1.h:2:{{.*}} error: submodule cannot be started here
 
 void test() { f<int>(); }
 // Test that we use relative paths to name files within an imported module.
Index: test/Modules/auto-module-import.m
===================================================================
--- test/Modules/auto-module-import.m
+++ test/Modules/auto-module-import.m
@@ -83,6 +83,6 @@
   return not_in_module;
 }
 
-void includeNotAtTopLevel() { // expected-note {{to match this '{'}}
-  #include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} expected-error {{expected '}'}}
-} // expected-error {{extraneous closing brace}}
+void includeNotAtTopLevel() { // expected-note {{function 'includeNotAtTopLevel' begins here}}
+  #include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} expected-error {{import of module 'NoUmbrella.A' appears within function 'includeNotAtTopLevel'}}
+}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -14274,6 +14274,10 @@
   }
 }
 
+void Sema::diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc) {
+  return checkModuleImportContext(*this, M, ImportLoc, CurContext);
+}
+
 DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, 
                                    SourceLocation ImportLoc, 
                                    ModuleIdPath Path) {
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -1989,6 +1989,43 @@
   return Actions.ConvertDeclToDeclGroup(Import.get());
 }
 
+/// \brief Try recover parser when module annotation appears where it must not
+/// be found.
+/// \returns true if the recover was successful and parsing may be continued, or
+/// false if parser must bail out to top level and handle the token there.
+bool Parser::tryParseMisplacedModuleImport() {
+  switch (Tok.getKind()) {
+  case tok::annot_module_end:
+    Diag(Tok, diag::err_unexpected_module_end);
+    break;
+  case tok::annot_module_begin: {
+    Diag(Tok, diag::err_unexpected_module_start);
+    // Recover by skipping content of the included submodule.
+    unsigned ModuleNesting = 1;
+    do {
+      ConsumeAnyToken();
+      if (SkipUntil(tok::annot_module_end)) {
+        --ModuleNesting;
+      } else {
+        if (Tok.is(tok::annot_module_begin))
+          ++ModuleNesting;
+      }
+    } while (ModuleNesting && Tok.isNot(tok::eof));
+    return true;
+  }
+  case tok::annot_module_include:
+    // Module import found where it should not be, for instance, inside a
+    // namespace. Recover by ignoring the import.
+    Actions.diagnoseMisplacedModuleImport(reinterpret_cast<Module *>(
+      Tok.getAnnotationValue()), Tok.getLocation());
+    ConsumeToken();
+    return true;
+  default:
+    llvm_unreachable("Module annotation token expected");
+  }
+  return false;
+}
+
 bool BalancedDelimiterTracker::diagnoseOverflow() {
   P.Diag(P.Tok, diag::err_bracket_depth_exceeded)
     << P.getLangOpts().BracketDepth;
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -944,7 +944,13 @@
       Stmts.push_back(R.get());
   }
 
-  while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
+  while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+    if (Tok.isOneOf(tok::annot_module_include, tok::annot_module_begin,
+                    tok::annot_module_end)) {
+      if (tryParseMisplacedModuleImport())
+        continue;
+      break;
+    }
     if (Tok.is(tok::annot_pragma_unused)) {
       HandlePragmaUnused();
       continue;
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -210,7 +210,13 @@
                                  ParsedAttributes &attrs,
                                  BalancedDelimiterTracker &Tracker) {
   if (index == Ident.size()) {
-    while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
+    while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+      if (Tok.isOneOf(tok::annot_module_include, tok::annot_module_begin,
+                      tok::annot_module_end)) {
+        if (tryParseMisplacedModuleImport())
+          continue;
+        break;
+      }
       ParsedAttributesWithRange attrs(AttrFactory);
       MaybeParseCXX11Attributes(attrs);
       MaybeParseMicrosoftAttributes(attrs);
@@ -3063,11 +3069,17 @@
 
   if (TagDecl) {
     // While we still have something to read, read the member-declarations.
-    while (Tok.isNot(tok::r_brace) && !isEofOrEom())
+    while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+      if (Tok.isOneOf(tok::annot_module_include, tok::annot_module_begin,
+                      tok::annot_module_end)) {
+        if (tryParseMisplacedModuleImport())
+          continue;
+        break;
+      }
       // Each iteration of this loop reads one member-declaration.
       ParseCXXClassMemberDeclarationWithPragmas(
           CurAS, AccessAttrs, static_cast<DeclSpec::TST>(TagType), TagDecl);
-
+    }
     T.consumeClose();
   } else {
     SkipUntil(tok::r_brace);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1778,6 +1778,10 @@
   /// \brief The parser has left a submodule.
   void ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod);
 
+  /// \brief Check if module import may be found in the current context,
+  /// emit error if not.
+  void diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc);
+
   /// \brief Create an implicit import of the given module at the given
   /// source location, for error recovery, if possible.
   ///
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2554,6 +2554,7 @@
   //===--------------------------------------------------------------------===//
   // Modules
   DeclGroupPtrTy ParseModuleImport(SourceLocation AtLoc);
+  bool tryParseMisplacedModuleImport();
 
   //===--------------------------------------------------------------------===//
   // C++11/G++: Type Traits [Type-Traits.html in the GCC manual]
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -1015,6 +1015,8 @@
   "expected a module name after module import">;
 def err_module_expected_semi : Error<
   "expected ';' after module name">;
+def err_unexpected_module_end : Error<"unexpected module end">;
+def err_unexpected_module_start : Error<"submodule cannot be started here">;
 }
 
 let CategoryName = "Generics Issue" in {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to