This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB 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]

FYI: fix PR c++/7173


I'm checking this in.

PR C++/7173 concerns ambiguous base classes.  Currently, gdb does not
properly diagnose ambiguous references, but it should, so that users
don't silently see the wrong value.

This patch fixes the bug.

Built and regtested on x86-64 Fedora 16.

Tom

2012-05-21  Tom Tromey  <tromey@redhat.com>

	PR c++/7173:
	* gnu-v3-abi.c (gnuv3_baseclass_offset): Return early for Java
	types.
	* value.h (value_cast_pointers): Update.
	* valops.c (value_cast_pointers): Add 'subclass_check' argument.
	(value_cast): Update.
	(update_search_result): New function.
	(do_search_struct_field): New, from search_struct_field.  Check
	for ambiguous results.
	(search_struct_field): Rewrite.
	* infcall.c (value_arg_coerce): Update.
	* eval.c (evaluate_subexp_standard) <STRUCTOP_MEMBER>: Use
	value_cast_pointers.
	* ada-lang.c (ada_convert_actual): Update.

2012-05-21  Tom Tromey  <tromey@redhat.com>

	* gdb.cp/inherit.exp (test_print_mi_members): Expect errors.
	Remove kfails.
	(test_print_mi_member_types): Likewise.

Index: ada-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/ada-lang.c,v
retrieving revision 1.368
diff -u -r1.368 ada-lang.c
--- ada-lang.c	18 May 2012 21:02:46 -0000	1.368
+++ ada-lang.c	21 May 2012 19:45:54 -0000
@@ -4139,7 +4139,7 @@
         }
       else
 	return actual;
-      return value_cast_pointers (formal_type, result);
+      return value_cast_pointers (formal_type, result, 0);
     }
   else if (TYPE_CODE (actual_type) == TYPE_CODE_PTR)
     return ada_value_ind (actual);
Index: eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.161
diff -u -r1.161 eval.c
--- eval.c	18 May 2012 21:02:47 -0000	1.161
+++ eval.c	21 May 2012 19:45:54 -0000
@@ -2047,8 +2047,8 @@
 
 	case TYPE_CODE_MEMBERPTR:
 	  /* Now, convert these values to an address.  */
-	  arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
-			     arg1);
+	  arg1 = value_cast_pointers (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)),
+				      arg1, 1);
 
 	  mem_offset = value_as_long (arg2);
 
Index: gnu-v3-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/gnu-v3-abi.c,v
retrieving revision 1.74
diff -u -r1.74 gnu-v3-abi.c
--- gnu-v3-abi.c	18 May 2012 15:27:25 -0000	1.74
+++ gnu-v3-abi.c	21 May 2012 19:45:54 -0000
@@ -430,8 +430,9 @@
   ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
 
   /* If it isn't a virtual base, this is easy.  The offset is in the
-     type definition.  */
-  if (!BASETYPE_VIA_VIRTUAL (type, index))
+     type definition.  Likewise for Java, which doesn't really have
+     virtual inheritance in the C++ sense.  */
+  if (!BASETYPE_VIA_VIRTUAL (type, index) || TYPE_CPLUS_REALLY_JAVA (type))
     return TYPE_BASECLASS_BITPOS (type, index) / 8;
 
   /* To access a virtual base, we need to use the vbase offset stored in
Index: infcall.c
===================================================================
RCS file: /cvs/src/src/gdb/infcall.c,v
retrieving revision 1.154
diff -u -r1.154 infcall.c
--- infcall.c	16 May 2012 14:35:05 -0000	1.154
+++ infcall.c	21 May 2012 19:45:54 -0000
@@ -159,7 +159,7 @@
 	struct value *new_value;
 
 	if (TYPE_CODE (arg_type) == TYPE_CODE_REF)
-	  return value_cast_pointers (type, arg);
+	  return value_cast_pointers (type, arg, 0);
 
 	/* Cast the value to the reference's target type, and then
 	   convert it back to a reference.  This will issue an error
Index: valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.293
diff -u -r1.293 valops.c
--- valops.c	21 Feb 2012 13:48:59 -0000	1.293
+++ valops.c	21 May 2012 19:45:54 -0000
@@ -301,10 +301,14 @@
 
 /* Cast one pointer or reference type to another.  Both TYPE and
    the type of ARG2 should be pointer types, or else both should be
-   reference types.  Returns the new pointer or reference.  */
+   reference types.  If SUBCLASS_CHECK is non-zero, this will force a
+   check to see whether TYPE is a superclass of ARG2's type.  If
+   SUBCLASS_CHECK is zero, then the subclass check is done only when
+   ARG2 is itself non-zero.  Returns the new pointer or reference.  */
 
 struct value *
