This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PATCH RFA: Permit attributes on labels in C++


Jason Merrill <jason@redhat.com> writes:

> Ian Lance Taylor wrote:
>> Note that I changed is_late_template_attribute to mark the unused
>> attribute on a label as applying at template instantiation time.
>
> I don't think that's necessary; the change to re-apply attributes in
> tsubst_expr does the trick.

OK, removed.

>> +	  if (!cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"))
>> +	    gcc_unreachable ();
>
> This consumes the semicolon as part of the label, which breaks
>
> { label: __attribute ((unused)) ; }

Oh yeah.  Thanks for noticing that.  I added a test case.

Ran bootstrap and g++ testsuite on i686-unknown-linux-gnu.  OK for
mainline?

Ian


gcc/ChangeLog:

2009-06-06  Ian Lance Taylor  <iant@google.com>

	* doc/extend.texi (Attribute Syntax): Document that C++ labels on
	empty statements can now have attributes.

gcc/cp/ChangeLog:

2009-06-06  Ian Lance Taylor  <iant@google.com>

	* parser.c (cp_parser_label_for_labeled_statement): Support
	attribute on labels if immediately followed by semicolon.
	* semantics.c (finish_label_stmt): Return new label.
	* pt.c (tsubst_expr): Handle attributes for LABEL_EXPR.

gcc/testsuite/ChangeLog:

2009-06-06  Ian Lance Taylor  <iant@google.com>

	* gcc.dg/Wunused-label-1.c: New test case.
	* g++.dg/warn/Wunused-label-1.C: New test case.
	* g++.dg/warn/Wunused-label-2.C: New test case.
	* g++.dg/warn/Wunused-label-3.C: New test case.


Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 148230)
+++ cp/pt.c	(working copy)
@@ -10895,7 +10895,14 @@ tsubst_expr (tree t, tree args, tsubst_f
       break;
 
     case LABEL_EXPR:
-      finish_label_stmt (DECL_NAME (LABEL_EXPR_LABEL (t)));
+      {
+	tree decl = LABEL_EXPR_LABEL (t);
+	tree label;
+
+	label = finish_label_stmt (DECL_NAME (decl));
+	if (DECL_ATTRIBUTES (decl) != NULL_TREE)
+	  cplus_decl_attributes (&label, DECL_ATTRIBUTES (decl), 0);
+      }
       break;
 
     case GOTO_EXPR:
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 148230)
+++ cp/semantics.c	(working copy)
@@ -1315,17 +1315,19 @@ finish_asm_stmt (int volatile_p, tree st
   return add_stmt (r);
 }
 
-/* Finish a label with the indicated NAME.  */
+/* Finish a label with the indicated NAME.  Returns the new label.  */
 
 tree
 finish_label_stmt (tree name)
 {
   tree decl = define_label (input_location, name);
 
-  if (decl  == error_mark_node)
+  if (decl == error_mark_node)
     return error_mark_node;
 
-  return add_stmt (build_stmt (LABEL_EXPR, decl));
+  add_stmt (build_stmt (LABEL_EXPR, decl));
+
+  return decl;
 }
 
 /* Finish a series of declarations for local labels.  G++ allows users
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 148230)
+++ cp/parser.c	(working copy)
@@ -7052,6 +7052,7 @@ static void
 cp_parser_label_for_labeled_statement (cp_parser* parser)
 {
   cp_token *token;
+  tree label = NULL_TREE;
 
   /* The next token should be an identifier.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -7111,12 +7112,34 @@ cp_parser_label_for_labeled_statement (c
 
     default:
       /* Anything else must be an ordinary label.  */
-      finish_label_stmt (cp_parser_identifier (parser));
+      label = finish_label_stmt (cp_parser_identifier (parser));
       break;
     }
 
   /* Require the `:' token.  */
   cp_parser_require (parser, CPP_COLON, "%<:%>");
