[Patch / RFC] Improving more locations for binary expressions

Paolo Carlini paolo.carlini@oracle.com
Fri May 11 23:35:00 GMT 2012


On 05/10/2012 04:28 PM, Jason Merrill wrote:
> Looks good.
Thanks Jason. The below is the idea fully implemented.

The call.c bits are exactly in the form I had in mind a couple of days ago.

The parser.c bits, the ones I actually preliminarily posted, are now a 
bit different: I noticed that in the middle of the function we were 
reading / writing all the cp_parser_expression_stack_entry fields by 
hand (and now would be one more) thus tweaked the algorithm to use a 
cp_parser_expression_stack_entry as local variable. In my opinion this 
tidies the code quite a bit and also makes manifest that tree_type and 
loc are always updated at the same time, as they should be.

Booted and tested x86_64-linux. Ok?

Thanks,
Paolo.

//////////////////////////////
-------------- next part --------------
/cp
2012-05-12

	* parser.c (struct cp_parser_expression_stack_entry): Add location_t
	field.
	(cp_parser_binary_expression): Rework to always update at the same
	time tree_type and loc.
	* call.c (print_z_candidate): Add location_t parameter.
	(print_z_candidates, convert_like_real, joust): Adjust.

/testsuite
2012-05-12

	* g++.dg/parse/error47.C: New.
-------------- next part --------------
Index: testsuite/g++.dg/parse/error47.C
===================================================================
--- testsuite/g++.dg/parse/error47.C	(revision 0)
+++ testsuite/g++.dg/parse/error47.C	(revision 0)
@@ -0,0 +1,9 @@
+struct T { };
+
+T foo();
+
+void bar(int a, int b)
+{
+  if (foo() && a < b) // { dg-error "13:no match for 'operator&&'" }
+    ;
+}
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 187414)
+++ cp/parser.c	(working copy)
@@ -1621,6 +1621,8 @@ typedef struct cp_parser_expression_stack_entry
   enum tree_code tree_type;
   /* Precedence of the binary operation we are parsing.  */
   enum cp_parser_prec prec;
+  /* Location of the binary operation we are parsing.  */
+  location_t loc;
 } cp_parser_expression_stack_entry;
 
 /* The stack for storing partial expressions.  We only need NUM_PREC_VALUES
@@ -7275,30 +7277,33 @@ cp_parser_binary_expression (cp_parser* parser, bo
 {
   cp_parser_expression_stack stack;
   cp_parser_expression_stack_entry *sp = &stack[0];
-  tree lhs, rhs;
+  cp_parser_expression_stack_entry sentry;
+  tree rhs;
   cp_token *token;
-  location_t loc;
-  enum tree_code tree_type, lhs_type, rhs_type;
+  enum tree_code rhs_type;
   enum cp_parser_prec new_prec, lookahead_prec;
   tree overload;
 
   /* Parse the first expression.  */
