This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

Re: C/C++ PATCH to add __remove_qualifiers (PR c/65455, c/39985)


On Thu, Aug 31, 2017 at 04:38:27PM +0000, Joseph Myers wrote:
> I think the documentation needs to say (and the tests need to test) that 
> this produces a non-atomic type (like lvalue-to-rvalue conversion), if 
> that's the intent for how it handles atomic types, since _Atomic is 
> syntactically a qualifier but largely not treated like one in the 
> standard.

True, updated patch here:

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2017-09-01  Marek Polacek  <polacek@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.
	* gcc.dg/remove-quals-3.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 f4e1cf6aa0c..f65d5f17ebb 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 4bfae3655d5..2d4605d8726 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..8e6a7d8c395 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,38 @@ 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.  In C11, the @code{_Atomic} qualifier is also removed
+so the resulting type is a non-atomic type.  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" } */
+}
diff --git gcc/testsuite/gcc.dg/remove-quals-3.c gcc/testsuite/gcc.dg/remove-quals-3.c
index e69de29bb2d..8e88031003d 100644
--- gcc/testsuite/gcc.dg/remove-quals-3.c
+++ gcc/testsuite/gcc.dg/remove-quals-3.c
@@ -0,0 +1,13 @@
+/* PR c/65455 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void
+fn (void)
+{
+  _Atomic int a;
+  __remove_qualifiers (_Atomic int) a; /* { dg-error "conflicting type qualifiers" } */
+
+  _Atomic int b;
+  __remove_qualifiers (__typeof (b)) b; /* { dg-error "conflicting type qualifiers" } */
+}

	Marek


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