[OPENMP]Fix skipping of functions body.
authorAlexey Bataev <a.bataev@hotmail.com>
Fri, 13 Dec 2019 21:05:30 +0000 (16:05 -0500)
committerAlexey Bataev <a.bataev@hotmail.com>
Fri, 13 Dec 2019 21:51:46 +0000 (16:51 -0500)
When parsing the code with OpenMP and the function's body must be
skipped, need to skip also OpenMP annotation tokens. Otherwise the
counters for braces/parens are unbalanced and parsing fails.

clang/include/clang/Parse/Parser.h
clang/include/clang/Parse/RAIIObjectsForParser.h
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Parse/Parser.cpp
clang/test/OpenMP/crash-skipped-bodies-template-inst.cpp [new file with mode: 0644]
clang/test/OpenMP/openmp_check.cpp

index a1e7bbb..7d13a4b 100644 (file)
@@ -56,6 +56,7 @@ namespace clang {
 ///
 class Parser : public CodeCompletionHandler {
   friend class ColonProtectionRAIIObject;
+  friend class ParsingOpenMPDirectiveRAII;
   friend class InMessageExpressionRAIIObject;
   friend class PoisonSEHIdentifiersRAIIObject;
   friend class ObjCDeclContextSwitch;
@@ -215,6 +216,9 @@ class Parser : public CodeCompletionHandler {
   /// ColonProtectionRAIIObject RAII object.
   bool ColonIsSacred;
 
+  /// Parsing OpenMP directive mode.
+  bool OpenMPDirectiveParsing = false;
+
   /// When true, we are directly inside an Objective-C message
   /// send expression.
   ///
index 558106e..fb092c0 100644 (file)
@@ -287,6 +287,25 @@ namespace clang {
     }
   };
 
+  /// Activates OpenMP parsing mode to preseve OpenMP specific annotation
+  /// tokens.
+  class ParsingOpenMPDirectiveRAII {
+    Parser &P;
+    bool OldVal;
+
+  public:
+    ParsingOpenMPDirectiveRAII(Parser &P)
+        : P(P), OldVal(P.OpenMPDirectiveParsing) {
+      P.OpenMPDirectiveParsing = true;
+    }
+
+    /// This can be used to restore the state early, before the dtor
+    /// is run.
+    void restore() { P.OpenMPDirectiveParsing = OldVal; }
+
+    ~ParsingOpenMPDirectiveRAII() { restore(); }
+  };
+
   /// RAII object that makes '>' behave either as an operator
   /// or as the closing angle bracket for a template argument list.
   class GreaterThanIsOperatorScope {
index 442d2ce..9dbbcc0 100644 (file)
@@ -1332,6 +1332,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
     AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
     DeclSpec::TST TagType, Decl *Tag) {
   assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+  ParsingOpenMPDirectiveRAII DirScope(*this);
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
 
   SourceLocation Loc = ConsumeAnnotationToken();
@@ -1667,6 +1668,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
 StmtResult
 Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
   assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+  ParsingOpenMPDirectiveRAII DirScope(*this);
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
   SmallVector<OMPClause *, 5> Clauses;
   SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
index 2645f27..ed4e6ff 100644 (file)
@@ -278,6 +278,10 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
     case tok::annot_pragma_openmp:
     case tok::annot_pragma_openmp_end:
       // Stop before an OpenMP pragma boundary.
+      if (OpenMPDirectiveParsing)
+        return false;
+      ConsumeAnnotationToken();
+      break;
     case tok::annot_module_begin:
     case tok::annot_module_end:
     case tok::annot_module_include:
diff --git a/clang/test/OpenMP/crash-skipped-bodies-template-inst.cpp b/clang/test/OpenMP/crash-skipped-bodies-template-inst.cpp
new file mode 100644 (file)
index 0000000..c7ba432
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: not %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:28:5 -fopenmp %s -o - 2>&1 | FileCheck %s
+template <class T>
+auto make_func() {
+  struct impl {
+    impl* func() {
+      int x;
+      if (x = 10) {
+      #pragma omp parallel
+        ;
+      }
+      // Check that body of this function is actually skipped.
+      // CHECK-NOT: crash-skipped-bodies-template-inst.cpp:7:{{[0-9]+}}: warning: using the result of an assignment as a condition without parentheses
+      return this;
+    }
+  };
+
+  int x;
+  if (x = 10) {}
+  // Check that this function is not skipped.
+  // CHECK: crash-skipped-bodies-template-inst.cpp:18:9: warning: using the result of an assignment as a condition without parentheses
+  return impl();
+}
+
+void foo() {
+  []() {
+    make_func<int>();
+    m
+    // CHECK: COMPLETION: make_func : [#auto#]make_func<<#class T#>>()
+  };
+}
index cd4706b..6a8dd17 100644 (file)
@@ -19,7 +19,6 @@ int nested(int a) {
 #if __cplusplus <= 199711L
   // expected-warning@-2 {{'auto' type specifier is a C++11 extension}}
   // expected-error@-3 {{expected expression}}
-  // expected-error@-4 {{expected ';' at end of declaration}}
 #endif
 
 #pragma omp parallel
@@ -29,14 +28,5 @@ int nested(int a) {
     }
   };
   F();
-#if __cplusplus <= 199711L
-  // expected-error@-2 {{C++ requires a type specifier for all declarations}}
-#endif
   return a;
-#if __cplusplus <= 199711L
-  // expected-error@-2 {{expected unqualified-id}}
-#endif
 }
-#if __cplusplus <= 199711L
-// expected-error@-2 {{extraneous closing brace ('}')}}
-#endif