This is so that use of symbols referenced in these asm()-s can be
properly tracked by the compiler, just like is the case for all other
asm()-s. I'm particularly looking forward to use this in the Linux
kernel. It is certainly not very useful in PIC code, at least not with
some extra care.

gcc/
2011-09-30  Jan Beulich  <jbeul...@suse.com>

        * c-parser.c (c_parser_simple_asm_expr): Add new second parameter
        'inputsp'. Process inputs if caller indicates they are allowed. Adjust
        calls to c_parser_asm_operands().
        (c_parser_asm_operands): Change type of second parameter from 'bool'
        to 'int'. Call c_parser_expression() only for non-negative 'mode', and
        c_parser_expr_no_commas() otherwise.
        (c_parser_declaration_or_fndef): Pass NULL as new second argument to
        c_parser_simple_asm_expr().
        (c_parser_asm_definition): New local variables 'loc' and 'inputs'.
        Adjust calls to c_parser_simple_asm_expr() and cgraph_add_asm_node().
        (c_parser_simple_asm_expr): 
        * cgraph.c (cgraph_add_asm_node): Call check_unique_operand_names() to
        validate input operands. Store inputs and location.
        * cgraph.h (struct cgraph_asm_node): Add 'inputs' and 'loc'.
        (cgraph_add_asm_node): New second and third parameters.
        * cgraphunit.c (cgraph_output_pending_asms): Pass new second and third
        arguments to assemble_asm().
        (process_function_and_variable_attributes): New local variable 'anode'.
        Process list starting from 'cgraph_asm_nodes'.
        (cgraph_output_in_order): Pass new second and third arguments to
        assemble_asm().
        * cp/parser.c (enum required_token): Add RT_COLON_NO_OUTPUT.
        (cp_parser_asm_definition): New local variable 'loc'. Correct a
        comment. Parse and process input operands if permitted.
        (cp_parser_required_error): Handle new case RT_COLON_NO_OUTPUT.
        * lto-streamer-in.c (lto_input_toplevel_asms): Pass new second and
        third arguments to cgraph_add_asm_node().
        * lto-streamer-out.c (lto_output_toplevel_asms): Also output inputs
        and location.
        * output.h (assemble_asm): New second and third parameters.
        * stmt.c (check_unique_operand_names): Remove static declaration and
        make global.
        * tree.h (check_unique_operand_names): Declare.
        * varasm.c: Include pretty-print.h.
        (assemble_asm): New parameters 'inputs' and 'loc'. Process inputs if
        provided.

gcc/testsuite/
2011-09-30  Jan Beulich  <jbeul...@suse.com>

        * g++.dg/ext/asm-static-1.C: New.
        * gcc.dg/asm-static-1.c: New.
        * gcc.dg/asm-static-2.c: New.
        * gcc.dg/asm-static-3.c: New.
        * gcc.dg/asm-static-4.c: New.

--- 2011-09-29.orig/gcc/c-parser.c      2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/c-parser.c   2011-09-29 15:07:29.000000000 +0200
@@ -1131,7 +1131,7 @@ static struct c_arg_info *c_parser_parms
 static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree,
                                                          tree);
 static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
-static tree c_parser_simple_asm_expr (c_parser *);
+static tree c_parser_simple_asm_expr (c_parser *, tree *);
 static tree c_parser_attributes (c_parser *);
 static struct c_type_name *c_parser_type_name (c_parser *);
 static struct c_expr c_parser_initializer (c_parser *);
