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 2/2] add typeof and decltype, PR 13206


I'd appreciate some comments on this patch.

This adds some support for typeof, decltype, and __typeof__.

The decltype support is not perfect since we don't look to see whether
the argument is an lvalue; and so we don't ever use a reference type.

We also unconditionally recognize decltype for C++ -- but if the user
is not using C++11, this is wrong.  There's no decent way to determine
if the user compiled with a C++11 compiler; this is a DWARF
deficiency.  I'm going to file a DWARF bug report.

Likewise we unconditionally allow the "typeof" keyword for C.  I may
change this to first see if a symbol named "typeof" is available --
comments?  (There's likewise no way to tell if the CU was compiled in
GNU C mode.)

One final flaw in this patch is that it 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>: New case.
	* breakpoint.c (watchpoint_exp_is_const) <OP_TYPEOF>: New case.
	* c-exp.y (TYPEOF, DECLTYPE): New tokens.
	(type_exp): Add new productions.
	(ident_tokens): Add __typeof__, typeof, and decltype.
	* eval.c (evaluate_subexp_standard) <OP_TYPEOF>: New case.
	* expprint.c (dump_subexp_body_standard) <OP_TYPEOF>: New case.
	* parse.c (operator_length_standard) <OP_TYPEOF>: New case.
	* std-operator.def (OP_TYPEOF): New constant.
	* varobj.c (varobj_create): Handle OP_TYPEOF.

	* gdb.cp/casts.exp: Add tests for typeof, __typeof__, and decltype.
---
 gdb/ax-gdb.c                   |    1 +
 gdb/breakpoint.c               |    1 +
 gdb/c-exp.y                    |   22 +++++++++++++++++++++-
 gdb/eval.c                     |   11 +++++++++++
 gdb/expprint.c                 |    5 +++++
 gdb/parse.c                    |    1 +
 gdb/std-operator.def           |    4 ++++
 gdb/testsuite/gdb.cp/casts.exp |   13 +++++++++++++
 gdb/varobj.c                   |    3 ++-
 9 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 8f14a94..7db5c30 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2251,6 +2251,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
       break;
 
     case OP_TYPE:
+    case OP_TYPEOF:
       error (_("Attempt to use a type name as an expression."));
 
     default:
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index df6b598..8cab9f9 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -9932,6 +9932,7 @@ watchpoint_exp_is_const (const struct expression *exp)
 	case OP_BITSTRING:
 	case OP_ARRAY:
 	case OP_TYPE:
+	case OP_TYPEOF:
 	case OP_NAME:
 	case OP_OBJC_NSSTRING:
 
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index c4a050d..d963a3f 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -215,6 +215,8 @@ static struct stoken operator_stoken (const char *);
 %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.  */
@@ -262,6 +264,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_TYPEOF);
+			}
 	;
 
 /* Expressions, including the comma operator.  */
@@ -1968,7 +1984,11 @@ static const struct token ident_tokens[] =
     {"const_cast", CONST_CAST, OP_NULL, 1 },
     {"dynamic_cast", DYNAMIC_CAST, OP_NULL, 1 },
     {"static_cast", STATIC_CAST, OP_NULL, 1 },
-    {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, 1 }
+    {"reinterpret_cast", REINTERPRET_CAST, OP_NULL, 1 },
+
+    {"__typeof__", TYPEOF, OP_TYPEOF, 0 },
+    {"typeof", TYPEOF, OP_TYPEOF, 0 },
+    {"decltype", DECLTYPE, OP_TYPEOF, 1 }
   };
 
 /* When we find that lexptr (the global var defined in parse.c) is
diff --git a/gdb/eval.c b/gdb/eval.c
index 11c5290..5d4db9c 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2883,6 +2883,17 @@ evaluate_subexp_standard (struct type *expect_type,
       else
         error (_("Attempt to use a type name as an expression"));
 
+    case OP_TYPEOF:
+      if (noside == EVAL_SKIP)
+	{
+	  evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+	  goto nosideret;
+	}
+      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	return evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      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..fa89cd8 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -971,6 +971,11 @@ dump_subexp_body_standard (struct expression *exp,
       fprintf_filtered (stream, ")");
       elt += 2;
       break;
+    case OP_TYPEOF:
+      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 a600994..baa323e 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -939,6 +939,7 @@ operator_length_standard (const struct expression *expr, int endpos,
     case UNOP_ODD:
     case UNOP_ORD:
     case UNOP_TRUNC:
+    case OP_TYPEOF:
       oplen = 1;
       args = 1;
       break;
diff --git a/gdb/std-operator.def b/gdb/std-operator.def
index 9c6a01b..dc1819f 100644
--- a/gdb/std-operator.def
+++ b/gdb/std-operator.def
@@ -332,3 +332,7 @@ 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)
+
+/* typeof and decltype.  This has one expression argument, which is
+   evaluated solely for its type.  */
+OP (OP_TYPEOF)
diff --git a/gdb/testsuite/gdb.cp/casts.exp b/gdb/testsuite/gdb.cp/casts.exp
index 0856ba5..add82e9 100644
--- a/gdb/testsuite/gdb.cp/casts.exp
+++ b/gdb/testsuite/gdb.cp/casts.exp
@@ -116,6 +116,19 @@ 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"
 
+# 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"
+}
+
 # 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..94662b3e 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -675,7 +675,8 @@ 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)
 	{
 	  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]