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]

[PATCH 3/3] add typeof and decltype, PR 13206


This adds some support for typeof, decltype, and other spellings
thereof.

Because there is no good way to tell what version of C++ was in use,
or whether GNU extensions were in use, we use "shadowed" keywords for
'typeof' and 'decltype'.  This means that these keywords are disabled
if the user's program defines one of these symbols.

The "__" forms, like "__typeof", are always available.

This patch doesn't implement support for typeof in all places.  In
particular it doesn't work as argument types in casts to function type
-- (void (*)(typeof(x))) &func.  I consider this obscure enough not to
worry about, at least for the time being.

Built and regtested on x86-64 Fedora 16.

	PR exp/13206:
	* ax-gdb.c (gen_expr) <OP_TYPEOF, OP_DECLTYPE>: New cases.
	* breakpoint.c (watchpoint_exp_is_const) <OP_TYPEOF,
	OP_DECLTYPE>: New cases.
	* c-exp.y (TYPEOF, DECLTYPE): New tokens.
	(type_exp): Add new productions.
	(ident_tokens): Add __typeof__, typeof, __typeof, __decltype,
	and decltype.
	* eval.c (evaluate_subexp_standard) <OP_TYPEOF, OP_DECLTYPE>:
	New case.
	* expprint.c (dump_subexp_body_standard) <OP_TYPEOF,
	OP_DECLTYPE>: New case.
	* parse.c (operator_length_standard) <OP_TYPEOF, OP_DECLTYPE>:
	New case.
	* std-operator.def (OP_TYPEOF, OP_DECLTYPE): New constants.
	* varobj.c (varobj_create): Handle OP_TYPEOF, OP_DECLTYPE.

	* gdb.cp/casts.exp: Add tests for typeof and decltype.
	* gdb.cp/casts.cc (decltype): New function.
	(main): Use it.
---
 gdb/ax-gdb.c                   |    2 ++
 gdb/breakpoint.c               |    2 ++
 gdb/c-exp.y                    |   24 +++++++++++++++++++++++-
 gdb/eval.c                     |   39 +++++++++++++++++++++++++++++++++++++++
 gdb/expprint.c                 |    6 ++++++
 gdb/parse.c                    |    2 ++
 gdb/std-operator.def           |    9 +++++++++
 gdb/testsuite/gdb.cp/casts.cc  |   10 ++++++++++
 gdb/testsuite/gdb.cp/casts.exp |   19 +++++++++++++++++++
 gdb/varobj.c                   |    4 +++-
 10 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 2db56bf..f2c5155 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2255,6 +2255,8 @@ gen_expr (struct expression *exp, union exp_element **pc,
       break;
 
     case OP_TYPE:
+    case OP_TYPEOF:
+    case OP_DECLTYPE:
       error (_("Attempt to use a type name as an expression."));
 
     default:
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 72eb673..af977a8 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -10154,6 +10154,8 @@ watchpoint_exp_is_const (const struct expression *exp)
 	case OP_BITSTRING:
 	case OP_ARRAY:
 	case OP_TYPE:
+	case OP_TYPEOF:
+	case OP_DECLTYPE:
 	case OP_NAME:
 	case OP_OBJC_NSSTRING:
 
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index e721995..174a38c 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -219,6 +219,8 @@ static void check_parameter_typelist (VEC (type_ptr) *);
 %type <sval> operator
 %token REINTERPRET_CAST DYNAMIC_CAST STATIC_CAST CONST_CAST
 %token ENTRY
+%token TYPEOF
+%token DECLTYPE
 
 /* Special type cases, put in to allow the parser to distinguish different
    legal basetypes.  */
@@ -268,6 +270,20 @@ type_exp:	type
 			{ write_exp_elt_opcode(OP_TYPE);
 			  write_exp_elt_type($1);
 			  write_exp_elt_opcode(OP_TYPE);}
+	|	TYPEOF '(' exp ')'
+			{
+			  write_exp_elt_opcode (OP_TYPEOF);
+			}
+	|	TYPEOF '(' type ')'
+			{
+			  write_exp_elt_opcode (OP_TYPE);
+			  write_exp_elt_type ($3);
+			  write_exp_elt_opcode (OP_TYPE);
+			}
+	|	DECLTYPE '(' exp ')'
+			{
+			  write_exp_elt_opcode (OP_DECLTYPE);
+			}
 	;
 
 /* Expressions, including the comma operator.  */
@@ -2059,7 +2075,13 @@ static const struct token ident_tokens[] =
     {"const_cast", CONST_CAST, OP_NULL, FLAG_CXX },
     {"dynamic_cast", DYNAMIC_CAST, OP_NULL, FLAG_CXX },
     {"static_cast", STATIC_CAST, OP_NULL, FLAG_CXX },
-    {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, FLAG_CXX }
+    {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, FLAG_CXX },
+
+    {"__typeof__", TYPEOF, OP_TYPEOF, 0 },
+    {"__typeof", TYPEOF, OP_TYPEOF, 0 },
+    {"typeof", TYPEOF, OP_TYPEOF, FLAG_SHADOW },
+    {"__decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX },
+    {"decltype", DECLTYPE, OP_DECLTYPE, FLAG_CXX | FLAG_SHADOW }
   };
 
 /* When we find that lexptr (the global var defined in parse.c) is
diff --git a/gdb/eval.c b/gdb/eval.c
index a012873..4253820 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2900,6 +2900,45 @@ evaluate_subexp_standard (struct type *expect_type,
       else
         error (_("Attempt to use a type name as an expression"));
 
+    case OP_TYPEOF:
+    case OP_DECLTYPE:
+      if (noside == EVAL_SKIP)
+	{
+	  evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+	  goto nosideret;
+	}
+      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	{
+	  enum exp_opcode sub_op = exp->elts[*pos].opcode;
+	  struct value *result;
+
+	  result = evaluate_subexp (NULL_TYPE, exp, pos,
+				    EVAL_AVOID_SIDE_EFFECTS);
+
+	  /* 'decltype' has special semantics for lvalues.  */
+	  if (op == OP_DECLTYPE
+	      && (sub_op == BINOP_SUBSCRIPT
+		  || sub_op == STRUCTOP_MEMBER
+		  || sub_op == STRUCTOP_MPTR
+		  || sub_op == UNOP_IND
+		  || sub_op == STRUCTOP_STRUCT
+		  || sub_op == STRUCTOP_PTR
+		  || sub_op == OP_SCOPE))
+	    {
+	      struct type *type = value_type (result);
+
+	      if (TYPE_CODE (check_typedef (type)) != TYPE_CODE_REF)
+		{
+		  type = lookup_reference_type (type);
+		  result = allocate_value (type);
+		}
+	    }
+
+	  return result;
+	}
+      else
+        error (_("Attempt to use a type as an expression"));
+
     default:
       /* Removing this case and compiling with gcc -Wall reveals that
          a lot of cases are hitting this case.  Some of these should
diff --git a/gdb/expprint.c b/gdb/expprint.c
index c3f6697..945389c 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -971,6 +971,12 @@ dump_subexp_body_standard (struct expression *exp,
       fprintf_filtered (stream, ")");
       elt += 2;
       break;
+    case OP_TYPEOF:
+    case OP_DECLTYPE:
+      fprintf_filtered (stream, "Typeof (");
+      elt = dump_subexp (exp, stream, elt);
+      fprintf_filtered (stream, ")");
+      break;
     case STRUCTOP_STRUCT:
     case STRUCTOP_PTR:
       {
diff --git a/gdb/parse.c b/gdb/parse.c
index 1f9addf..269d8fc 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -938,6 +938,8 @@ operator_length_standard (const struct expression *expr, int endpos,
     case UNOP_ODD:
     case UNOP_ORD:
     case UNOP_TRUNC:
+    case OP_TYPEOF:
+    case OP_DECLTYPE:
       oplen = 1;
       args = 1;
       break;
diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index 9c6a01b..b013687 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -332,3 +332,12 @@ OP (OP_DECFLOAT)
 /* OP_ADL_FUNC specifies that the function is to be looked up in an
    Argument Dependent manner (Koenig lookup).  */
 OP (OP_ADL_FUNC)
