]> granicus.if.org Git - clang/commitdiff
Avoid a couple of assertions when preprocessing with modules
authorBen Langmuir <blangmuir@apple.com>
Wed, 10 Sep 2014 21:29:41 +0000 (21:29 +0000)
committerBen Langmuir <blangmuir@apple.com>
Wed, 10 Sep 2014 21:29:41 +0000 (21:29 +0000)
1. We were hitting the NextIsPrevious assertion because we were trying
to merge decl chains that were independent of each other because we had
no Sema object to allow them to find existing decls. This is fixed by
delaying loading the "preloaded" decls until Sema is available.

2. We were trying to get identifier info from an annotation token, which
asserts.  The fix is to special-case the module annotations in the
preprocessed output printer.

Fixed in a single commit because when you hit 1 you almost invariably
hit 2 as well.

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

include/clang/Serialization/ASTReader.h
lib/Frontend/PrintPreprocessedOutput.cpp
lib/Lex/TokenConcatenation.cpp
lib/Serialization/ASTReader.cpp
test/Modules/Inputs/diamond_left.h
test/Modules/Inputs/diamond_top.h
test/Modules/Inputs/preprocess-prefix.h [new file with mode: 0644]
test/Modules/preprocess.m [new file with mode: 0644]

index 12d27f105f274304403496e0d2bfaada82becdeb..1b3d46a6e474b62925cee1e35eefd5fba4abf261 100644 (file)
@@ -2076,9 +2076,9 @@ public:
   /// \brief Retrieve the AST context that this AST reader supplements.
   ASTContext &getContext() { return Context; }
 
-  // \brief Contains declarations that were loaded before we have
+  // \brief Contains the IDs for declarations that were requested before we have
   // access to a Sema object.
-  SmallVector<NamedDecl *, 16> PreloadedDecls;
+  SmallVector<uint64_t, 16> PreloadedDeclIDs;
 
   /// \brief Retrieve the semantic analysis object used to analyze the
   /// translation unit in which the precompiled header is being
index 17d7279e3ffce37c33b2f52c3af759ef1d26cdc0..7c1d9a568831c24589071edcac7c0aa0dc8b8ed3 100644 (file)
@@ -332,7 +332,10 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
     MoveToLine(HashLoc);
     OS << "@import " << Imported->getFullModuleName() << ";"
        << " /* clang -E: implicit import for \"" << File->getName() << "\" */";
+    // Since we want a newline after the @import, but not a #<line>, start a new
+    // line immediately.
     EmittedTokensOnThisLine = true;
+    startNewLineIfNeeded();
   }
 }
 
index 0a66bba91fcd8717b9dab598c45e2d87abdf5eae..866cbb142c86d9f03b4bb5f572a7d19d323694fe 100644 (file)
@@ -163,8 +163,8 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
     return false;
 
   tok::TokenKind PrevKind = PrevTok.getKind();
-  if (PrevTok.getIdentifierInfo())  // Language keyword or named operator.
-    PrevKind = tok::identifier;
+  if (!PrevTok.isAnnotation() && PrevTok.getIdentifierInfo())
+    PrevKind = tok::identifier; // Language keyword or named operator.
 
   // Look up information on when we should avoid concatenation with prevtok.
   unsigned ConcatInfo = TokenInfo[PrevKind];
@@ -178,6 +178,14 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
       return true;
     ConcatInfo &= ~aci_avoid_equal;
   }
+  if (Tok.isAnnotation()) {
+    // Modules annotation can show up when generated automatically for includes.
+    assert((Tok.is(tok::annot_module_include) ||
+            Tok.is(tok::annot_module_begin) ||
+            Tok.is(tok::annot_module_end)) &&
+           "unexpected annotation in AvoidConcat");
+    ConcatInfo = 0;
+  }
 
   if (ConcatInfo == 0) return false;
 
