While attempting to write some code that uses the new x86 named address space
support in gcc 6, I found that __typeof is very unhelpful. In particular, given
int __seg_fs *ptr;
__typeof(*ptr) obj;
OBJ will not be type "int", but "int __seg_fs". Which means that you can't use
it to create temporaries within statement expressions.
In the process of writing this, I found a hack in __typeof added just to
support _Atomic. Which suggests that one of these variants would be more
generally helpful than the hack.
I add __typeof_noas and __typeof_noqual. The first strips only the address
space, leaving 'const' and 'volatile' (and, I suppose 'restrict'). The second
strips all qualifiers, essentially yielding the TYPE_MAIN_VARIANT.
Thoughts?
r~
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 378afae..4972fe1 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -509,6 +509,10 @@ const struct c_common_resword c_common_reswords[] =
{ "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
{ "__typeof", RID_TYPEOF, 0 },
{ "__typeof__", RID_TYPEOF, 0 },
+ { "__typeof_noas", RID_TYPEOF_NOAS, 0 },
+ { "__typeof_noas__", RID_TYPEOF_NOAS, 0 },
+ { "__typeof_noqual", RID_TYPEOF_NOQUAL, 0 },
+ { "__typeof_noqual__", RID_TYPEOF_NOQUAL, 0 },
{ "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
{ "__volatile", RID_VOLATILE, 0 },
{ "__volatile__", RID_VOLATILE, 0 },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index fa3746c..6c6c2b1 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -100,9 +100,10 @@ enum rid
/* C extensions */
RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
- RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX,
RID_BUILTIN_SHUFFLE,
- RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
+ RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX,
+ RID_BUILTIN_SHUFFLE, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
+ RID_TYPEOF_NOAS, RID_TYPEOF_NOQUAL,
/* C11 */
RID_ALIGNAS, RID_GENERIC,
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index eede3a7..199a39f 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -561,6 +561,8 @@ c_token_starts_typename (c_token *token)
case RID_STRUCT:
case RID_UNION:
case RID_TYPEOF:
+ case RID_TYPEOF_NOAS:
+ case RID_TYPEOF_NOQUAL:
case RID_CONST:
case RID_ATOMIC:
case RID_VOLATILE:
@@ -722,6 +724,8 @@ c_token_starts_declspecs (c_token *token)
case RID_STRUCT:
case RID_UNION:
case RID_TYPEOF:
+ case RID_TYPEOF_NOAS:
+ case RID_TYPEOF_NOQUAL:
case RID_CONST:
case RID_VOLATILE:
case RID_RESTRICT:
@@ -2530,6 +2534,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs
*specs,
declspecs_add_type (loc, specs, t);
break;
case RID_TYPEOF:
+ case RID_TYPEOF_NOAS:
+ case RID_TYPEOF_NOQUAL:
/* ??? The old parser rejected typeof after other type
specifiers, but is a syntax error the best way of
handling this? */
@@ -3179,7 +3185,12 @@ c_parser_typeof_specifier (c_parser *parser)
ret.spec = error_mark_node;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+
+ enum rid keyword = c_parser_peek_token (parser)->keyword;
+ gcc_assert (keyword == RID_TYPEOF
+ || keyword == RID_TYPEOF_NOAS
+ || keyword == RID_TYPEOF_NOQUAL);
+
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
in_typeof++;
@@ -3221,9 +3232,19 @@ c_parser_typeof_specifier (c_parser *parser)
/* For use in macros such as those in <stdatomic.h>, remove all
qualifiers from atomic types. (const can be an issue for more macros
using typeof than just the <stdatomic.h> ones.) */
- if (ret.spec != error_mark_node && TYPE_ATOMIC (ret.spec))
- ret.spec = c_build_qualified_type (ret.spec, TYPE_UNQUALIFIED);
+ if (ret.spec != error_mark_node
+ && keyword == RID_TYPEOF
+ && TYPE_ATOMIC (ret.spec))
+ keyword = RID_TYPEOF_NOQUAL;
}
+
+ /* If requested, drop (some) qualifiers. */
+ if (keyword != RID_TYPEOF && ret.spec != error_mark_node)
+ ret.spec = c_build_qualified_type (ret.spec,
+ keyword == RID_TYPEOF_NOQUAL
+ ? TYPE_UNQUALIFIED
+ : TYPE_QUALS_NO_ADDR_SPACE (ret.spec));
+
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
return ret;
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d03b0c9..49bdf4f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -978,6 +978,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer
*lexer)
/* GNU extensions. */
case RID_ATTRIBUTE:
case RID_TYPEOF:
+ case RID_TYPEOF_NOAS:
+ case RID_TYPEOF_NOQUAL:
/* C++0x extensions. */
case RID_DECLTYPE:
case RID_UNDERLYING_TYPE:
@@ -16093,19 +16095,27 @@ cp_parser_simple_type_specifier (cp_parser* parser,
break;
case RID_TYPEOF:
- /* Consume the `typeof' token. */
- cp_lexer_consume_token (parser->lexer);
- /* Parse the operand to `typeof'. */
- type = cp_parser_sizeof_operand (parser, RID_TYPEOF);
- /* If it is not already a TYPE, take its type. */
- if (!TYPE_P (type))
- type = finish_typeof (type);
-
- if (decl_specs)
- cp_parser_set_decl_spec_type (decl_specs, type,
- token,
- /*type_definition_p=*/false);
-
+ case RID_TYPEOF_NOAS:
+ case RID_TYPEOF_NOQUAL:
+ {
+ enum rid keyword = token->keyword;
+ /* Consume the `typeof' token. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Parse the operand to `typeof'. */
+ type = cp_parser_sizeof_operand (parser, keyword);
+ /* If it is not already a TYPE, take its type. */
+ if (!TYPE_P (type))
+ type = finish_typeof (type);
+ /* If requested, make the type unqualified. */
+ if (keyword != RID_TYPEOF && type != error_mark_node)
+ type = build_qualified_type (type,
+ keyword == RID_TYPEOF_NOQUAL
+ ? TYPE_UNQUALIFIED
+ : TYPE_QUALS_NO_ADDR_SPACE (type));
+ if (decl_specs)
+ cp_parser_set_decl_spec_type (decl_specs, type, token,
+ /*type_definition_p=*/false);
+ }
return type;
case RID_UNDERLYING_TYPE:
diff --git a/gcc/testsuite/c-c++-common/typeof-noqual-1.c
b/gcc/testsuite/c-c++-common/typeof-noqual-1.c
new file mode 100644
index 0000000..e4af7fb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/typeof-noqual-1.c
@@ -0,0 +1,28 @@
+/* { dg-do "compile" } */
+
+void foo(void)
+{
+ int i = 0;
+ const int ci = 0;
+ volatile int vi = 0;
+
+ __typeof(i) *ip = 0;
+ __typeof(ci) *cip = 0;
+ __typeof(vi) *vip = 0;
+
+ __typeof_noqual(i) *nip = 0;
+ __typeof_noqual(ci) *ncip = 0;
+ __typeof_noqual(vi) *nvip = 0;
+
+ ip = cip; /* { dg-warning "assignment discards" } */
+ ip = vip; /* { dg-warning "assignment discards" } */
+
+ ip = nip;
+ ip = ncip;
+ ip = nvip;
+
+ ncip = cip; /* { dg-warning "assignment discards" } */
+ nvip = vip; /* { dg-warning "assignment discards" } */
+
+ nip = ip;
+}
diff --git a/gcc/testsuite/gcc.target/i386/typeof-nq-seg-1.c
b/gcc/testsuite/gcc.target/i386/typeof-nq-seg-1.c
new file mode 100644
index 0000000..b7decb7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/typeof-nq-seg-1.c
@@ -0,0 +1,37 @@
+/* { dg-do "compile" } */
+/* { dg-options "" } */
+
+int *ip;
+int __seg_fs *fp;
+int __seg_gs *gp;
+
+void foo()
+{
+ __typeof(*fp) *fip = 0;
+ __typeof(*gp) *gip = 0;
+
+ __typeof_noqual(*fp) *qfip = 0;
+ __typeof_noqual(*gp) *qgip = 0;
+
+ __typeof_noas(*fp) *afip = 0;
+ __typeof_noas(*gp) *agip = 0;
+
+ ip = fp; /* { dg-error "address space" } */
+ ip = gp; /* { dg-error "address space" } */
+ ip = fip; /* { dg-error "address space" } */
+ ip = gip; /* { dg-error "address space" } */
+ ip = qfip;
+ ip = qgip;
+ ip = afip;
+ ip = agip;
+
+ fp = ip; /* { dg-error "address space" } */
+ fp = gp; /* { dg-error "address space" } */
+ fp = fip;
+ fp = qfip; /* { dg-error "address space" } */
+ fp = afip; /* { dg-error "address space" } */
+
+ gp = gip;
+ gp = qgip; /* { dg-error "address space" } */
+ gp = agip; /* { dg-error "address space" } */
+}
diff --git a/gcc/testsuite/gcc.target/i386/typeof-nq-seg-2.c
b/gcc/testsuite/gcc.target/i386/typeof-nq-seg-2.c
new file mode 100644
index 0000000..74e9e3e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/typeof-nq-seg-2.c
@@ -0,0 +1,46 @@
+/* { dg-do "compile" } */
+/* { dg-options "" } */
+
+int *ip;
+int __seg_fs *fp;
+int __seg_gs *gp;
+
+const int *cip;
+const int __seg_fs *cfp;
+const int __seg_gs *cgp;
+
+volatile int *vip;
+volatile int __seg_fs *vfp;
+volatile int __seg_gs *vgp;
+
+void foo()
+{
+ __typeof_noqual(*cfp) *qcfp = 0;
+ __typeof_noqual(*cgp) *qcgp = 0;
+ __typeof_noqual(*vfp) *qvfp = 0;
+ __typeof_noqual(*vgp) *qvgp = 0;
+
+ __typeof_noas(*cfp) *acfp = 0;
+ __typeof_noas(*cgp) *acgp = 0;
+ __typeof_noas(*vfp) *avfp = 0;
+ __typeof_noas(*vgp) *avgp = 0;
+
+ ip = qcfp;
+ ip = qcgp;
+ ip = qvfp;
+ ip = qvgp;
+ ip = acfp; /* { dg-warning "assignment discards" } */
+ ip = acgp; /* { dg-warning "assignment discards" } */
+ ip = avfp; /* { dg-warning "assignment discards" } */
+ ip = avgp; /* { dg-warning "assignment discards" } */
+
+ cip = acfp;
+ cip = acgp;
+ cip = avfp; /* { dg-warning "assignment discards" } */
+ cip = avgp; /* { dg-warning "assignment discards" } */
+
+ vip = acfp; /* { dg-warning "assignment discards" } */
+ vip = acgp; /* { dg-warning "assignment discards" } */
+ vip = avfp;
+ vip = avgp;
+}