Author: Michele Scandale
Date: 2020-02-24T08:08:47-05:00
New Revision: bd5b22070b6984d89c13b6cf38c3e54fc98ce291

URL: 
https://github.com/llvm/llvm-project/commit/bd5b22070b6984d89c13b6cf38c3e54fc98ce291
DIFF: 
https://github.com/llvm/llvm-project/commit/bd5b22070b6984d89c13b6cf38c3e54fc98ce291.diff

LOG: Fix TryParsePtrOperatorSeq.

The syntax rules for ptr-operator allow attributes after *, &,
&&, therefore we should be able to parse the following:

void fn() {
    void (*[[attr]] x)() = &fn;
    void (&[[attr]] y)() = fn;
    void (&&[[attr]] z)() = fn;
}
However the current logic in TryParsePtrOperatorSeq does not consider
the presence of attributes leading to unexpected parsing errors.

Moreover we should also consider _Atomic a possible qualifier that can
appear after the sequence of attribute specifiers.

Added: 
    

Modified: 
    clang/include/clang/Parse/Parser.h
    clang/lib/Parse/ParseTentative.cpp
    clang/test/CXX/dcl.decl/p4-0x.cpp
    clang/test/Parser/cxx-ambig-decl-expr.cpp
    clang/test/Parser/cxx-attributes.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 879c7fdf682d..8802bf9bb90a 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2442,6 +2442,10 @@ class Parser : public CodeCompletionHandler {
   TPResult TryParseBracketDeclarator();
   TPResult TryConsumeDeclarationSpecifier();
 
+  /// Try to skip a possibly empty sequence of 'attribute-specifier's without
+  /// full validation of the syntactic structure of attributes.
+  bool TrySkipAttributes();
+
 public:
   TypeResult ParseTypeName(SourceRange *Range = nullptr,
                            DeclaratorContext Context

diff  --git a/clang/lib/Parse/ParseTentative.cpp 
b/clang/lib/Parse/ParseTentative.cpp
index ad0a15b0c8a6..75cc7c2912b5 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -186,21 +186,8 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
     ConsumeToken();
 
     // Skip attributes.
-    while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec,
-                       tok::kw_alignas)) {
-      if (Tok.is(tok::l_square)) {
-        ConsumeBracket();
-        if (!SkipUntil(tok::r_square))
-          return TPResult::Error;
-      } else {
-        ConsumeToken();
-        if (Tok.isNot(tok::l_paren))
-          return TPResult::Error;
-        ConsumeParen();
-        if (!SkipUntil(tok::r_paren))
-          return TPResult::Error;
-      }
-    }
+    if (!TrySkipAttributes())
+      return TPResult::Error;
 
     if (TryAnnotateOptionalCXXScopeToken())
       return TPResult::Error;
@@ -781,6 +768,32 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
   return CAK_NotAttributeSpecifier;
 }
 
