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]

PATCH RFA: Permit attributes on labels in C++


The gcc C frontend permits attributes on labels by having __attribute__
follow the label, as in
    lab: __attribute__ ((unused))

A simple adaptation for this is not appropriate for C++, because in C++,
unlike C, a label is permitted on a declaration, as in
    lab: __attribute__ ((unused)) int i;
For backward compatibility in such a case, the attribute should attach
to the variable i, not to the label lab.

However, it is safe to attach the attribute to the label when the label
applies to an empty statement, as in
    lab: __attribute__ ((unused)) ;
In this case no ambiguity is possible.

There is no conflict with C++0X, as in C++ label attributes come
*before* the label:
    [[unused]] lab:
(In retrospect, that might have been a wiser choice for gcc as well.)

This patch changes the C++ frontend to permit attributes on labels if
the __attribute__ clauses is followed immediately by a semicolon.
Besides C++ test cases, this patch adds a C test case to verify that
attributes on labels on empty statements work as expected.

Note that I changed is_late_template_attribute to mark the unused
attribute on a label as applying at template instantiation time.  I
think that is safe, but on the other hand it also seems possible that
whether a label is used or unused can be determined entirely at the time
that the template is written.  Please pay attention to that part of the
patch.

Something like this patch is a prerequisite for merging gcc-in-cxx into
mainline, so that g++ does not issue warnings for the unused labels in
insn-recog.c.

Bootstrapped on i686-unknown-linux-gnu.  I ran the C++ testsuite.

This patch requires approval from the C++ frontend maintainers.

OK for mainline?

Ian


gcc/ChangeLog:

2009-05-29  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-05-29  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.
	* decl2.c (is_late_template_attribute): Postpone unused attribute
	on a label.
	* pt.c (tsubst_expr): Handle attributes for LABEL_EXPR.

gcc/testsuite/ChangeLog:

2009-05-29  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 147961)
+++ 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 147961)
+++ 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/decl2.c
===================================================================
--- cp/decl2.c	(revision 147961)
+++ cp/decl2.c	(working copy)
@@ -1038,6 +1038,11 @@ is_late_template_attribute (tree attr, t
   if (is_attribute_p ("weak", name))
     return true;
 
+  /* The unused attribute on a label must be applied at instantation
+     time.  */
+  if (TREE_CODE (decl) == LABEL_DECL && is_attribute_p ("unused", name))
+    return true;
+
   /* If any of the arguments are dependent expressions, we can't evaluate
      the attribute until instantiation time.  */
   for (arg = args; arg; arg = TREE_CHAIN (arg))
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 147961)
+++ 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,38 @@ 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
+	{
+	  if (!cp_parser_require (parser, CPP_SEMICOLON, "%<;%>"))
+	    gcc_unreachable ();
+	  cplus_decl_attributes (&label, attrs, 0);
+	}
+    }
 }
 
 /* Parse an expression-statement.
Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 147961)
+++ 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,22 @@
+// { 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()
+{
+  // 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 *-*-* } 18 }
+}
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]