@@ -1150,7 +1150,7 @@ static void c_parser_while_statement (c_
 static void c_parser_do_statement (c_parser *);
 static void c_parser_for_statement (c_parser *);
 static tree c_parser_asm_statement (c_parser *);
-static tree c_parser_asm_operands (c_parser *, bool);
+static tree c_parser_asm_operands (c_parser *, int);
 static tree c_parser_asm_goto_operands (c_parser *);
 static tree c_parser_asm_clobbers (c_parser *);
 static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
@@ -1623,7 +1623,7 @@ c_parser_declaration_or_fndef (c_parser 
             function definition.  */
          fndef_ok = false;
          if (c_parser_next_token_is_keyword (parser, RID_ASM))
-           asm_name = c_parser_simple_asm_expr (parser);
+           asm_name = c_parser_simple_asm_expr (parser, NULL);
          if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
            postfix_attrs = c_parser_attributes (parser);
          if (c_parser_next_token_is (parser, CPP_EQ))
@@ -1782,9 +1782,12 @@ c_parser_declaration_or_fndef (c_parser 
 static void
 c_parser_asm_definition (c_parser *parser)
 {
-  tree asm_str = c_parser_simple_asm_expr (parser);
+  location_t loc = c_parser_peek_token (parser)->location;
+  tree inputs = NULL_TREE;
+  tree asm_str = c_parser_simple_asm_expr (parser, &inputs);
+
   if (asm_str)
-    cgraph_add_asm_node (asm_str);
+    cgraph_add_asm_node (asm_str, inputs, loc);
   c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
 }
 
@@ -3330,10 +3333,11 @@ c_parser_asm_string_literal (c_parser *p
 
    simple-asm-expr:
      asm ( asm-string-literal )
+     asm ( asm-string-literal :: asm-operands )
 */
 
 static tree
-c_parser_simple_asm_expr (c_parser *parser)
+c_parser_simple_asm_expr (c_parser *parser, tree *inputsp)
 {
   tree str;
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
@@ -3347,6 +3351,11 @@ c_parser_simple_asm_expr (c_parser *pars
       return NULL_TREE;
     }
   str = c_parser_asm_string_literal (parser);
+  if (inputsp && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN)
+      && c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>")
+      && c_parser_require (parser, CPP_COLON,
+                          "expected %<:%> (no output operands allowed here)"))
+      *inputsp = c_parser_asm_operands (parser, -1);
   parser->lex_untranslated_string = false;
   if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
     {
@@ -5050,10 +5059,10 @@ c_parser_asm_statement (c_parser *parser
            /* For asm goto, we don't allow output operands, but reserve
               the slot for a future extension that does allow them.  */
            if (!is_goto)
-             outputs = c_parser_asm_operands (parser, false);
+             outputs = c_parser_asm_operands (parser, 0);
            break;
          case 1:
-           inputs = c_parser_asm_operands (parser, true);
+           inputs = c_parser_asm_operands (parser, 1);
            break;
          case 2:
            clobbers = c_parser_asm_clobbers (parser);
@@ -5091,9 +5100,10 @@ c_parser_asm_statement (c_parser *parser
   goto error;
 }
 
-/* Parse asm operands, a GNU extension.  If CONVERT_P (for inputs but
-   not outputs), apply the default conversion of functions and arrays
-   to pointers.
+/* Parse asm operands, a GNU extension.  If MODE is non-zero (for inputs
+   but not outputs), apply the default conversion of functions and arrays
+   to pointers.  If MODE is negative (for inputs of asm definitions),
+   don't allow comma expressions.
 
    asm-operands:
      asm-operand
@@ -5105,7 +5115,7 @@ c_parser_asm_statement (c_parser *parser
 */
 
 static tree
-c_parser_asm_operands (c_parser *parser, bool convert_p)
+c_parser_asm_operands (c_parser *parser, int mode)
 {
   tree list = NULL_TREE;
   location_t loc;
@@ -5144,9 +5154,12 @@ c_parser_asm_operands (c_parser *parser,
          return NULL_TREE;
        }
       loc = c_parser_peek_token (parser)->location;
-      expr = c_parser_expression (parser);
+      if (mode >= 0)
+       expr = c_parser_expression (parser);
+      else
+       expr = c_parser_expr_no_commas(parser, NULL);
       mark_exp_read (expr.value);
-      if (convert_p)
+      if (mode)
        expr = default_function_array_conversion (loc, expr);
       expr.value = c_fully_fold (expr.value, false, NULL);
       parser->lex_untranslated_string = true;
--- 2011-09-29.orig/gcc/cgraph.c        2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/cgraph.c     2011-09-29 15:07:29.000000000 +0200
@@ -1990,12 +1990,15 @@ change_decl_assembler_name (tree decl, t
 /* Add a top-level asm statement to the list.  */
 
 struct cgraph_asm_node *
-cgraph_add_asm_node (tree asm_str)
+cgraph_add_asm_node (tree asm_str, tree inputs, location_t loc)
 {
   struct cgraph_asm_node *node;
 
   node = ggc_alloc_cleared_cgraph_asm_node ();
   node->asm_str = asm_str;
+  node->inputs = check_unique_operand_names (NULL_TREE, inputs, NULL_TREE)
+                ? inputs : NULL_TREE;
+  node->loc = loc;
   node->order = cgraph_order++;
   node->next = NULL;
   if (cgraph_asm_nodes == NULL)
--- 2011-09-29.orig/gcc/cgraph.h        2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/cgraph.h     2011-09-29 15:07:29.000000000 +0200
@@ -430,6 +430,10 @@ struct GTY(()) cgraph_asm_node {
   struct cgraph_asm_node *next;
   /* String for this asm node.  */
   tree asm_str;
+  /* Inputs for this asm node (optional).  */
+  tree inputs;
+  /* Source location of the asm().  */
+  location_t loc;
   /* Ordering of all cgraph nodes.  */
   int order;
 };
@@ -510,7 +514,7 @@ void cgraph_redirect_edge_callee (struct
 void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *);
 bool cgraph_only_called_directly_p (struct cgraph_node *);
 
-struct cgraph_asm_node *cgraph_add_asm_node (tree);
+struct cgraph_asm_node *cgraph_add_asm_node (tree, tree, location_t);
 
 bool cgraph_function_possibly_inlined_p (tree);
 void cgraph_unnest_node (struct cgraph_node *);
--- 2011-09-29.orig/gcc/cgraphunit.c    2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/cgraphunit.c 2011-09-29 15:07:29.000000000 +0200
@@ -819,7 +819,7 @@ cgraph_output_pending_asms (void)
     return;
 
   for (can = cgraph_asm_nodes; can; can = can->next)
-    assemble_asm (can->asm_str);
+    assemble_asm (can->asm_str, can->inputs, can->loc);
   cgraph_asm_nodes = NULL;
 }
 
@@ -972,6 +972,7 @@ process_function_and_variable_attributes
 {
   struct cgraph_node *node;
   struct varpool_node *vnode;
+  struct cgraph_asm_node *anode;
 
   for (node = cgraph_nodes; node != first; node = node->next)
     {
@@ -1052,6 +1053,47 @@ process_function_and_variable_attributes
        }
       process_common_attributes (decl);
     }
+  for (anode = cgraph_asm_nodes; anode; anode = anode->next)
+    if (anode->inputs)
+      {
+       tree node = anode->inputs;
+
+       for (; node && node != error_mark_node; node = TREE_CHAIN (node))
+         {
+           tree value = TREE_VALUE (node);
+
+           while (value && value != error_mark_node)
+             {
+               switch (TREE_CODE (value))
+                 {
+                   case INTEGER_CST:
+                     value = NULL_TREE;
+                     break;
+
+                   CASE_CONVERT:
+                   case ADDR_EXPR:
+                   case FDESC_EXPR:
+                   case POINTER_PLUS_EXPR:
+                   case COMPONENT_REF:
+                     value = TREE_OPERAND (value, 0);
+                     break;
+
+                   case FUNCTION_DECL:
+                   case VAR_DECL:
+                     mark_decl_referenced (value);
+                     value = NULL_TREE;
+                     break;
+
+                   default:
+                     error_at (EXPR_LOCATION (value),
+                               "expression not supported as file scope"
+                               " asm() input");
+                     value = NULL_TREE;
+                     break;
+                 }
+             }
+         }
+      }
 }
 
 /* Process CGRAPH_NODES_NEEDED queue, analyze each function (and transitively
@@ -1965,7 +2007,8 @@ cgraph_output_in_order (void)
          break;
 
        case ORDER_ASM:
-         assemble_asm (nodes[i].u.a->asm_str);
+         assemble_asm (nodes[i].u.a->asm_str, nodes[i].u.a->inputs,
+                       nodes[i].u.a->loc);
          break;
 
        case ORDER_UNDEFINED:
--- 2011-09-29.orig/gcc/cp/parser.c     2011-09-28 10:53:33.000000000 +0200
+++ 2011-09-29/gcc/cp/parser.c  2011-09-29 15:07:29.000000000 +0200
@@ -139,6 +139,7 @@ typedef enum required_token {
   RT_MULT, /* '*' */
   RT_COMPL, /* '~' */
   RT_COLON, /* ':' */
+  RT_COLON_NO_OUTPUT, /* ':' with "no output" remark */
   RT_COLON_SCOPE, /* ':' or '::' */
   RT_CLOSE_PAREN, /* ')' */
   RT_COMMA_CLOSE_PAREN, /* ',' or ')' */
@@ -14282,6 +14283,7 @@ cp_parser_asm_definition (cp_parser* par
   bool invalid_inputs_p = false;
   bool invalid_outputs_p = false;
   bool goto_p = false;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
   required_token missing = RT_NONE;
 
   /* Look for the `asm' keyword.  */
@@ -14363,7 +14365,7 @@ cp_parser_asm_definition (cp_parser* par
        {
          /* Consume the `:' or `::'.  */
          cp_lexer_consume_token (parser->lexer);
-         /* Parse the output-operands.  */
+         /* Parse the input-operands.  */
          if (cp_lexer_next_token_is_not (parser->lexer,
                                          CPP_COLON)
              && cp_lexer_next_token_is_not (parser->lexer,
@@ -14414,6 +14416,34 @@ cp_parser_asm_definition (cp_parser* par
     }
   else if (goto_p)
     missing = RT_COLON_SCOPE;
+  else if (cp_parser_allow_gnu_extensions_p (parser)
+          && ! parser->in_function_body
+          && (cp_lexer_next_token_is (parser->lexer, CPP_COLON)
+              || cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)))
+    {
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+       {
+         /* Consume the `:'.  */
+         cp_lexer_consume_token (parser->lexer);
+         if (! cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+           {
+             invalid_outputs_p = true;
+             missing = RT_COLON_NO_OUTPUT;
+           }
+       }
+
+      if (! invalid_outputs_p)
+       {
+         /* Consume the `:' or `::'.  */
+         cp_lexer_consume_token (parser->lexer);
+
+         /* Parse the input-operands.  */
+         inputs = cp_parser_asm_operand_list (parser);
+
+         if (inputs == error_mark_node)
+           invalid_inputs_p = true;
+       }
+    }
 
   /* Look for the closing `)'.  */
   if (!cp_parser_require (parser, missing ? CPP_COLON : CPP_CLOSE_PAREN,
@@ -14440,7 +14470,33 @@ cp_parser_asm_definition (cp_parser* par
            }
        }
       else
-       cgraph_add_asm_node (string);
+       {
+         tree input = inputs;
+
+         while (input && input != error_mark_node)
+           {
+             tree operand = decay_conversion (TREE_VALUE (input));
+
+             /* If the type of the operand hasn't been determined (e.g.,
+                because it involves an overloaded function), then issue
+                an error message.  There's no context available to
+                resolve the overloading.  */
+             if (TREE_TYPE (operand) == unknown_type_node)
+               {
+                 error ("type of asm operand %qE could not be determined",
+                        TREE_VALUE (input));
+                 operand = error_mark_node;
+               }
+
+             if (!cxx_mark_addressable (operand))
+               operand = error_mark_node;
+
+             TREE_VALUE (input) = operand;
+
+             input = TREE_CHAIN (input);
+           }
+         cgraph_add_asm_node (string, inputs, loc);
+       }
     }
 }
 
@@ -21344,6 +21400,9 @@ cp_parser_required_error (cp_parser *par
          case RT_COLON:
            cp_parser_error (parser, "expected %<:%>");
            return;
+         case RT_COLON_NO_OUTPUT:
+           cp_parser_error (parser, "expected %<:%> (no output operands 
allowed here)");
+           return;
          case RT_COLON_SCOPE:
            cp_parser_error (parser, "expected %<:%> or %<::%>");
            return;
--- 2011-09-29.orig/gcc/lto-streamer-in.c       2011-09-29 15:07:23.000000000 
+0200
+++ 2011-09-29/gcc/lto-streamer-in.c    2011-09-29 15:07:29.000000000 +0200
@@ -1173,7 +1173,12 @@ lto_input_toplevel_asms (struct lto_file
                     header->lto_header.minor_version);
 
   while ((str = streamer_read_string_cst (data_in, &ib)))
-    cgraph_add_asm_node (str);
+    {
+      tree inputs = lto_input_tree (&ib, data_in);
+      location_t loc = lto_input_location (&ib, data_in);
+
+      cgraph_add_asm_node (str, inputs, loc);
+    }
 
   clear_line_info (data_in);
   lto_data_in_delete (data_in);
--- 2011-09-29.orig/gcc/lto-streamer-out.c      2011-09-29 15:07:23.000000000 
+0200
+++ 2011-09-29/gcc/lto-streamer-out.c   2011-09-29 15:07:29.000000000 +0200
@@ -954,7 +954,11 @@ lto_output_toplevel_asms (void)
   streamer_write_char_stream (ob->string_stream, 0);
 
   for (can = cgraph_asm_nodes; can; can = can->next)
-    streamer_write_string_cst (ob, ob->main_stream, can->asm_str);
+    {
+      streamer_write_string_cst (ob, ob->main_stream, can->asm_str);
+      lto_output_tree (ob, can->inputs, false);
+      lto_output_location (ob, can->loc);
+    }
 
   streamer_write_string_cst (ob, ob->main_stream, NULL_TREE);
 
--- 2011-09-29.orig/gcc/output.h        2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/output.h     2011-09-29 15:07:29.000000000 +0200
@@ -188,7 +188,7 @@ extern void default_assemble_visibility 
 
 /* Output a string of literal assembler code
    for an `asm' keyword used between functions.  */
-extern void assemble_asm (tree);
+extern void assemble_asm (tree, tree, location_t);
 
 /* Output assembler code for the constant pool of a function and associated
    with defining the name of the function.  DECL describes the function.
--- 2011-09-29.orig/gcc/stmt.c  2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/stmt.c       2011-09-29 15:07:29.000000000 +0200
@@ -113,7 +113,6 @@ static int n_occurrences (int, const cha
 static bool tree_conflicts_with_clobbers_p (tree, HARD_REG_SET *);
 static void expand_nl_goto_receiver (void);
 static bool check_operand_nalternatives (tree, tree);
-static bool check_unique_operand_names (tree, tree, tree);
 static char *resolve_operand_name_1 (char *, tree, tree, tree);
 static void expand_null_return_1 (void);
 static void expand_value_return (rtx);
@@ -1250,7 +1249,7 @@ check_operand_nalternatives (tree output
    are identifiers, and so have been canonicalized by get_identifier,
    so all we need are pointer comparisons.  */
 
-static bool
+bool
 check_unique_operand_names (tree outputs, tree inputs, tree labels)
 {
   tree i, j;
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/g++.dg/ext/asm-static-1.C  2011-09-29 
15:07:29.000000000 +0200
@@ -0,0 +1,26 @@
+/* Check compilation of file scope asm() with input oprand(s). */
+/* { dg-do compile } */
+/* { dg-options "-fno-PIC" { target fpic } } */
+
+extern int aaa[];
+extern void fff(int*);
+extern struct s {
+       int i, a[2];
+} sss;
+static inline void iii(void)
+{
+}
+
+__asm__ (".long %c0" : : "i" (fff));
+__asm__ (".long %c0" : : "i" (aaa));
+__asm__ (".long %c0" : : "i" (iii));
+__asm__ (".long %c0" : : "i" (&sss.i));
+__asm__ (".long %c0" : : "i" (sss.a));
+__asm__ (".long %c0, %c1, %c2" :: "i" (-1), "i" ((long)fff), "i" (aaa + 1));
+__asm__ (".long %c[arr], %c[cnst], %c[fn]"
+        :: [cnst] "i" (-1), [fn] "i" ((long)fff), [arr] "i" (aaa + 1));
+
+/* { dg-final { scan-assembler "long.*aaa" } } */
+/* { dg-final { scan-assembler "long.*fff" } } */
+/* { dg-final { scan-assembler "long.*iii" } } */
+/* { dg-final { scan-assembler "long.*sss" } } */
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/gcc.dg/asm-static-1.c      2011-09-29 
15:07:29.000000000 +0200
@@ -0,0 +1,26 @@
+/* Check compilation of file scope asm() with input oprand(s). */
+/* { dg-do compile } */
+/* { dg-options "-fno-PIC" { target fpic } } */
+
+extern int aaa[];
+extern void fff(int*);
+extern struct s {
+       int i, a[2];
+} sss;
+static __inline__ void iii(void)
+{
+}
+
+__asm__ (".long %c0" :: "i" (fff));
+__asm__ (".long %c0" :: "i" (aaa));
+__asm__ (".long %c0" :: "i" (iii));
+__asm__ (".long %c0" :: "i" (&sss.i));
+__asm__ (".long %c0" :: "i" (sss.a));
+__asm__ (".long %c0, %c1, %c2" :: "i" (-1), "i" ((long)fff), "i" (aaa + 1));
+__asm__ (".long %c[arr], %c[cnst], %c[fn]"
+        :: [cnst] "i" (-1), [fn] "i" ((long)fff), [arr] "i" (aaa + 1));
+
+/* { dg-final { scan-assembler "long.*aaa" } } */
+/* { dg-final { scan-assembler "long.*fff" } } */
+/* { dg-final { scan-assembler "long.*iii" } } */
+/* { dg-final { scan-assembler "long.*sss" } } */
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/gcc.dg/asm-static-2.c      2011-09-29 
15:07:29.000000000 +0200
@@ -0,0 +1,9 @@
+/* Check for parse time errors. */
+/* { dg-do compile } */
+
+extern int a[];
+
+__asm__ (".long %c0" : "i" (0)); /* { dg-error "expected .?:.*no output 
operand" } */
+__asm__ (".long %c0" ::: "i" (0)); /* { dg-error "expected string literal" } */
+__asm__ (".long %c0" :: "=g" (a[0]): "0" (0)); /* { dg-error "expected .?\\)" 
} */
+__asm__ (".long %c[n]" :: [n] "i" (0), [n] "i" (0)); /* { dg-error 
"duplicate.*operand name" } */
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/gcc.dg/asm-static-3.c      2011-09-29 
15:07:29.000000000 +0200
@@ -0,0 +1,8 @@
+/* Check for errors detected before code generation. */
+/* { dg-do compile } */
+/* { dg-options "-fno-PIC" { target fpic } } */
+
+extern int a[];
+extern void f(int*);
+
+__asm__ (".long %c0" :: "i" ((long)a - (long)f)); /* { dg-error "expression 
not supported" } */
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ 2011-09-29/gcc/testsuite/gcc.dg/asm-static-4.c      2011-09-29 
15:07:29.000000000 +0200
@@ -0,0 +1,9 @@
+/* Check for errors detected during code generation. */
+/* { dg-do compile } */
+/* { dg-options "-fno-PIC" { target fpic } } */
+
+__asm__ (".long %0" :: "r" (0)); /* { dg-warning "invalid.*constraint ignored" 
} */
+__asm__ (".long %c1" :: "i" (0)); /* { dg-error "operand number out of range" 
} */
+__asm__ (".long %!0" :: "i" (0)); /* { dg-error "invalid.*%-code" } */
+__asm__ (".long %c[n" :: "i" (0)); /* { dg-error "missing close brace" } */
+__asm__ (".long %c[n]" :: "i" (0)); /* { dg-error "undefined named.*operand" } 
*/
--- 2011-09-29.orig/gcc/tree.h  2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/tree.h       2011-09-29 15:07:29.000000000 +0200
@@ -5624,6 +5624,7 @@ extern bool parse_input_constraint (cons
                                    const char * const *, bool *, bool *);
 extern void expand_asm_stmt (gimple);
 extern tree resolve_asm_operand_names (tree, tree, tree, tree);
+extern bool check_unique_operand_names (tree, tree, tree);
 extern bool expand_switch_using_bit_tests_p (tree, tree, unsigned int,
                                             unsigned int);
 extern void expand_case (gimple);
--- 2011-09-29.orig/gcc/varasm.c        2011-09-28 10:56:01.000000000 +0200
+++ 2011-09-29/gcc/varasm.c     2011-09-29 15:07:29.000000000 +0200
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.  
 #include "basic-block.h"
 #include "tree-iterator.h"
 #include "pointer-set.h"
+#include "pretty-print.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -1352,14 +1353,111 @@ make_decl_rtl_for_debug (tree decl)
    for an `asm' keyword used between functions.  */
 
 void
-assemble_asm (tree string)
+assemble_asm (tree string, tree inputs, location_t loc)
 {
   app_enable ();
 
   if (TREE_CODE (string) == ADDR_EXPR)
     string = TREE_OPERAND (string, 0);
 
-  fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
+  if (inputs)
+    {
+      const char *p = TREE_STRING_POINTER (string);
+      char c;
+
+      putc ('\t', asm_out_file);
+
+      while ((c = *p++))
+       {
+         tree node;
+
+         if (c != '%')
+           {
+             putc (c, asm_out_file);
+             continue;
+           }
+
+         c = *p;
+         if (!ISDIGIT(c))
+           switch (c)
+             {
+               case 'c': case 'a':
+                 /* For now simply ignore (but also don't require) these.  */
+                 c = *++p;
+                 break;
+               case '%':
+                 ++p;
+                 putc ('%', asm_out_file);
+                 continue;
+             }
+         if (c == '[')
+           {
+             const char *end = strchr (++p, ']');
+             char *q;
+
+             if (! end)
+               {
+                 error_at (loc,
+                           "missing close brace for named asm() operand");
+                 break;
+               }
+             q = xstrndup (p, end - p);
+
+             for (node = inputs; node && node != error_mark_node; )
+               {
+                 tree name = TREE_PURPOSE (TREE_PURPOSE (node));
+
+                 if (name && ! strcmp (TREE_STRING_POINTER (name), q))
+                   break;
+                 node = TREE_CHAIN (node);
+               }
+             if (! node)
+               error_at (loc, "undefined named asm() operand %qs",
+                         identifier_to_locale (q));
+             free (q);
+             p = end + 1;
+           }
+         else if (ISDIGIT(c))
+           {
+             char *endp;
+             unsigned long opnum = strtoul (p, &endp, 10);
+
+             for (node = inputs; opnum-- && node && node != error_mark_node; )
+               node = TREE_CHAIN (node);
+
+             if (! node)
+               error_at (loc, "asm() operand number out of range");
+             p = endp;
+           }
+         else
+           {
+             error_at (loc, 
+                       "unsupported or invalid asm() %%-code"
+                       " in this context");
+             break;
+           }
+
+         if (node && node != error_mark_node)
+           {
+             tree val = TREE_VALUE (node);
+
+             string = TREE_VALUE (TREE_PURPOSE (node));
+             gcc_assert (TREE_CODE (string) == STRING_CST);
+             if (strcmp (TREE_STRING_POINTER (string), "i"))
+               warning_at (loc, 0,
+                           "unsupported or invalid asm() constraint"
+                           " ignored - \"i\" assumed");
+
+             output_addr_const (asm_out_file,
+                                expand_expr (val, NULL_RTX, VOIDmode,
+                                             EXPAND_INITIALIZER));
+           }
+       }
+
+      putc ('\n', asm_out_file);
+    }
+  else
+    fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));
 }
 
 /* Record an element in the table of global destructors.  SYMBOL is


Reply via email to