index 8f1d88c6d58e5da6a25f5a418e553de7dcdecd2e..93c01cb1e128735b14df43d01741f7460fdb575d 100644 (file)
@@ -6893,11 +6893,11 @@ void ASTReader::InitializeSema(Sema &S) {
 
   // Makes sure any declarations that were deserialized "too early"
   // still get added to the identifier's declaration chains.
-  for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
-    pushExternalDeclIntoScope(PreloadedDecls[I],
-                              PreloadedDecls[I]->getDeclName());
+  for (uint64_t ID : PreloadedDeclIDs) {
+    NamedDecl *D = cast<NamedDecl>(GetDecl(ID));
+    pushExternalDeclIntoScope(D, D->getDeclName());
   }
-  PreloadedDecls.clear();
+  PreloadedDeclIDs.clear();
 
   // FIXME: What happens if these are changed by a module import?
   if (!FPPragmaOptions.empty()) {
@@ -7349,24 +7349,26 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
   }
 
   for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
-    NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
-    if (SemaObj) {
-      // If we're simply supposed to record the declarations, do so now.
-      if (Decls) {
-        Decls->push_back(D);
-        continue;
-      }
-
-      // Introduce this declaration into the translation-unit scope
-      // and add it to the declaration chain for this identifier, so
-      // that (unqualified) name lookup will find it.
-      pushExternalDeclIntoScope(D, II);
-    } else {
+    if (!SemaObj) {
       // Queue this declaration so that it will be added to the
       // translation unit scope and identifier's declaration chain
       // once a Sema object is known.
-      PreloadedDecls.push_back(D);
+      PreloadedDeclIDs.push_back(DeclIDs[I]);
+      continue;
     }
+
+    NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
+
+    // If we're simply supposed to record the declarations, do so now.
+    if (Decls) {
+      Decls->push_back(D);
+      continue;
+    }
+
+    // Introduce this declaration into the translation-unit scope
+    // and add it to the declaration chain for this identifier, so
+    // that (unqualified) name lookup will find it.
+    pushExternalDeclIntoScope(D, II);
   }
 }
 
index fce2e48882f8f0acb691ca35262684779d302196..6494551e4bfa0ce84e0c1e9f25e282d70725ff92 100644 (file)
@@ -1,3 +1,5 @@
+int top_left_before(void *);
+
 @import diamond_top;
 
 float left(float *);
index 34998cd4324b94abf9c5dc3cc6ebb07e956c56fa..30da14f6449b55218cef1fb57388e8173738aabb 100644 (file)
@@ -2,3 +2,4 @@ int top(int *);
 
 int top_left(char *c);
 
+int top_left_before(void *);
diff --git a/test/Modules/Inputs/preprocess-prefix.h b/test/Modules/Inputs/preprocess-prefix.h
new file mode 100644 (file)
index 0000000..04d0175
--- /dev/null
@@ -0,0 +1,2 @@
+int left_and_right(int *);
+#import "diamond_left.h"
diff --git a/test/Modules/preprocess.m b/test/Modules/preprocess.m
new file mode 100644 (file)
index 0000000..a1c024d
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs -include %S/Inputs/preprocess-prefix.h -E %s | FileCheck -strict-whitespace %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs -x objective-c-header -emit-pch %S/Inputs/preprocess-prefix.h -o %t.pch
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs -include-pch %t.pch -E %s | FileCheck -strict-whitespace %s
+#import "diamond_right.h"
+#import "diamond_right.h" // to check that imports get their own line
+void test() {
+  top_left_before();
+  left_and_right();
+}
+
+
+// CHECK: int left_and_right(int *);{{$}}
+// CHECK-NEXT: @import diamond_left; /* clang -E: implicit import for "{{.*}}diamond_left.h" */{{$}}
+
+// CHECK: @import diamond_right; /* clang -E: implicit import for "/Users/blangmuir/src/clang/test/Modules/Inputs/diamond_right.h" */{{$}}
+// CHECK: @import diamond_right; /* clang -E: implicit import for "/Users/blangmuir/src/clang/test/Modules/Inputs/diamond_right.h" */{{$}}
+// CHECK-NEXT: void test() {{{$}}
+// CHECK-NEXT:    top_left_before();{{$}}
+// CHECK-NEXT:    left_and_right();{{$}}
+// CHECK-NEXT: }{{$}}