+bool Parser::TrySkipAttributes() {
+  while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec,
+                     tok::kw_alignas)) {
+    if (Tok.is(tok::l_square)) {
+      ConsumeBracket();
+      if (Tok.isNot(tok::l_square))
+        return false;
+      ConsumeBracket();
+      if (!SkipUntil(tok::r_square) || Tok.isNot(tok::r_square))
+        return false;
+      // Note that explicitly checking for `[[` and `]]` allows to fail as
+      // expected in the case of the Objective-C message send syntax.
+      ConsumeBracket();
+    } else {
+      ConsumeToken();
+      if (Tok.isNot(tok::l_paren))
+        return false;
+      ConsumeParen();
+      if (!SkipUntil(tok::r_paren))
+        return false;
+    }
+  }
+
+  return true;
+}
+
 Parser::TPResult Parser::TryParsePtrOperatorSeq() {
   while (true) {
     if (TryAnnotateOptionalCXXScopeToken(true))
@@ -790,9 +803,14 @@ Parser::TPResult Parser::TryParsePtrOperatorSeq() {
         (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
       // ptr-operator
       ConsumeAnyToken();
+
+      // Skip attributes.
+      if (!TrySkipAttributes())
+        return TPResult::Error;
+
       while (Tok.isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_restrict,
                          tok::kw__Nonnull, tok::kw__Nullable,
-                         tok::kw__Null_unspecified))
+                         tok::kw__Null_unspecified, tok::kw__Atomic))
         ConsumeToken();
     } else {
       return TPResult::True;

diff  --git a/clang/test/CXX/dcl.decl/p4-0x.cpp 
b/clang/test/CXX/dcl.decl/p4-0x.cpp
index 35177a038697..3a7b21568044 100644
--- a/clang/test/CXX/dcl.decl/p4-0x.cpp
+++ b/clang/test/CXX/dcl.decl/p4-0x.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 struct X {
   void f() &;
@@ -7,3 +6,15 @@ struct X {
 };
 
 void (X::*pmf)() & = &X::f;
+
+void fn() {
+  void (*[[attr]] fn_ptr)() = &fn; // expected-warning{{unknown attribute 
'attr' ignored}}
+  void (*[[attrA]] *[[attrB]] fn_ptr_ptr)() = &fn_ptr; // 
expected-warning{{unknown attribute 'attrA' ignored}} expected-warning{{unknown 
attribute 'attrB' ignored}}
+
+  void (&[[attr]] fn_lref)() = fn; // expected-warning{{unknown attribute 
'attr' ignored}}
+  void (&&[[attr]] fn_rref)() = fn; // expected-warning{{unknown attribute 
'attr' ignored}}
+
+  int i[5];
+  int (*[[attr(i[1])]] pi);  // expected-warning{{unknown attribute 'attr' 
ignored}}
+  pi = &i[0];
+}

diff  --git a/clang/test/Parser/cxx-ambig-decl-expr.cpp 
b/clang/test/Parser/cxx-ambig-decl-expr.cpp
index 02857e21f7c3..6203db2fbd22 100644
--- a/clang/test/Parser/cxx-ambig-decl-expr.cpp
+++ b/clang/test/Parser/cxx-ambig-decl-expr.cpp
@@ -38,4 +38,7 @@ void arr() {
   // These are array declarations.
   int(x[(1,1)]); // expected-error {{redefinition}}
   int(x[true ? 1,1 : 1]); // expected-error {{redefinition}}
+
+  int (*_Atomic atomic_ptr_to_int);
+  *atomic_ptr_to_int = 42;
 }

diff  --git a/clang/test/Parser/cxx-attributes.cpp 
b/clang/test/Parser/cxx-attributes.cpp
index 6591532a91a2..53b098b6260a 100644
--- a/clang/test/Parser/cxx-attributes.cpp
+++ b/clang/test/Parser/cxx-attributes.cpp
@@ -22,3 +22,15 @@ namespace PR17666 {
 }
 
 __attribute((typename)) int x; // expected-warning {{unknown attribute 
'typename' ignored}}
+
+void fn() {
+  void (*__attribute__((attr)) fn_ptr)() = &fn; // expected-warning{{unknown 
attribute 'attr' ignored}}
+  void (*__attribute__((attrA)) *__attribute__((attrB)) fn_ptr_ptr)() = 
&fn_ptr; // expected-warning{{unknown attribute 'attrA' ignored}} 
expected-warning{{unknown attribute 'attrB' ignored}}
+
+  void (&__attribute__((attr)) fn_lref)() = fn; // expected-warning{{unknown 
attribute 'attr' ignored}}
+  void (&&__attribute__((attr)) fn_rref)() = fn; // expected-warning{{unknown 
attribute 'attr' ignored}}
+
+  int i[5];
+  int (*__attribute__((attr(i[1]))) pi);  // expected-warning{{unknown 
attribute 'attr' ignored}}
+  pi = &i[0];
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to