-value_cast_pointers (struct type *type, struct value *arg2)
+value_cast_pointers (struct type *type, struct value *arg2,
+		     int subclass_check)
 {
   struct type *type1 = check_typedef (type);
   struct type *type2 = check_typedef (value_type (arg2));
@@ -313,7 +317,7 @@
 
   if (TYPE_CODE (t1) == TYPE_CODE_STRUCT
       && TYPE_CODE (t2) == TYPE_CODE_STRUCT
-      && !value_logical_not (arg2))
+      && (subclass_check || !value_logical_not (arg2)))
     {
       struct value *v2;
 
@@ -568,7 +572,7 @@
   else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2))
     {
       if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
-	return value_cast_pointers (type, arg2);
+	return value_cast_pointers (type, arg2, 0);
 
       arg2 = value_copy (arg2);
       deprecated_set_value_type (arg2, type);
@@ -1976,17 +1980,41 @@
   return i + 1;
 }
 
-/* Helper function used by value_struct_elt to recurse through
-   baseclasses.  Look for a field NAME in ARG1.  Adjust the address of
-   ARG1 by OFFSET bytes, and search in it assuming it has (class) type
-   TYPE.  If found, return value, else return NULL.
-
-   If LOOKING_FOR_BASECLASS, then instead of looking for struct
-   fields, look for a baseclass named NAME.  */
+/* Helper class for do_search_struct_field that updates *RESULT_PTR
+   and *LAST_BOFFSET, and possibly throws an exception if the field
+   search has yielded ambiguous results.  */
+
+static void
+update_search_result (struct value **result_ptr, struct value *v,
+		      int *last_boffset, int boffset,
+		      const char *name, struct type *type)
+{
+  if (v != NULL)
+    {
+      if (*result_ptr != NULL
+	  /* The result is not ambiguous if all the classes that are
+	     found occupy the same space.  */
+	  && *last_boffset != boffset)
+	error (_("base class '%s' is ambiguous in type '%s'"),
+	       name, TYPE_SAFE_NAME (type));
+      *result_ptr = v;
+      *last_boffset = boffset;
+    }
+}
 
-static struct value *
-search_struct_field (const char *name, struct value *arg1, int offset,
-		     struct type *type, int looking_for_baseclass)
+/* A helper for search_struct_field.  This does all the work; most
+   arguments are as passed to search_struct_field.  The result is
+   stored in *RESULT_PTR, which must be initialized to NULL.
+   OUTERMOST_TYPE is the type of the initial type passed to
+   search_struct_field; this is used for error reporting when the
+   lookup is ambiguous.  */
+
+static void
+do_search_struct_field (const char *name, struct value *arg1, int offset,
+			struct type *type, int looking_for_baseclass,
+			struct value **result_ptr,
+			int *last_boffset,
+			struct type *outermost_type)
 {
   int i;
   int nbases;
@@ -2012,12 +2040,9 @@
 			 name);
 	      }
 	    else
