[gcc r10-9536] Objective-C++ : Fix handling of unnamed message parms [PR49070].

Iain D Sandoe iains@gcc.gnu.org
Wed Mar 24 22:07:32 GMT 2021


https://gcc.gnu.org/g:e3cac00975a1de879dc8356285a8908c25026ec4

commit r10-9536-ge3cac00975a1de879dc8356285a8908c25026ec4
Author: Iain Sandoe <iain@sandoe.co.uk>
Date:   Fri Feb 26 10:21:02 2021 +0000

    Objective-C++ : Fix handling of unnamed message parms [PR49070].
    
    When we are parsing an Objective-C++ message, a colon is a valid
    terminator for a assignment-expression.  That is:
    
    [receiver meth:x:x:x:x];
    
    Is a valid, if somewhat unreadable, construction; corresponding
    to a method declaration like:
    
    - (id) meth:(id)arg0 :(id)arg1 :(id)arg2 :(id)arg3;
    
    Where three of the message params have no selector name.
    
    If fact, although it might be unintentional, Objective-C/C++ can
    accept message selectors with all the parms unnamed (this applies
    to the clang implementation too, which is taken as the reference
    for the language).
    
    For regular C++, the pattern x:x is not valid in that position an
    an error is emitted with a fixit for the expected scope token.
    
    If we simply made that error conditional on !c_dialect_objc()
    that would regress Objective-C++ diagnostics for cases outside a
    message selector, so we add a state flag for this.
    
    gcc/cp/ChangeLog:
    
            PR objc++/49070
            * parser.c (cp_debug_parser): Add Objective-C++ message
            state flag.
            (cp_parser_nested_name_specifier_opt): Allow colon to
            terminate an assignment-expression when parsing Objective-
            C++ messages.
            (cp_parser_objc_message_expression): Set and clear message
            parsing state on entry and exit.
            * parser.h (struct cp_parser): Add a context flag for
            Objective-C++ message state.
    
    gcc/testsuite/ChangeLog:
    
            PR objc++/49070
            * obj-c++.dg/pr49070.mm: New test.
            * objc.dg/unnamed-parms.m: New test.
    
    (cherry picked from commit 0cc218d42c241ed286cc5af9fb7d2e45386f7a24)

Diff:
---
 gcc/cp/parser.c                       |  8 +++++-
 gcc/cp/parser.h                       |  4 +++
 gcc/testsuite/obj-c++.dg/pr49070.mm   | 54 +++++++++++++++++++++++++++++++++++
 gcc/testsuite/objc.dg/unnamed-parms.m | 30 +++++++++++++++++++
 4 files changed, 95 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index f15b3a6a20f..1f4a28ff7c0 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -571,6 +571,8 @@ cp_debug_parser (FILE *file, cp_parser *parser)
 			      parser->colon_corrects_to_scope_p);
   cp_debug_print_flag (file, "Colon doesn't start a class definition",
 			      parser->colon_doesnt_start_class_def_p);
+  cp_debug_print_flag (file, "Parsing an Objective-C++ message context",
+			      parser->objective_c_message_context_p);
   if (parser->type_definition_forbidden_message)
     fprintf (file, "Error message for forbidden type definitions: %s %s\n",
 	     parser->type_definition_forbidden_message,
@@ -6404,7 +6406,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
 
 	  if (token->type == CPP_COLON
 	      && parser->colon_corrects_to_scope_p
-	      && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_NAME)
+	      && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_NAME
+	      /* name:name is a valid sequence in an Objective C message.  */
+	      && !parser->objective_c_message_context_p)
 	    {
 	      gcc_rich_location richloc (token->location);
 	      richloc.add_fixit_replace ("::");
@@ -32045,6 +32049,7 @@ cp_parser_objc_message_expression (cp_parser* parser)
 {
   tree receiver, messageargs;
 
+  parser->objective_c_message_context_p = true;
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
   cp_lexer_consume_token (parser->lexer);  /* Eat '['.  */
   receiver = cp_parser_objc_message_receiver (parser);
@@ -32061,6 +32066,7 @@ cp_parser_objc_message_expression (cp_parser* parser)
   location_t combined_loc = make_location (start_loc, start_loc, end_loc);
   protected_set_expr_location (result, combined_loc);
 
+  parser->objective_c_message_context_p = false;
   return result;
 }
 
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index ec487ea4252..602238f865a 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -349,6 +349,10 @@ struct GTY(()) cp_parser {
      is terminated by colon.  */
   bool colon_doesnt_start_class_def_p;
 
+  /* TRUE if we are parsing an objective c message, and ':' is permitted
+     to terminate an assignment-expression.  */
+  bool objective_c_message_context_p;
+
   /* If non-NULL, then we are parsing a construct where new type
      definitions are not permitted.  The string stored here will be
      issued as an error message if a type is defined.  */
diff --git a/gcc/testsuite/obj-c++.dg/pr49070.mm b/gcc/testsuite/obj-c++.dg/pr49070.mm
new file mode 100644
index 00000000000..e946c5a4000
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/pr49070.mm
@@ -0,0 +1,54 @@
+/* Only needs to compile.  */
+/* { dg-additional-options "-std=c++11" } */
+
+#ifdef __cplusplus
+enum X {
+  x = 5,
+  y
+};
+#endif
+
+#if __has_attribute(__objc_root_class__)
+__attribute__((__objc_root_class__))
+#endif
+@interface A
+- (id) :(id)arg0 :(id)arg1;
+- (id) m:(id)arg0 :(id)arg1 :(id)arg2 :(id)arg3;
+#ifdef __cplusplus
+- (id) n:(X)arg0 :(X)arg1 :(id)arg2 :(id)arg3;
+#endif
+@end
+
+@implementation A
+- (id) :(id)arg0 :(id)arg1
+{
+  return arg1;
+}
+- (id) m:(id)arg0 :(id)arg1 :(id)arg2 :(id)arg3
+{
+  return arg2;
+}
+#ifdef __cplusplus
+- (id) n:(X)arg0 :(X)arg1 :(id)arg2 :(id)arg3
+{
+  return arg2;
+}
+#endif
+@end
+
+id f1 (A *x)
+{
+  return [x:x:x];
+}
+
+id f2 (A *x)
+{
+  return [x m:x:x:x:x];
+}
+
+#ifdef __cplusplus
+id f3 (A *x)
+{
+  return [x n:X::x:X::y:x:x];
+}
+#endif
diff --git a/gcc/testsuite/objc.dg/unnamed-parms.m b/gcc/testsuite/objc.dg/unnamed-parms.m
new file mode 100644
index 00000000000..b1c457c735b
--- /dev/null
+++ b/gcc/testsuite/objc.dg/unnamed-parms.m
@@ -0,0 +1,30 @@
+/* Only needs to compile [see PR 49070 for C++ issue].  */
+
+#if __has_attribute(__objc_root_class__)
+__attribute__((__objc_root_class__))
+#endif
+@interface A
+- (id) :(id)arg0 :(id)arg1;
+- (id) m:(id)arg0 :(id)arg1 :(id)arg2 :(id)arg3;
+@end
+
+@implementation A
+- (id) :(id)arg0 :(id)arg1
+{
+  return arg1;
+}
+- (id) m:(id)arg0 :(id)arg1 :(id)arg2 :(id)arg3
+{
+  return arg2;
+}
+@end
+
+id f1 (A *x)
+{
+  return [x:x:x];
+}
+
+id f2 (A *x)
+{
+  return [x m:x:x:x:x];
+}


More information about the Gcc-cvs mailing list