llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Akash Manna (akash-manna-sky)

<details>
<summary>Changes</summary>

Fixes #<!-- -->219354

For `template &lt;class T, int N&gt; &amp;T::foo() { ... }`, `T::` doesn't name 
a class, so Sema diagnoses the declarator and never creates a declaration. The 
parser still parses the body, but in a fake function scope that leaves 
`CurContext` at the translation unit while `T` and `N` are still visible. 
`collapse(N)` is dependent, so OpenMP holds off on building the loop 
expressions, and `finishLinearClauses` then asserts because the context isn't 
dependent. The same happens when Sema rejects a template parameter list but 
still builds an invalid, non-dependent declaration, like `template &lt;int 
N&gt; void A&lt;0&gt;::f() {}`, out of line or as an in-class friend. OpenMP is 
just the first thing to trip over it; this goes back to at least clang 9.

Now the body is skipped whenever template parameters are in scope but there's 
no dependent context to parse it in, i.e. no declaration at all or only an 
invalid, non-dependent one. The tokens are consumed the same way delayed 
template parsing already does, in `ParseFunctionDefinition` and where in-class 
definitions are cached. A valid function template always has a dependent 
context, so correct code isn't affected, and the declaration error is still 
reported.


---
Full diff: https://github.com/llvm/llvm-project/pull/226805.diff


4 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+5) 
- (modified) clang/lib/Parse/ParseCXXInlineMethods.cpp (+10) 
- (modified) clang/lib/Parse/Parser.cpp (+11) 
- (added) clang/test/OpenMP/gh219354.cpp (+47) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 3c6acf353f93f..1b4b0d9f3fbf5 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -707,6 +707,11 @@ features cannot lower the translation-unit ABI level;
 - Fixed merging of lambdas across modules in the case where neither lambda is
   imported from an AST file. (#GH214560)
 
+- Fixed an assertion when the body of an invalid function template definition,
+  such as `template <class T, int N> void T::f() {}`, used an OpenMP loop
+  directive. Such bodies are now skipped instead of being analyzed as
+  non-template code. (#GH219354)
+
 - Fixed a crash when a non-type template parameter of reference type is bound
   to a subobject and is used in a context that requires an implicit conversion.
   (#GH215900)
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp 
b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 35dbec8dfb2f7..3ddc870b045d4 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -138,6 +138,16 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
     return FnD;
   }
 
+  // The template parameters are in scope but there is no dependent context.
+  if (auto *FD = dyn_cast_if_present<FunctionDecl>(FnD);
+      FD && TemplateInfo.Kind == ParsedTemplateKind::Template &&
+      FD->isInvalidDecl() && !FD->isDependentContext()) {
+    CachedTokens Toks;
+    LexTemplateFunctionForLateParsing(Toks);
+    Actions.ActOnSkippedFunctionBody(FnD);
+    return FnD;
+  }
+
   // In delayed template parsing mode, if we are within a class template
   // or if we are about to parse function member template then consume
   // the tokens and store them for parsing at the end of the translation unit.
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index c86ed6b2ea3f9..fa0496e19d18e 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1405,6 +1405,17 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
     return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
   }
 
+  // The template parameters are in scope but there is no dependent context.
+  if (TemplateInfo.Kind == ParsedTemplateKind::Template &&
+      (!Res ||
+       (Res->isInvalidDecl() && !Res->getAsFunction()->isDependentContext()))) 
{
+    CachedTokens Toks;
+    LexTemplateFunctionForLateParsing(Toks);
+    BodyScope.Exit();
+    Actions.ActOnSkippedFunctionBody(Res);
+    return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
+  }
+
   return ParseFunctionBody(Res, BodyScope);
 }
 
diff --git a/clang/test/OpenMP/gh219354.cpp b/clang/test/OpenMP/gh219354.cpp
new file mode 100644
index 0000000000000..78850d6196456
--- /dev/null
+++ b/clang/test/OpenMP/gh219354.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fopenmp -fsyntax-only -verify %s
+
+template <class T, int N> &T::foo() { // expected-error {{nested name 
specifier 'T' for declaration does not refer into a class, class template or 
class template partial specialization}}
+#pragma omp simd collapse(N)
+  ;
+}
+
+struct S {
+  template <int N> void bar();
+};
+
+namespace NS {
+template <int N> void S::bar() { // expected-error {{cannot define or 
redeclare 'bar' here because namespace 'NS' does not enclose namespace 'S'}}
+#pragma omp simd collapse(N)
+  ;
+}
+}
+
+template <int M> class D;
+template <int M> template <int N> void D<M>::baz() { // expected-error 
{{out-of-line definition of 'baz' from class 'D<M>' without definition}}
+#pragma omp simd collapse(N)
+  ;
+}
+
+template <int> struct E {
+  void spec();
+};
+template <int N> void E<0>::spec() { // expected-error {{template parameter 
list matching the non-templated nested type 'E<0>' should be empty 
('template<>')}}
+#pragma omp simd collapse(N)
+  ;
+}
+
+template <int> struct G {
+  void fr();
+};
+struct H {
+  template <int N> friend void G<0>::fr() { // expected-error {{template 
parameter list matching the non-templated nested type 'G<0>' should be empty 
('template<>')}}
+#pragma omp simd collapse(N)
+    ;
+  }
+};
+
+#pragma omp declare simd // expected-error {{function declaration is expected 
after 'declare simd' directive}}
+template <class T, int N> void T::qux() { // expected-error {{nested name 
specifier 'T' for declaration does not refer into a class, class template or 
class template partial specialization}}
+#pragma omp simd collapse(N)
+  ;
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/226805
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to