This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 2/2] add typeof and decltype, PR 13206
- From: Tom Tromey <tromey at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Thu, 28 Jun 2012 14:03:25 -0600
- Subject: [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