-  lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p, pidk);
-  lhs_type = ERROR_MARK;
+  sentry.lhs = cp_parser_cast_expression (parser, /*address_p=*/false,
+					  cast_p, pidk);
+  sentry.lhs_type = ERROR_MARK;
+  sentry.prec = prec;
 
   for (;;)
     {
       /* Get an operator token.  */
       token = cp_lexer_peek_token (parser->lexer);
-      loc = token->location;
 
       if (warn_cxx0x_compat
           && token->type == CPP_RSHIFT
           && !parser->greater_than_is_operator_p)
         {
-          if (warning_at (loc, OPT_Wc__0x_compat, "%<>>%> operator is treated"
+          if (warning_at (token->location, OPT_Wc__0x_compat,
+			  "%<>>%> operator is treated"
 			  " as two right angle brackets in C++11"))
-	    inform (loc, "suggest parentheses around %<>>%> expression");
+	    inform (token->location,
+		    "suggest parentheses around %<>>%> expression");
         }
 
       new_prec = TOKEN_PRECEDENCE (token);
@@ -7310,7 +7315,7 @@ cp_parser_binary_expression (cp_parser* parser, bo
 	 - or, we found an operator which has lower priority.  This is the case
 	   where the recursive descent *ascends*, as in `3 * 4 + 5' after
 	   parsing `3 * 4'.  */
-      if (new_prec <= prec)
+      if (new_prec <= sentry.prec)
 	{
 	  if (sp == stack)
 	    break;
@@ -7319,17 +7324,18 @@ cp_parser_binary_expression (cp_parser* parser, bo
 	}
 
      get_rhs:
-      tree_type = binops_by_token[token->type].tree_type;
+      sentry.tree_type = binops_by_token[token->type].tree_type;
+      sentry.loc = token->location;
 
       /* We used the operator token.  */
       cp_lexer_consume_token (parser->lexer);
 
       /* For "false && x" or "true || x", x will never be executed;
 	 disable warnings while evaluating it.  */
-      if (tree_type == TRUTH_ANDIF_EXPR)
-	c_inhibit_evaluation_warnings += lhs == truthvalue_false_node;
-      else if (tree_type == TRUTH_ORIF_EXPR)
-	c_inhibit_evaluation_warnings += lhs == truthvalue_true_node;
+      if (sentry.tree_type == TRUTH_ANDIF_EXPR)
+	c_inhibit_evaluation_warnings += sentry.lhs == truthvalue_false_node;
+      else if (sentry.tree_type == TRUTH_ORIF_EXPR)
+	c_inhibit_evaluation_warnings += sentry.lhs == truthvalue_true_node;
 
       /* Extract another operand.  It may be the RHS of this expression
 	 or the LHS of a new, higher priority expression.  */
@@ -7347,14 +7353,11 @@ cp_parser_binary_expression (cp_parser* parser, bo
 	     expression.  Since precedence levels on the stack are
 	     monotonically increasing, we do not have to care about
 	     stack overflows.  */
-	  sp->prec = prec;
-	  sp->tree_type = tree_type;
-	  sp->lhs = lhs;
-	  sp->lhs_type = lhs_type;
-	  sp++;
-	  lhs = rhs;
-	  lhs_type = rhs_type;
-	  prec = new_prec;
+	  *sp = sentry;
+	  ++sp;
+	  sentry.lhs = rhs;
+	  sentry.lhs_type = rhs_type;
+	  sentry.prec = new_prec;
 	  new_prec = lookahead_prec;
 	  goto get_rhs;
 
@@ -7367,20 +7370,17 @@ cp_parser_binary_expression (cp_parser* parser, bo
 	     the precedence of the higher level subexpression
 	     (`PREC_ADDITIVE_EXPRESSION').  TOKEN is the CPP_PLUS token,
 	     which will be used to actually build the additive expression.  */
+	  rhs = sentry.lhs;
+	  rhs_type = sentry.lhs_type;
 	  --sp;
-	  prec = sp->prec;
-	  tree_type = sp->tree_type;
-	  rhs = lhs;
-	  rhs_type = lhs_type;
-	  lhs = sp->lhs;
-	  lhs_type = sp->lhs_type;
+	  sentry = *sp;
 	}
 
       /* Undo the disabling of warnings done above.  */
-      if (tree_type == TRUTH_ANDIF_EXPR)
-	c_inhibit_evaluation_warnings -= lhs == truthvalue_false_node;
-      else if (tree_type == TRUTH_ORIF_EXPR)
-	c_inhibit_evaluation_warnings -= lhs == truthvalue_true_node;
+      if (sentry.tree_type == TRUTH_ANDIF_EXPR)
+	c_inhibit_evaluation_warnings -= sentry.lhs == truthvalue_false_node;
+      else if (sentry.tree_type == TRUTH_ORIF_EXPR)
+	c_inhibit_evaluation_warnings -= sentry.lhs == truthvalue_true_node;
 
       overload = NULL;
       /* ??? Currently we pass lhs_type == ERROR_MARK and rhs_type ==
@@ -7391,14 +7391,17 @@ cp_parser_binary_expression (cp_parser* parser, bo
 	 surrounded by parentheses.
       */
       if (no_toplevel_fold_p
-	  && lookahead_prec <= prec
+	  && lookahead_prec <= sentry.prec
 	  && sp == stack
-	  && TREE_CODE_CLASS (tree_type) == tcc_comparison)
-	lhs = build2 (tree_type, boolean_type_node, lhs, rhs);
+	  && TREE_CODE_CLASS (sentry.tree_type) == tcc_comparison)
+	sentry.lhs = build2 (sentry.tree_type, boolean_type_node,
+			     sentry.lhs, rhs);
       else
-	lhs = build_x_binary_op (loc, tree_type, lhs, lhs_type, rhs, rhs_type,
-				 &overload, tf_warning_or_error);
-      lhs_type = tree_type;
+	sentry.lhs = build_x_binary_op (sentry.loc, sentry.tree_type,
+					sentry.lhs, sentry.lhs_type,
+					rhs, rhs_type, &overload,
+					tf_warning_or_error);
+      sentry.lhs_type = sentry.tree_type;
 
       /* If the binary operator required the use of an overloaded operator,
 	 then this expression cannot be an integral constant-expression.
@@ -7412,7 +7415,7 @@ cp_parser_binary_expression (cp_parser* parser, bo
 	return error_mark_node;
     }
 
-  return lhs;
+  return sentry.lhs;
 }
 
 
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 187414)
+++ cp/call.c	(working copy)
@@ -163,7 +163,7 @@ static void op_error (location_t, enum tree_code,
 		      tree, tree, bool);
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
 							 tsubst_flags_t);
-static void print_z_candidate (const char *, struct z_candidate *);
+static void print_z_candidate (location_t, const char *, struct z_candidate *);
 static void print_z_candidates (location_t, struct z_candidate *);
 static tree build_this (tree);
 static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
@@ -3159,36 +3159,38 @@ print_arity_information (location_t loc, unsigned
    life simpler in print_z_candidates and for the translators.  */
 
 static void
-print_z_candidate (const char *msgstr, struct z_candidate *candidate)
+print_z_candidate (location_t loc, const char *msgstr,
+		   struct z_candidate *candidate)
 {
   const char *msg = (msgstr == NULL
 		     ? ""
 		     : ACONCAT ((msgstr, " ", NULL)));
-  location_t loc = location_of (candidate->fn);
+  location_t cloc = location_of (candidate->fn);
 
   if (TREE_CODE (candidate->fn) == IDENTIFIER_NODE)
     {
+      cloc = loc;
       if (candidate->num_convs == 3)
-	inform (input_location, "%s%D(%T, %T, %T) <built-in>", msg, candidate->fn,
+	inform (cloc, "%s%D(%T, %T, %T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type,
 		candidate->convs[2]->type);
       else if (candidate->num_convs == 2)
-	inform (input_location, "%s%D(%T, %T) <built-in>", msg, candidate->fn,
+	inform (cloc, "%s%D(%T, %T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type);
       else
-	inform (input_location, "%s%D(%T) <built-in>", msg, candidate->fn,
+	inform (cloc, "%s%D(%T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type);
     }
   else if (TYPE_P (candidate->fn))
-    inform (loc, "%s%T <conversion>", msg, candidate->fn);
+    inform (cloc, "%s%T <conversion>", msg, candidate->fn);
   else if (candidate->viable == -1)
-    inform (loc, "%s%#D <near match>", msg, candidate->fn);
+    inform (cloc, "%s%#D <near match>", msg, candidate->fn);
   else if (DECL_DELETED_FN (STRIP_TEMPLATE (candidate->fn)))
-    inform (loc, "%s%#D <deleted>", msg, candidate->fn);
+    inform (cloc, "%s%#D <deleted>", msg, candidate->fn);
   else
-    inform (loc, "%s%#D", msg, candidate->fn);
+    inform (cloc, "%s%#D", msg, candidate->fn);
   /* Give the user some information about why this candidate failed.  */
   if (candidate->reason != NULL)
     {
@@ -3197,23 +3199,23 @@ static void
       switch (r->code)
 	{
 	case rr_arity:
-	  print_arity_information (loc, r->u.arity.actual,
+	  print_arity_information (cloc, r->u.arity.actual,
 				   r->u.arity.expected);
 	  break;
 	case rr_arg_conversion:
-	  print_conversion_rejection (loc, &r->u.conversion);
+	  print_conversion_rejection (cloc, &r->u.conversion);
 	  break;
 	case rr_bad_arg_conversion:
-	  print_conversion_rejection (loc, &r->u.bad_conversion);
+	  print_conversion_rejection (cloc, &r->u.bad_conversion);
 	  break;
 	case rr_explicit_conversion:
-	  inform (loc, "  return type %qT of explicit conversion function "
+	  inform (cloc, "  return type %qT of explicit conversion function "
 		  "cannot be converted to %qT with a qualification "
 		  "conversion", r->u.conversion.from_type,
 		  r->u.conversion.to_type);
 	  break;
 	case rr_template_conversion:
-	  inform (loc, "  conversion from return type %qT of template "
+	  inform (cloc, "  conversion from return type %qT of template "
 		  "conversion function specialization to %qT is not an "
 		  "exact match", r->u.conversion.from_type,
 		  r->u.conversion.to_type);
@@ -3224,12 +3226,12 @@ static void
 	     them here.  */
 	  if (r->u.template_unification.tmpl == NULL_TREE)
 	    {
-	      inform (loc, "  substitution of deduced template arguments "
+	      inform (cloc, "  substitution of deduced template arguments "
 		      "resulted in errors seen above");
 	      break;
 	    }
 	  /* Re-run template unification with diagnostics.  */
-	  inform (loc, "  template argument deduction/substitution failed:");
+	  inform (cloc, "  template argument deduction/substitution failed:");
 	  fn_type_unification (r->u.template_unification.tmpl,
 			       r->u.template_unification.explicit_targs,
 			       r->u.template_unification.targs,
@@ -3247,7 +3249,7 @@ static void
 				tf_warning_or_error);
 	  break;
 	case rr_invalid_copy:
-	  inform (loc,
+	  inform (cloc,
 		  "  a constructor taking a single argument of its own "
 		  "class type is invalid");
 	  break;
@@ -3312,7 +3314,7 @@ print_z_candidates (location_t loc, struct z_candi
 
   inform_n (loc, n_candidates, "candidate is:", "candidates are:");
   for (; candidates; candidates = candidates->next)
-    print_z_candidate (NULL, candidates);
+    print_z_candidate (loc, NULL, candidates);
 }
 
 /* USER_SEQ is a user-defined conversion sequence, beginning with a
@@ -5678,7 +5680,7 @@ convert_like_real (conversion *convs, tree expr, t
 	    {
 	      permerror (loc, "invalid user-defined conversion "
 			 "from %qT to %qT", TREE_TYPE (expr), totype);
-	      print_z_candidate ("candidate is:", t->cand);
+	      print_z_candidate (loc, "candidate is:", t->cand);
 	      expr = convert_like_real (t, expr, fn, argnum, 1,
 					/*issue_conversion_warnings=*/false,
 					/*c_cast_p=*/false,
@@ -8405,8 +8407,8 @@ tweak:
 	      "ISO C++ says that these are ambiguous, even "
 	      "though the worst conversion for the first is better than "
 	      "the worst conversion for the second:");
-	      print_z_candidate (_("candidate 1:"), w);
-	      print_z_candidate (_("candidate 2:"), l);
+	      print_z_candidate (input_location, _("candidate 1:"), w);
+	      print_z_candidate (input_location, _("candidate 2:"), l);
 	    }
 	  else
 	    add_warning (w, l);


More information about the Gcc-patches mailing list