+
+  /* An ordinary label may optionally be followed by attributes.
+     However, this is only permitted if the attributes are then
+     followed by a semicolon.  This is because, for backward
+     compatibility, when parsing
+       lab: __attribute__ ((unused)) int i;
+     we want the attribute to attach to "i", not "lab".  */
+  if (label != NULL_TREE
+      && cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
+    {
+      tree attrs;
+
+      cp_parser_parse_tentatively (parser);
+      attrs = cp_parser_attributes_opt (parser);
+      if (attrs == NULL_TREE
+	  || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+	cp_parser_abort_tentative_parse (parser);
+      else if (!cp_parser_parse_definitely (parser))
+	;
+      else
+	cplus_decl_attributes (&label, attrs, 0);
+    }
 }
 
 /* Parse an expression-statement.
Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 148230)
+++ doc/extend.texi	(working copy)
@@ -3440,11 +3440,13 @@ feature is intended for code generated b
 that may be unused but which is compiled with @option{-Wall}.  It would
 not normally be appropriate to use in it human-written code, though it
 could be useful in cases where the code that jumps to the label is
-contained within an @code{#ifdef} conditional.  GNU C++ does not permit
-such placement of attribute lists, as it is permissible for a
-declaration, which could begin with an attribute list, to be labelled in
-C++.  Declarations cannot be labelled in C90 or C99, so the ambiguity
-does not arise there.
+contained within an @code{#ifdef} conditional.  GNU C++ only permits
+attributes on labels if the attribute specifier is immediately
+followed by a semicolon (i.e., the label applies to an empty
+statement).  If the semicolon is missing, C++ label attributes are
+ambiguous, as it is permissible for a declaration, which could begin
+with an attribute list, to be labelled in C++.  Declarations cannot be
+labelled in C90 or C99, so the ambiguity does not arise there.
 
 An attribute specifier list may appear as part of a @code{struct},
 @code{union} or @code{enum} specifier.  It may go either immediately
Index: testsuite/gcc.dg/Wunused-label-1.c
===================================================================
--- testsuite/gcc.dg/Wunused-label-1.c	(revision 0)
+++ testsuite/gcc.dg/Wunused-label-1.c	(revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Wunused-label" } */
+
+extern void f2 ();
+
+void
+f1 ()
+{
+ l1: f2 ();				/* { dg-warning "not used" } */
+ l2: __attribute__ ((unused)) f2 ();
+ l3: ; f2 ();				/* { dg-warning "not used" } */
+ l4: __attribute__ ((unused)) ; f2 ();
+}
Index: testsuite/g++.dg/warn/Wunused-label-1.C
===================================================================
--- testsuite/g++.dg/warn/Wunused-label-1.C	(revision 0)
+++ testsuite/g++.dg/warn/Wunused-label-1.C	(revision 0)
@@ -0,0 +1,28 @@
+// { dg-do compile }
+// { dg-options "-Wunused-label" }
+
+extern void f9();
+
+void
+f1()
+{
+ l1: f9();				// { dg-warning "not used" }
+ l3: ; f9();				// { dg-warning "not used" }
+ l4: __attribute__ ((unused)) ; f9();
+}
+
+void
+f2()
+{
+ label: __attribute ((unused)) ;
+}
+
+void
+f3()
+{
+  // The next line would be OK in C but is a syntax error in C++.
+ l2: __attribute__ ((unused)) f9();	// { dg-error "expected" }
+		// We still get an unused label warning--this is
+		// optional and can be removed if it ever changes.
+		// { dg-warning "not used" "expected" { target *-*-* } 24 }
+}
Index: testsuite/g++.dg/warn/Wunused-label-2.C
===================================================================
--- testsuite/g++.dg/warn/Wunused-label-2.C	(revision 0)
+++ testsuite/g++.dg/warn/Wunused-label-2.C	(revision 0)
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-Wunused" }
+
+// If __attribute__ ((unused)) follows a label and precedes a
+// declaration, we should get a warning for the label, not the
+// declaration.
+
+void
+f1()
+{
+  int i1;				// { dg-warning "unused variable" }
+ l1: __attribute__ ((unused)) int i2;	// { dg-warning "label \[^\n\]* not used" }
+}
Index: testsuite/g++.dg/warn/Wunused-label-3.C
===================================================================
--- testsuite/g++.dg/warn/Wunused-label-3.C	(revision 0)
+++ testsuite/g++.dg/warn/Wunused-label-3.C	(revision 0)
@@ -0,0 +1,51 @@
+// { dg-do compile }
+// { dg-options "-Wunused-label" }
+
+extern void f9();
+
+template<int i>
+void
+f1()
+{
+  if (i)
+    return;
+
+ l1: f9();				// { dg-warning "not used" }
+ l3: ; f9();				// { dg-warning "not used" }
+ l4: __attribute__ ((unused)) ; f9();
+}
+
+template
+void f1<0>();
+
+template<int i>
+void
+f2()
+{
+  if (i)
+    return;
+
+ l1: f9();				// { dg-warning "not used" }
+ l3: ; f9();				// { dg-warning "not used" }
+ l4: __attribute__ ((unused)) ; f9();
+}
+
+template
+void f2<1>();
+
+template<int i>
+void
+f3()
+{
+  void* lab;
+ l1: f9();
+ l2: __attribute__ ((unused)) ; f9();
+  lab = i ? &&l1 : &&l2;
+  goto *lab;
+}
+
+template
+void f3<0>();
+
+template
+void f3<1>();

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]