+
+/* The typeof operator.  This has one expression argument, which is
+   evaluated solely for its type.  */
+OP (OP_TYPEOF)
+
+/* The decltype operator.  This has one expression argument, which is
+   evaluated solely for its type.  This is similar to typeof, but has
+   slight different semantics.  */
+OP (OP_DECLTYPE)
diff --git a/gdb/testsuite/gdb.cp/casts.cc b/gdb/testsuite/gdb.cp/casts.cc
index 543db89..43f112f 100644
--- a/gdb/testsuite/gdb.cp/casts.cc
+++ b/gdb/testsuite/gdb.cp/casts.cc
@@ -34,6 +34,14 @@ struct DoublyDerived : public VirtuallyDerived,
 {
 };
 
+// Confuse a simpler approach.
+
+double
+decltype(int x)
+{
+  return x + 2.0;
+}
+
 int
 main (int argc, char **argv)
 {
@@ -48,5 +56,7 @@ main (int argc, char **argv)
   Alpha *ad = &derived;
   Alpha *add = &doublyderived;
 
+  double y = decltype(2);
+
   return 0;  /* breakpoint spot: casts.exp: 1 */
 }
diff --git a/gdb/testsuite/gdb.cp/casts.exp b/gdb/testsuite/gdb.cp/casts.exp
index 2013ab8..a3fe743 100644
--- a/gdb/testsuite/gdb.cp/casts.exp
+++ b/gdb/testsuite/gdb.cp/casts.exp
@@ -107,6 +107,25 @@ gdb_test "print reinterpret_cast<void> (b)" "Invalid reinterpret_cast" \
 gdb_test "print reinterpret_cast<A &> (*b)" " = \\(A \\&\\) @$hex: {a = 42}" \
     "reinterpret_cast to reference type"
 
+# Test that keyword shadowing works.
+
+gdb_test "whatis decltype(5)" " = double"
+
+# Basic tests using typeof.
+
+foreach opname {__typeof__ __typeof __decltype} {
+    gdb_test "print (${opname}(a)) (b)" " = \\(A \\*\\) $hex" \
+	"old-style cast using $opname"
+
+    gdb_test "print static_cast<${opname}(a)> (b)" " = \\(A \\*\\) $hex" \
+	"static_cast using $opname"
+
+    gdb_test "print reinterpret_cast<${opname}(a)> (b)" " = \\(A \\*\\) $hex" \
+	"reinterpret_cast using $opname"
+}
+
+gdb_test "whatis __decltype(*a)" "type = A \\&"
+
 # Tests of dynamic_cast.
 
 set nonzero_hex "0x\[0-9A-Fa-f\]\[0-9A-Fa-f\]+"
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 42e2ce4..99b158e 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -675,7 +675,9 @@ varobj_create (char *objname,
 	}
 
       /* Don't allow variables to be created for types.  */
-      if (var->root->exp->elts[0].opcode == OP_TYPE)
+      if (var->root->exp->elts[0].opcode == OP_TYPE
+	  || var->root->exp->elts[0].opcode == OP_TYPEOF
+	  || var->root->exp->elts[0].opcode == OP_DECLTYPE)
 	{
 	  do_cleanups (old_chain);
 	  fprintf_unfiltered (gdb_stderr, "Attempt to use a type name"
-- 
1.7.7.6


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