-	      {
-		v = value_primitive_field (arg1, offset, i, type);
-		if (v == 0)
-		  error (_("there is no field named %s"), name);
-	      }
-	    return v;
+	      v = value_primitive_field (arg1, offset, i, type);
+	    *result_ptr = v;
+	    return;
 	  }
 
 	if (t_field_name
@@ -2042,7 +2067,7 @@
 		   represented as a struct, with a member for each
 		   <variant field>.  */
 
-		struct value *v;
+		struct value *v = NULL;
 		int new_offset = offset;
 
 		/* This is pretty gross.  In G++, the offset in an
@@ -2056,18 +2081,23 @@
 			&& TYPE_FIELD_BITPOS (field_type, 0) == 0))
 		  new_offset += TYPE_FIELD_BITPOS (type, i) / 8;
 
-		v = search_struct_field (name, arg1, new_offset, 
-					 field_type,
-					 looking_for_baseclass);
+		do_search_struct_field (name, arg1, new_offset, 
+					field_type,
+					looking_for_baseclass, &v,
+					last_boffset,
+					outermost_type);
 		if (v)
-		  return v;
+		  {
+		    *result_ptr = v;
+		    return;
+		  }
 	      }
 	  }
       }
 
   for (i = 0; i < nbases; i++)
     {
-      struct value *v;
+      struct value *v = NULL;
       struct type *basetype = check_typedef (TYPE_BASECLASS (type, i));
       /* If we are looking for baseclasses, this is what we get when
          we hit them.  But it could happen that the base part's member
@@ -2077,10 +2107,10 @@
 			     && (strcmp_iw (name, 
 					    TYPE_BASECLASS_NAME (type, 
 								 i)) == 0));
+      int boffset = value_embedded_offset (arg1) + offset;
 
       if (BASETYPE_VIA_VIRTUAL (type, i))
 	{
-	  int boffset;
 	  struct value *v2;
 
 	  boffset = baseclass_offset (type, i,
@@ -2116,22 +2146,51 @@
 	    }
 
 	  if (found_baseclass)
-	    return v2;
-	  v = search_struct_field (name, v2, 0,
-				   TYPE_BASECLASS (type, i),
-				   looking_for_baseclass);
+	    v = v2;
+	  else
+	    {
+	      do_search_struct_field (name, v2, 0,
+				      TYPE_BASECLASS (type, i),
+				      looking_for_baseclass,
+				      result_ptr, last_boffset,
+				      outermost_type);
+	    }
 	}
       else if (found_baseclass)
 	v = value_primitive_field (arg1, offset, i, type);
       else
-	v = search_struct_field (name, arg1,
-				 offset + TYPE_BASECLASS_BITPOS (type, 
-								 i) / 8,
-				 basetype, looking_for_baseclass);
-      if (v)
-	return v;
+	{
+	  do_search_struct_field (name, arg1,
+				  offset + TYPE_BASECLASS_BITPOS (type, 
+								  i) / 8,
+				  basetype, looking_for_baseclass,
+				  result_ptr, last_boffset,
+				  outermost_type);
+	}
+
+      update_search_result (result_ptr, v, last_boffset,
+			    boffset, name, outermost_type);
     }
-  return NULL;
+}
+
+/* Helper function used by value_struct_elt to recurse through
+   baseclasses.  Look for a field NAME in ARG1.  Adjust the address of
+   ARG1 by OFFSET bytes, and search in it assuming it has (class) type
+   TYPE.  If found, return value, else return NULL.
+
+   If LOOKING_FOR_BASECLASS, then instead of looking for struct
+   fields, look for a baseclass named NAME.  */
+
+static struct value *
+search_struct_field (const char *name, struct value *arg1, int offset,
+		     struct type *type, int looking_for_baseclass)
+{
+  struct value *result = NULL;
+  int boffset = 0;
+
+  do_search_struct_field (name, arg1, offset, type, looking_for_baseclass,
+			  &result, &boffset, type);
+  return result;
 }
 
 /* Helper function used by value_struct_elt to recurse through
Index: value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.205
diff -u -r1.205 value.h
--- value.h	18 May 2012 15:31:40 -0000	1.205
+++ value.h	21 May 2012 19:45:54 -0000
@@ -669,7 +669,7 @@
 extern struct value *value_full_object (struct value *, struct type *, int,
 					int, int);
 
-extern struct value *value_cast_pointers (struct type *, struct value *);
+extern struct value *value_cast_pointers (struct type *, struct value *, int);
 
 extern struct value *value_cast (struct type *type, struct value *arg2);
 
Index: testsuite/gdb.cp/inherit.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/inherit.exp,v
retrieving revision 1.24
diff -u -r1.24 inherit.exp
--- testsuite/gdb.cp/inherit.exp	15 Mar 2012 15:49:42 -0000	1.24
+++ testsuite/gdb.cp/inherit.exp	21 May 2012 19:45:57 -0000
@@ -321,25 +321,11 @@
 
     # Print all members of g_D.
     #
-    # g_D.A::a and g_D.A::x are ambiguous member accesses, and gdb
-    # should detect these.  There are no ways to PASS these tests
-    # because I don't know what the gdb message will be.  -- chastain
-    # 2004-01-27.
-
-    set name "print g_D.A::a"
-    gdb_test_multiple "print g_D.A::a" $name {
-	-re "$vhn = (15|11)$nl$gdb_prompt $" {
-	    kfail "gdb/68" "print g_D.A::a"
-	}
-    }
-
-    set name "print g_D.A::x"
-    gdb_test_multiple "print g_D.A::x" $name {
-	-re "$vhn = (16|12)$nl$gdb_prompt $" {
-	    kfail "gdb/68" "print g_D.A::x"
-	}
-    }
-
+    # g_D.A::a and g_D.A::x are ambiguous member accesses.
+    gdb_test "print g_D.A::a" "base class 'A' is ambiguous in type 'D'"
+    gdb_test "print g_D.C::a" "$vhn = 15"
+    gdb_test "print g_D.B::a" "$vhn = 11"
+    gdb_test "print g_D.A::x" "base class 'A' is ambiguous in type 'D'"
     gdb_test "print g_D.B::b" "$vhn = 13"
     gdb_test "print g_D.B::x" "$vhn = 14"
     gdb_test "print g_D.C::c" "$vhn = 17"
@@ -350,20 +336,8 @@
     # Print all members of g_E.
     # g_E.A::a and g_E.A::x are ambiguous.
 
-    set name "print g_E.A::a"
-    gdb_test_multiple "print g_E.A::a" $name {
-	-re "$vhn = (21|25)$nl$gdb_prompt $" {
-	    kfail "gdb/68" "print g_E.A::a"
-	}
-    }
-
-    set name "print g_E.A::x"
-    gdb_test_multiple "print g_E.A::x" $name {
-	-re "$vhn = (26|22)$nl$gdb_prompt $" {
-	    kfail "gdb/68" "print g_E.A::x"
-	}
-    }
-
+    gdb_test "print g_E.A::a" "base class 'A' is ambiguous in type 'E'"
+    gdb_test "print g_E.A::x" "base class 'A' is ambiguous in type 'E'"
     gdb_test "print g_E.B::b" "$vhn = 23"
     gdb_test "print g_E.B::x" "$vhn = 24"
     gdb_test "print g_E.C::c" "$vhn = 27"
@@ -406,25 +380,10 @@
 
     # Print all members of g_D.
     #
-    # g_D.A::a and g_D.A::x are ambiguous member accesses, and gdb
-    # should detect these.  There are no ways to PASS these tests
-    # because I don't know what the gdb message will be.  -- chastain
-    # 2004-01-27.
-
-    set name "ptype g_D.A::a"
-    gdb_test_multiple "ptype g_D.A::a" $name {
-	-re "type = int$nl$gdb_prompt $" {
-	    kfail "gdb/68" "ptype g_D.A::a"
-	}
-    }
-
-    set name "ptype g_D.A::x"
-    gdb_test_multiple "ptype g_D.A::x" $name {
-	-re "type = int$nl$gdb_prompt $" {
-	    kfail "gdb/68" "ptype g_D.A::x"
-	}
-    }
+    # g_D.A::a and g_D.A::x are ambiguous member accesses.
 
+    gdb_test "ptype g_D.A::a" "base class 'A' is ambiguous in type 'D'"
+    gdb_test "ptype g_D.A::x" "base class 'A' is ambiguous in type 'D'"
     gdb_test "ptype g_D.B::b" "type = int"
     gdb_test "ptype g_D.B::x" "type = int"
     gdb_test "ptype g_D.C::c" "type = int"
@@ -435,20 +394,8 @@
     # Print all members of g_E.
     # g_E.A::a and g_E.A::x are ambiguous.
 
-    set name "ptype g_E.A::a"
-    gdb_test_multiple "ptype g_E.A::a" $name {
-	-re "type = int$nl$gdb_prompt $" {
-	    kfail "gdb/68" "ptype g_E.A::a"
-	}
-    }
-
-    set name "ptype g_E.A::x"
-    gdb_test_multiple "ptype g_E.A::x" $name {
-	-re "type = int$nl$gdb_prompt $" {
-	    kfail "gdb/68" "ptype g_E.A::x"
-	}
-    }
-
+    gdb_test "ptype g_E.A::a" "base class 'A' is ambiguous in type 'E'"
+    gdb_test "ptype g_E.A::x" "base class 'A' is ambiguous in type 'E'"
     gdb_test "ptype g_E.B::b" "type = int"
     gdb_test "ptype g_E.B::x" "type = int"
     gdb_test "ptype g_E.C::c" "type = int"


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