After a long time, I'm finally sending the revisited patch dealing with these two PRs. To quickly recap, users were looking for a typeof variant that strips type qualifiers. I sent a path adding __typeof_noqual, but a discussion ensued and it's been concluded that we'd rather go a different way, i.e. add __remove_qualifiers, which takes a typename, and strips type qualifiers. That is my understanding anyway. Here's a patch implementing just that, for both C and C++ FEs.
Here's a link to the previous discussion: https://gcc.gnu.org/ml/gcc-patches/2017-07/msg01146.html Bootstrapped/regtested on x86_64-linux, ok for trunk? 2017-08-31 Marek Polacek <pola...@redhat.com> PR c/39985 PR c/65455 * c-common.c (c_common_reswords): Add __remove_qualifiers and __remove_qualifiers__. (keyword_begins_type_specifier): Handle RID_REMOVE_QUALS. * c-common.h (enum rid): Add RID_REMOVE_QUALS. * c-decl.c (start_struct): Also check in_remove_qualifiers. (finish_struct): Likewise. (start_enum): Likewise. (finish_enum): Likewise. * c-parser.c (c_keyword_starts_typename): Handle RID_REMOVE_QUALS. (c_token_starts_declspecs): Likewise. (c_parser_declaration_or_fndef): For __auto_type, remove all type qualifiers. (c_parser_declspecs): Handle RID_REMOVE_QUALS. (c_parser_remove_qualifiers_specifier): New function. (c_parser_objc_selector): Handle RID_REMOVE_QUALS. * c-tree.h (enum c_typespec_kind): Update a comment. Declare in_remove_qualifiers. * c-typeck.c (in_remove_qualifiers): New global variable. (build_external_ref): Also check in_remove_qualifiers. (struct maybe_used_decl): Likewise. (record_maybe_used_decl): Likewise. (pop_maybe_used): Likewise. * parser.c (cp_keyword_starts_decl_specifier_p): Handle RID_REMOVE_QUALS. (cp_parser_simple_type_specifier): Likewise. (cp_parser_sizeof_operand): For __remove_qualifiers, remove all type qualifiers. * doc/extend.texi: Document __remove_qualifiers. * c-c++-common/remove-quals-1.c: New test. * c-c++-common/remove-quals-2.c: New test. * c-c++-common/remove-quals-3.c: New test. * c-c++-common/remove-quals-4.c: New test. * g++.dg/ext/remove-quals-1.C: New test. * g++.dg/ext/remove-quals-2.C: New test. * gcc.dg/auto-type-3.c: New test. * gcc.dg/remove-quals-1.c: New test. * gcc.dg/remove-quals-2.c: New test. diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c index d959dbc25bb..ae92ff440f6 100644 --- gcc/c-family/c-common.c +++ gcc/c-family/c-common.c @@ -423,6 +423,8 @@ const struct c_common_resword c_common_reswords[] = { "__null", RID_NULL, 0 }, { "__real", RID_REALPART, 0 }, { "__real__", RID_REALPART, 0 }, + { "__remove_qualifiers", RID_REMOVE_QUALS, 0 }, + { "__remove_qualifiers__", RID_REMOVE_QUALS, 0 }, { "__restrict", RID_RESTRICT, 0 }, { "__restrict__", RID_RESTRICT, 0 }, { "__signed", RID_SIGNED, 0 }, @@ -7525,6 +7527,7 @@ keyword_begins_type_specifier (enum rid keyword) case RID_CLASS: case RID_UNION: case RID_ENUM: + case RID_REMOVE_QUALS: return true; default: if (keyword >= RID_FIRST_INT_N diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h index 8e367680600..e726aa8844b 100644 --- gcc/c-family/c-common.h +++ gcc/c-family/c-common.h @@ -101,7 +101,7 @@ enum rid 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_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, RID_REMOVE_QUALS, /* TS 18661-3 keywords, in the same sequence as the TI_* values. */ RID_FLOAT16, diff --git gcc/c/c-decl.c gcc/c/c-decl.c index d526f0e88e4..b9cd5f8cf56 100644 --- gcc/c/c-decl.c +++ gcc/c/c-decl.c @@ -7516,12 +7516,14 @@ start_struct (location_t loc, enum tree_code code, tree name, within a statement expr used within sizeof, et. al. This is not terribly serious as C++ doesn't permit statement exprs within sizeof anyhow. */ - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof + || in_remove_qualifiers)) warning_at (loc, OPT_Wc___compat, "defining type in %qs expression is invalid in C++", - (in_sizeof - ? "sizeof" - : (in_typeof ? "typeof" : "alignof"))); + (in_sizeof ? "sizeof" + : (in_typeof ? "typeof" + : (in_alignof ? "alignof" + : "__remove_qualifiers")))); return ref; } @@ -8159,7 +8161,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, struct_types. */ if (warn_cxx_compat && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) + && !in_sizeof && !in_typeof && !in_alignof && !in_remove_qualifiers) struct_parse_info->struct_types.safe_push (t); return t; @@ -8235,12 +8237,14 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) /* FIXME: This will issue a warning for a use of a type defined within sizeof in a statement expr. This is not terribly serious as C++ doesn't permit statement exprs within sizeof anyhow. */ - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof + || in_remove_qualifiers)) warning_at (loc, OPT_Wc___compat, "defining type in %qs expression is invalid in C++", - (in_sizeof - ? "sizeof" - : (in_typeof ? "typeof" : "alignof"))); + (in_sizeof ? "sizeof" + : (in_typeof ? "typeof" + : (in_alignof ? "alignof" + : "__remove_qualifiers")))); return enumtype; } @@ -8395,7 +8399,7 @@ finish_enum (tree enumtype, tree values, tree attributes) struct_types. */ if (warn_cxx_compat && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) + && !in_sizeof && !in_typeof && !in_alignof && !in_remove_qualifiers) struct_parse_info->struct_types.safe_push (enumtype); return enumtype; diff --git gcc/c/c-parser.c gcc/c/c-parser.c index 3d15eb7a6de..048574b0139 100644 --- gcc/c/c-parser.c +++ gcc/c/c-parser.c @@ -504,6 +504,7 @@ c_keyword_starts_typename (enum rid keyword) case RID_ACCUM: case RID_SAT: case RID_AUTO_TYPE: + case RID_REMOVE_QUALS: return true; default: if (keyword >= RID_FIRST_INT_N @@ -681,6 +682,7 @@ c_token_starts_declspecs (c_token *token) case RID_ALIGNAS: case RID_ATOMIC: case RID_AUTO_TYPE: + case RID_REMOVE_QUALS: return true; default: if (token->keyword >= RID_FIRST_INT_N @@ -1361,6 +1363,7 @@ static struct c_typespec c_parser_enum_specifier (c_parser *); static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); static tree c_parser_struct_declaration (c_parser *); static struct c_typespec c_parser_typeof_specifier (c_parser *); +static struct c_typespec c_parser_remove_qualifiers_specifier (c_parser *); static tree c_parser_alignas_specifier (c_parser *); static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, c_dtr_syn, bool *); @@ -2039,8 +2042,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, " initializer"); init = convert_lvalue_to_rvalue (init_loc, init, true, true); tree init_type = TREE_TYPE (init.value); - /* As with typeof, remove all qualifiers from atomic types. */ - if (init_type != error_mark_node && TYPE_ATOMIC (init_type)) + /* Remove all qualifiers from all types. */ + if (init_type != error_mark_node) init_type = c_build_qualified_type (init_type, TYPE_UNQUALIFIED); bool vm_type = variably_modified_type_p (init_type, @@ -2732,6 +2735,14 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, t = c_parser_typeof_specifier (parser); declspecs_add_type (loc, specs, t); break; + case RID_REMOVE_QUALS: + if (!typespec_ok) + goto out; + attrs_ok = true; + seen_type = true; + t = c_parser_remove_qualifiers_specifier (parser); + declspecs_add_type (loc, specs, t); + break; case RID_ATOMIC: /* C parser handling of Objective-C constructs needs checking for correct lvalue-to-rvalue conversions, and @@ -3435,6 +3446,55 @@ c_parser_typeof_specifier (c_parser *parser) return ret; } +/* Parse a __remove_qualifiers specifier (a GNU extension). + + remove-qualifiers-specifier: + __remove_qualifiers ( type-name ) +*/ + +static struct c_typespec +c_parser_remove_qualifiers_specifier (c_parser *parser) +{ + struct c_typespec ret; + ret.kind = ctsk_typeof; + ret.spec = error_mark_node; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + gcc_assert (c_parser_next_token_is_keyword (parser, RID_REMOVE_QUALS)); + + /* Consume '__remove_qualifiers'. */ + c_parser_consume_token (parser); + + matching_parens parens; + if (!parens.require_open (parser)) + return ret; + + /* Only accept a type-name as an argument. */ + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + /* Do not warn about problems with the expression. */ + c_inhibit_evaluation_warnings++; + in_remove_qualifiers++; + struct c_type_name *type = c_parser_type_name (parser); + /* Go back to evaluating expressions. */ + c_inhibit_evaluation_warnings--; + in_remove_qualifiers--; + if (type != NULL) + { + ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands); + pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE)); + /* Remove all type qualifiers. */ + if (ret.spec != error_mark_node) + ret.spec = c_build_qualified_type (ret.spec, TYPE_UNQUALIFIED); + } + } + else + error_at (c_parser_peek_token (parser)->location, + "%<__remove_qualifiers%> can only be applied to a type"); + parens.skip_until_found_close (parser); + return ret; +} + /* Parse an alignment-specifier. C11 6.7.5: @@ -9879,7 +9939,7 @@ c_parser_objc_synchronized_statement (c_parser *parser) break continue return goto asm sizeof typeof __alignof unsigned long const short volatile signed restrict _Complex in out inout bycopy byref oneway int char float double void _Bool - _Atomic + _Atomic __remove_qualifiers ??? Why this selection of keywords but not, for example, storage class specifiers? */ @@ -9944,6 +10004,7 @@ c_parser_objc_selector (c_parser *parser) case RID_INT_N_1: case RID_INT_N_2: case RID_INT_N_3: + case RID_REMOVE_QUALS: c_parser_consume_token (parser); return value; default: diff --git gcc/c/c-tree.h gcc/c/c-tree.h index 96c7ae7613f..e16c4185350 100644 --- gcc/c/c-tree.h +++ gcc/c/c-tree.h @@ -191,7 +191,7 @@ enum c_typespec_kind { ctsk_typedef, /* An ObjC-specific kind of type specifier. */ ctsk_objc, - /* A typeof specifier, or _Atomic ( type-name ). */ + /* A typeof specifier, _Atomic ( type-name ), or __remove_qualifiers. */ ctsk_typeof }; @@ -617,6 +617,7 @@ extern bool c_vla_unspec_p (tree x, tree fn); extern int in_alignof; extern int in_sizeof; extern int in_typeof; +extern int in_remove_qualifiers; extern tree c_last_sizeof_arg; extern location_t c_last_sizeof_loc; diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c index 135dd9d665c..ce720802e70 100644 --- gcc/c/c-typeck.c +++ gcc/c/c-typeck.c @@ -72,6 +72,9 @@ int in_sizeof; /* The level of nesting inside "typeof". */ int in_typeof; +/* The level of nesting inside "__remove_qualifiers". */ +int in_remove_qualifiers; + /* The argument of last parsed sizeof expression, only to be tested if expr.original_code == SIZEOF_EXPR. */ tree c_last_sizeof_arg; @@ -2782,7 +2785,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type) if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof) { - if (!in_sizeof && !in_typeof) + if (!in_sizeof && !in_typeof && !in_remove_qualifiers) C_DECL_USED (ref) = 1; else if (DECL_INITIAL (ref) == NULL_TREE && DECL_EXTERNAL (ref) @@ -2838,7 +2841,7 @@ struct maybe_used_decl { /* The decl. */ tree decl; - /* The level seen at (in_sizeof + in_typeof). */ + /* The level seen at (in_sizeof + in_typeof + in_remove_qualifiers). */ int level; /* The next one at this level or above, or NULL. */ struct maybe_used_decl *next; @@ -2856,7 +2859,7 @@ record_maybe_used_decl (tree decl) { struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl); t->decl = decl; - t->level = in_sizeof + in_typeof; + t->level = in_sizeof + in_typeof + in_remove_qualifiers; t->next = maybe_used_decls; maybe_used_decls = t; } @@ -2870,7 +2873,7 @@ void pop_maybe_used (bool used) { struct maybe_used_decl *p = maybe_used_decls; - int cur_level = in_sizeof + in_typeof; + int cur_level = in_sizeof + in_typeof + in_remove_qualifiers; while (p && p->level > cur_level) { if (used) diff --git gcc/cp/parser.c gcc/cp/parser.c index 47d91bfa9a7..0e3d00dbc47 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -973,9 +973,10 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) case RID_FLOAT: case RID_DOUBLE: case RID_VOID: - /* GNU extensions. */ + /* GNU extensions. */ case RID_ATTRIBUTE: case RID_TYPEOF: + case RID_REMOVE_QUALS: /* C++0x extensions. */ case RID_DECLTYPE: case RID_UNDERLYING_TYPE: @@ -16960,6 +16961,24 @@ cp_parser_simple_type_specifier (cp_parser* parser, return type; + case RID_REMOVE_QUALS: + /* Consume the `__remove_qualifiers' token. */ + cp_lexer_consume_token (parser->lexer); + /* Parse the operand to __remove_qualifiers`'. */ + type = cp_parser_sizeof_operand (parser, RID_REMOVE_QUALS); + if (!TYPE_P (type)) + { + error_at (token->location, + "%<__remove_qualifiers%> can only be applied to a type"); + type = error_mark_node; + } + if (decl_specs) + cp_parser_set_decl_spec_type (decl_specs, type, + token, + /*type_definition_p=*/false); + + return type; + case RID_UNDERLYING_TYPE: type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE); if (decl_specs) @@ -27696,6 +27715,9 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword) TYPENAME, /*initialized=*/0, /*attrlist=*/NULL); + /* __remove_qualifiers removes all type qualifiers. */ + if (keyword == RID_REMOVE_QUALS) + expr = cp_build_qualified_type (expr, TYPE_UNQUALIFIED); } } diff --git gcc/doc/extend.texi gcc/doc/extend.texi index 649be015dbb..749a9735f3b 100644 --- gcc/doc/extend.texi +++ gcc/doc/extend.texi @@ -29,6 +29,7 @@ extensions, accepted by GCC in C90 mode and in C++. * Nested Functions:: As in Algol and Pascal, lexical scoping of functions. * Constructing Calls:: Dispatching a call to another function. * Typeof:: @code{typeof}: referring to the type of an expression. +* __remove_qualifiers:: Removing type qualifiers using @code{__remove_qualifiers}. * Conditionals:: Omitting the middle operand of a @samp{?:} expression. * __int128:: 128-bit integers---@code{__int128}. * Long Long:: Double-word integers---@code{long long int}. @@ -788,6 +789,37 @@ evaluated only once when using @code{__auto_type}, but twice if @code{typeof} is used. @end itemize +@node __remove_qualifiers +@section Removing type qualifiers using @code{__remove_qualifiers} +@findex __remove_qualifiers + +@code{__remove_qualifiers} takes a typename as an argument: + +@smallexample +__remove_qualifiers (const int) +@end smallexample + +and produces the same type with all type qualifiers such as @code{const} and +@code{volatile} removed. This is useful in combination with @code{typeof}, +e.g. for certain macros when passed const arguments: + +@smallexample +#define MAX(x, y) \ + (@{ \ + __remove_qualifiers (__typeof (x)) ret = x; \ + if (y > ret) ret = y; \ + ret; \ + @}) + +const int ci = 5; +MAX (ci, 12); +@end smallexample + +In C++, it's possible to combine @code{__remove_qualifiers} with +@code{decltype} instead of @code{typeof}. + +It is an error to pass an expression as an argument. + @node Conditionals @section Conditionals with Omitted Operands @cindex conditional expressions, extensions diff --git gcc/testsuite/c-c++-common/remove-quals-1.c gcc/testsuite/c-c++-common/remove-quals-1.c index e69de29bb2d..28464eb6b87 100644 --- gcc/testsuite/c-c++-common/remove-quals-1.c +++ gcc/testsuite/c-c++-common/remove-quals-1.c @@ -0,0 +1,42 @@ +/* PR c/65455 */ +/* { dg-do compile } */ +/* { dg-options "-pedantic-errors" } */ + +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; + + __remove_qualifiers (__typeof (i)) *nip = 0; + __remove_qualifiers (__typeof (ci)) *ncip = 0; + __remove_qualifiers (__typeof (vi)) *nvip = 0; + + __remove_qualifiers (__typeof (i)) *nip2 = 0; + __remove_qualifiers (__typeof (ci)) *ncip2 = 0; + __remove_qualifiers (__typeof (vi)) *nvip2 = 0; + + ip = cip; /* { dg-error "assignment discards|invalid conversion" } */ + ip = vip; /* { dg-error "assignment discards|invalid conversion" } */ + + ip = nip; + ip = ncip; + ip = nvip; + + ip = nip2; + ip = ncip2; + ip = nvip2; + + ncip = cip; /* { dg-error "assignment discards|invalid conversion" } */ + nvip = vip; /* { dg-error "assignment discards|invalid conversion" } */ + ncip2 = cip; /* { dg-error "assignment discards|invalid conversion" } */ + nvip2 = vip; /* { dg-error "assignment discards|invalid conversion" } */ + + nip = ip; + nip2 = ip; +} diff --git gcc/testsuite/c-c++-common/remove-quals-2.c gcc/testsuite/c-c++-common/remove-quals-2.c index e69de29bb2d..fac314d52d8 100644 --- gcc/testsuite/c-c++-common/remove-quals-2.c +++ gcc/testsuite/c-c++-common/remove-quals-2.c @@ -0,0 +1,32 @@ +/* PR c/65455 */ +/* { dg-do compile } */ + +const int g(void); + +#define MAX(__x, __y) \ + ({ \ + __remove_qualifiers (__typeof (__x)) __ret = __x; \ + if (__y > __ret) __ret = __y; \ + __ret; \ + }) + +void +fn (void) +{ + const int ci = 5; + __remove_qualifiers (__typeof (({ ci; }))) n1; + __remove_qualifiers (__typeof (ci)) n2; + __typeof (g ()) n4; + __remove_qualifiers (__typeof (g ())) n3; + + typedef __remove_qualifiers (__typeof (ci)) T; + T n5; + + n1 = 5; + n2 = 5; + n3 = 5; + n4 = 5; + n5 = 5; + + MAX (ci, 12); +} diff --git gcc/testsuite/c-c++-common/remove-quals-3.c gcc/testsuite/c-c++-common/remove-quals-3.c index e69de29bb2d..c3ace534adf 100644 --- gcc/testsuite/c-c++-common/remove-quals-3.c +++ gcc/testsuite/c-c++-common/remove-quals-3.c @@ -0,0 +1,17 @@ +/* PR c/65455 */ +/* { dg-do run } */ + +int +main () +{ + __remove_qualifiers (const int) h; + h = 9; + + int i = 1; + __typeof (int [++i]) e; + __remove_qualifiers (int [++i]) e2; + __remove_qualifiers (__typeof (int [++i])) e3; + + if (i != 4) + __builtin_abort (); +} diff --git gcc/testsuite/c-c++-common/remove-quals-4.c gcc/testsuite/c-c++-common/remove-quals-4.c index e69de29bb2d..d140f553345 100644 --- gcc/testsuite/c-c++-common/remove-quals-4.c +++ gcc/testsuite/c-c++-common/remove-quals-4.c @@ -0,0 +1,15 @@ +/* PR c/65455 */ +/* { dg-do compile } */ +/* { dg-options "-Wall -Wextra -Wpedantic -Wno-unused -Wno-vla" } */ + +void +fn (void) +{ + __typeof (int [1 / 0]) t1; + __remove_qualifiers (int [1 / 0]) t2; + + int i; + __remove_qualifiers (i) t3; /* { dg-error ".__remove_qualifiers. can only be applied to a type|expected" } */ + __remove_qualifiers (1) t4; /* { dg-error ".__remove_qualifiers. can only be applied to a type|expected" } */ + __remove_qualifiers (int []) t5; /* { dg-error "array size|storage size" } */ +} diff --git gcc/testsuite/g++.dg/ext/remove-quals-1.C gcc/testsuite/g++.dg/ext/remove-quals-1.C index e69de29bb2d..0d0e33538b2 100644 --- gcc/testsuite/g++.dg/ext/remove-quals-1.C +++ gcc/testsuite/g++.dg/ext/remove-quals-1.C @@ -0,0 +1,12 @@ +// PR c/65455 +// { dg-do compile } +// { dg-options "-pedantic-errors" } + +void +fn (void) +{ + signed __remove_qualifiers (const int) s; /* { dg-error "used invalidly" } */ + + __typeof (struct S { int i; }) q; /* { dg-error "types may not be defined in .typeof. expressions" } */ + __remove_qualifiers (struct S2 { int i; }) q2; /* { dg-error "types may not be defined in .__remove_qualifiers__. expressions" } */ +} diff --git gcc/testsuite/g++.dg/ext/remove-quals-2.C gcc/testsuite/g++.dg/ext/remove-quals-2.C index e69de29bb2d..10f7b5c5d7c 100644 --- gcc/testsuite/g++.dg/ext/remove-quals-2.C +++ gcc/testsuite/g++.dg/ext/remove-quals-2.C @@ -0,0 +1,25 @@ +// PR c/65455 +// { dg-do compile { target c++11 } } + +template<typename T, typename U> +struct is_same +{ + static const bool value = false; +}; + +template<typename T> +struct is_same<T, T> +{ + static const bool value = true; +}; + +const int x = 1; +typedef __remove_qualifiers (decltype (x)) T; +T y = 1; +volatile int i; +static_assert(is_same<__remove_qualifiers (decltype (x)), int>::value, + "type should be int"); +static_assert(is_same<decltype (y), int>::value, + "type should be int"); +static_assert(is_same<__remove_qualifiers (decltype (i)), int>::value, + "type should be int"); diff --git gcc/testsuite/gcc.dg/auto-type-3.c gcc/testsuite/gcc.dg/auto-type-3.c index e69de29bb2d..79479c80084 100644 --- gcc/testsuite/gcc.dg/auto-type-3.c +++ gcc/testsuite/gcc.dg/auto-type-3.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +struct S +{ + int k; +}; + +void +foo (void) +{ + _Atomic register const int a = 3; + const int b = 16; + const struct S s; + int *const c = 0; + + __auto_type i = a; + i++; + __auto_type j = b; + j++; + __auto_type k = s.k; + k++; + __auto_type l = c; + l++; +} diff --git gcc/testsuite/gcc.dg/remove-quals-1.c gcc/testsuite/gcc.dg/remove-quals-1.c index e69de29bb2d..aecc17c949b 100644 --- gcc/testsuite/gcc.dg/remove-quals-1.c +++ gcc/testsuite/gcc.dg/remove-quals-1.c @@ -0,0 +1,23 @@ +/* PR c/65455 */ +/* { dg-do compile } */ +/* { dg-options "-Wrestrict" } */ + +int *restrict t; + +void +bar (__remove_qualifiers (__typeof (t)) p, __remove_qualifiers (__typeof (t)) q) +{ +} + +void +baz (__typeof (t) p, __typeof (t) q) +{ +} + +void +foo (void) +{ + int i = 42; + bar (&i, &i); + baz (&i, &i); /* { dg-warning "passing argument 1 to restrict-qualified parameter aliases" } */ +} diff --git gcc/testsuite/gcc.dg/remove-quals-2.c gcc/testsuite/gcc.dg/remove-quals-2.c index e69de29bb2d..2d13bf2b34e 100644 --- gcc/testsuite/gcc.dg/remove-quals-2.c +++ gcc/testsuite/gcc.dg/remove-quals-2.c @@ -0,0 +1,12 @@ +/* PR c/65455 */ +/* { dg-do compile } */ +/* { dg-options "-Wc++-compat" } */ + +void +fn (void) +{ + signed __remove_qualifiers (const int) s; /* { dg-error "two or more data types in declaration specifiers" } */ + + __typeof (struct S { int i; }) q; /* { dg-warning "defining type in .typeof. expression is invalid" } */ + __remove_qualifiers (struct S2 { int i; }) q2; /* { dg-warning "defining type in .__remove_qualifiers. expression is invalid" } */ +} Marek