public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/ARM/heads/morello)] c-family: Handle CHERI printf extensions in -Wformat
@ 2023-03-13 18:12 Alex Coplan
  0 siblings, 0 replies; only message in thread
From: Alex Coplan @ 2023-03-13 18:12 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:a865594ef03c5b2b83fc37e9b0c441d39f47d2b4

commit a865594ef03c5b2b83fc37e9b0c441d39f47d2b4
Author: Alex Coplan <alex.coplan@arm.com>
Date:   Tue Mar 7 12:47:31 2023 +0000

    c-family: Handle CHERI printf extensions in -Wformat
    
    This patch teaches the printf format checking to handle the CHERI
    extensions described here:
    
    https://github.com/CTSRD-CHERI/cheri-c-programming/wiki/Displaying-Capabilities
    
    in particular, we add support for the '#' flag and the 'l' length
    modifier to be used with the 'p' format specifier.
    
    Since these extensions should only be recognized when CHERI is enabled
    (i.e.  when compiling for a capability target), we make use of the
    existing dynamic_format_types mechanism to modify the format table at
    runtime to handle the CHERI extensions.
    
    The '#' flag is simple to handle in this way. The 'l' length modifier is
    not quite so straightforward to handle. The table that drives the
    checking has entries of type format_char_info. The two key members here
    are:
    
      int pointer_count;
      format_type_detail types[FMT_LEN_MAX];
    
    Currently, the %p format specifier is handled with a pointer_count of 1
    and an underlying type of void_type_node. The types array above is
    indexed by the format_lengths enum, so it is possible to vary the
    expected type based on length modifiers in this way. The problem is that
    we don't currently encode the pointer type in this array, the pointer
    type is instead implicit from the pointer_count field. Unfortunately,
    this doesn't allow us to distinguish between capability and integer
    pointers, which is necessary for hybrid CHERI.
    
    To fix this, we adjust the pointer_count for '%p' to 0, and encode the
    actual pointer type in the types array above (instead of
    void_type_node). This allows us to naturally distinguish between
    capability pointers (with the 'l' length modifier) and normal pointers
    (without the length modifiers).
    
    We then need to make a small change to check_format_types to handle
    pointer types encoded in this way. We continue to handle the existing
    pointer_count indirection mechanism here, as this is still suitable for
    use in other cases (e.g. for scanf where there can be multiple
    indirections).

Diff:
---
 gcc/c-family/c-format.c                            |  68 +++++++++++-
 gcc/c-family/c-format.h                            |   2 +
 gcc/testsuite/gcc.dg/format/c90-printf-1.c         |   5 +-
 gcc/testsuite/gcc.dg/format/c99-printf-1.c         |   5 +-
 .../gcc.target/aarch64/morello/wformat-pedantic.c  | 117 +++++++++++++++++++++
 gcc/testsuite/gcc.target/aarch64/morello/wformat.c | 110 +++++++++++++++++++
 6 files changed, 301 insertions(+), 6 deletions(-)

diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index a41a1e32e0c..82a96ba6a8b 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -706,7 +706,7 @@ static const format_char_info print_char_table[] =
   { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I",  "",   NULL },
   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
-  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "p",   0, STD_C89, { T89_PTR, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
   { "n",   1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
   /* C99 conversion specifiers.  */
   { "F",   0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "",   NULL },
@@ -4201,6 +4201,19 @@ check_format_types (const substring_loc &fmt_loc,
       if (i < types->pointer_count)
 	continue;
 
+      tree orig_wanted_type = wanted_type;
+
+      /* If we're looking for a pointer type and we have a suitable
+	 pointer type, look through to the target types.  */
+      if (POINTER_TYPE_P (wanted_type)
+	  && POINTER_TYPE_P (cur_type)
+	  && capability_type_p (wanted_type) == capability_type_p (cur_type))
+	{
+	  cur_type = TREE_TYPE (cur_type);
+	  wanted_type = TREE_TYPE (wanted_type);
+	  i++;
+	}
+
       cur_type = TYPE_MAIN_VARIANT (cur_type);
 
       /* Check whether the argument type is a character type.  This leniency
@@ -4262,7 +4275,7 @@ check_format_types (const substring_loc &fmt_loc,
 	continue;
       /* Now we have a type mismatch.  */
       format_type_warning (fmt_loc, param_loc, types,
-			   wanted_type, orig_cur_type, fki,
+			   orig_wanted_type, orig_cur_type, fki,
 			   offset_to_type_start, conversion_char);
     }
 }
@@ -4796,6 +4809,44 @@ find_length_info_modifier_index (const format_length_info *fli, int c)
   gcc_unreachable ();
 }
 
+static void
+init_cheri_printf_info ()
+{
+  static bool cheri_init_done = false;
+  if (cheri_init_done)
+    return;
+
+  gcc_assert (dynamic_format_types[printf_format_type].conversion_specs
+	      == print_char_table);
+
+  format_char_info *new_print_char_table
+    = (format_char_info *) xmemdup (print_char_table,
+				    sizeof (print_char_table),
+				    sizeof (print_char_table));
+
+  const unsigned num_entries
+    = sizeof (print_char_table) / sizeof (format_char_info);
+
+  format_char_info *p = new_print_char_table;
+  format_char_info *end = p + num_entries;
+  for (; p < end; p++)
+    {
+      if (strcmp (p->format_chars, "p"))
+	continue;
+
+      /* Allow the '#' flag to be used on the 'p' conversion specifier.  */
+      gcc_assert (!strcmp (p->flag_chars, "-w"));
+      p->flag_chars = "-w#";
+      p->types[FMT_LEN_l].type = &cap_ptr_type_node;
+      break;
+    }
+  gcc_assert (p < end);
+
+  dynamic_format_types[printf_format_type].conversion_specs
+    = new_print_char_table;
+  cheri_init_done = true;
+}
+
 /* Determine the type of HOST_WIDE_INT in the code being compiled for
    use in GCC's __asm_fprintf__ custom format attribute.  You must
    have set dynamic_format_types before calling this function.  */
@@ -5254,6 +5305,19 @@ handle_format_attribute (tree *node, tree atname, tree args,
 	gcc_unreachable ();
     }
 
+  /* Take CHERI printf extensions into account.  */
+  if (info.format_type == printf_format_type && cap_ptr_type_node)
+    {
+      /* Our first time through, we have to make sure that our
+	 format_type data is allocated dynamically and is modifiable.  */
+      if (!dynamic_format_types)
+	format_types = dynamic_format_types = (format_kind_info *)
+	  xmemdup (format_types_orig, sizeof (format_types_orig),
+		   sizeof (format_types_orig));
+
+      init_cheri_printf_info ();
+    }
+
   return NULL_TREE;
 }
 
diff --git a/gcc/c-family/c-format.h b/gcc/c-family/c-format.h
index ff8a9f988c3..130db5a0da5 100644
--- a/gcc/c-family/c-format.h
+++ b/gcc/c-family/c-format.h
@@ -301,11 +301,13 @@ struct format_kind_info
 #define T_UC	&unsigned_char_type_node
 #define T99_UC	{ STD_C99, NULL, T_UC }
 #define T_V	&void_type_node
+#define T_PTR	&ptr_type_node
 #define T89_G   { STD_C89, NULL, &local_gimple_ptr_node }
 #define T_CGRAPH_NODE   { STD_C89, NULL, &local_cgraph_node_ptr_node }
 #define T_EVENT_PTR    { STD_C89, NULL, &local_event_ptr_node }
 #define T89_T   { STD_C89, NULL, &local_tree_type_node }
 #define T89_V	{ STD_C89, NULL, T_V }
+#define T89_PTR { STD_C89, NULL, T_PTR }
 #define T_W	&wchar_type_node
 #define T94_W	{ STD_C94, "wchar_t", T_W }
 #define TEX_W	{ STD_EXT, "wchar_t", T_W }
diff --git a/gcc/testsuite/gcc.dg/format/c90-printf-1.c b/gcc/testsuite/gcc.dg/format/c90-printf-1.c
index c8652fc2252..a8ddced421a 100644
--- a/gcc/testsuite/gcc.dg/format/c90-printf-1.c
+++ b/gcc/testsuite/gcc.dg/format/c90-printf-1.c
@@ -91,7 +91,8 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
   printf (" %lE", d); /* { dg-warning "15:length|C" "bad use of %l" } */
   printf (" %lg", d); /* { dg-warning "15:length|C" "bad use of %l" } */
   printf (" %lG", d); /* { dg-warning "15:length|C" "bad use of %l" } */
-  printf (" %lp", p); /* { dg-warning "15:length|C" "bad use of %l" } */
+  printf (" %lp", p); /* { dg-warning "15:length|C" "bad use of %l" {target {! aarch64_capability_any}} } */
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability'} "" {target {cheri_capability_hybrid}} .-1 } */
   /* These next two were added in C94, but should be objected to in C90.
      For the first one, GCC has wanted wchar_t instead of the correct C94
      and C99 wint_t.
@@ -153,7 +154,7 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
   printf ("%#u", u); /* { dg-warning "14:flag" "bad use of # flag" } */
   printf ("%#c", i); /* { dg-warning "14:flag" "bad use of # flag" } */
   printf ("%#s", s); /* { dg-warning "14:flag" "bad use of # flag" } */
-  printf ("%#p", p); /* { dg-warning "14:flag" "bad use of # flag" } */
+  printf ("%#p", p); /* { dg-warning "14:flag" "bad use of # flag" {target {! aarch64_capability_any}} } */
   printf ("%#n", n); /* { dg-warning "14:flag" "bad use of # flag" } */
   /* Uses of the 0 flag.  */
   printf ("%08d%08i%08o%08u%08x%08X%08e%08E%08f%08g%08G", i, i, u, u, u, u,
diff --git a/gcc/testsuite/gcc.dg/format/c99-printf-1.c b/gcc/testsuite/gcc.dg/format/c99-printf-1.c
index 408ad49a680..62b7f6beabd 100644
--- a/gcc/testsuite/gcc.dg/format/c99-printf-1.c
+++ b/gcc/testsuite/gcc.dg/format/c99-printf-1.c
@@ -48,7 +48,8 @@ foo (int i, unsigned int u, double d, char *s, void *p, int *n,
   printf ("%lc", lc);
   printf ("%ls", ls);
   printf ("%lf%lF%le%lE%lg%lG%la%lA", d, d, d, d, d, d, d, d);
-  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" {target {! aarch64_capability_any}} } */
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability'} "" {target {cheri_capability_hybrid}} .-1 } */
   printf ("%lld%lli%llo%llu%llx%llX", ll, ll, ull, ull, ull, ull);
   printf ("%lln", lln);
   printf ("%llf", d); /* { dg-warning "length" "bad use of %ll" } */
@@ -154,7 +155,7 @@ foo (int i, unsigned int u, double d, char *s, void *p, int *n,
   printf ("%#u", u); /* { dg-warning "flag" "bad use of # flag" } */
   printf ("%#c", i); /* { dg-warning "flag" "bad use of # flag" } */
   printf ("%#s", s); /* { dg-warning "flag" "bad use of # flag" } */
-  printf ("%#p", p); /* { dg-warning "flag" "bad use of # flag" } */
+  printf ("%#p", p); /* { dg-warning "flag" "bad use of # flag" {target {! aarch64_capability_any}} } */
   printf ("%#n", n); /* { dg-warning "flag" "bad use of # flag" } */
   /* Uses of the 0 flag.  */
   printf ("%08d%08i%08o%08u%08x%08X%08e%08E%08f%08F%08g%08G%08a%08A", i, i,
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/wformat-pedantic.c b/gcc/testsuite/gcc.target/aarch64/morello/wformat-pedantic.c
new file mode 100644
index 00000000000..621b78398ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/wformat-pedantic.c
@@ -0,0 +1,117 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-Wformat -pedantic" } */
+/* Test CHERI extensions are handled by -Wformat.  */
+
+void base1(void *p) { __builtin_printf ("%p", p); }
+void base2(char *p) { __builtin_printf ("%p", p); }
+void base3(const void *p) { __builtin_printf ("%p", p); }
+void base4(const char *p) { __builtin_printf ("%p", p); }
+void base5(const void * const p) { __builtin_printf ("%p", p); }
+void base6(const char * const p) { __builtin_printf ("%p", p); }
+void base_bad1(int *p) {
+  __builtin_printf ("%p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'int \*'} "" {target *-*-*} .-1 } */
+}
+void base_bad2(int x)
+{
+  __builtin_printf ("%p", x);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'int'} "" {target *-*-*} .-1 } */
+}
+void hybrid_bad1 (void * __capability p)
+{
+  __builtin_printf ("%p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'void \* __capability'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void hybrid_bad2 (char * __capability p)
+{
+  __builtin_printf ("%p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'char \* __capability'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void hybrid_bad3 (int * __capability p)
+{
+  __builtin_printf ("%p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'int \*( __capability)?'} "" {target *-*-*} .-1 } */
+}
+
+void alt1(void *p) { __builtin_printf ("%#p", p); }
+void alt2(char *p) { __builtin_printf ("%#p", p); }
+void alt3(const void *p) { __builtin_printf ("%#p", p); }
+void alt4(const char *p) { __builtin_printf ("%#p", p); }
+void alt_bad1(int *p) {
+  __builtin_printf ("%#p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'int \*'} "" {target *-*-*} .-1 } */
+}
+void alt_bad2(const int *p)
+{
+  __builtin_printf ("%#p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'const int \*'} "" {target *-*-*} .-1 } */
+}
+void alt_bad3(int x)
+{
+  __builtin_printf ("%#p", x);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'int'} "" {target *-*-*} .-1 } */
+}
+
+void ell1(void * __capability p) { __builtin_printf ("%lp", p); }
+void ell2(char * __capability p) { __builtin_printf ("%lp", p); }
+void ell3(const void * __capability p) { __builtin_printf ("%lp", p); }
+void ell4(const char * __capability p) { __builtin_printf ("%lp", p); }
+void ell_bad1(int * __capability p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'int \*( __capability)?'} "" {target *-*-*} .-1 } */
+}
+void ell_bad2(const int * __capability p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'const int \*( __capability)?'} "" {target *-*-*} .-1 } */
+}
+void ell_bad3(void *p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'void \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void ell_bad4(char *p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'char \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void ell_bad5(int *p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'int \*'} "" {target *-*-*} .-1 } */
+}
+
+void both1(void * __capability p) { __builtin_printf ("%#lp", p); }
+void both2(char * __capability p) { __builtin_printf ("%#lp", p); }
+void both3(const void * __capability p) { __builtin_printf ("%#lp", p); }
+void both4(const char * __capability p) { __builtin_printf ("%#lp", p); }
+
+void both_bad1(int * __capability p) {
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'int \*( __capability)?'} "" {target *-*-*} .-1 } */
+}
+void both_bad2(const int * __capability p) {
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'const int \*( __capability)?'} "" {target *-*-*} .-1 } */
+}
+void both_bad3 (void *p)
+{
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'void \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void both_bad4 (char *p)
+{
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'char \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void both_bad5 (float *p)
+{
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'float \*( __capability)?'} "" {target *-*-*} .-1 } */
+}
+void both_bad6 (const void *p)
+{
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'const void \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/morello/wformat.c b/gcc/testsuite/gcc.target/aarch64/morello/wformat.c
new file mode 100644
index 00000000000..10c751f2234
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/morello/wformat.c
@@ -0,0 +1,110 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-Wformat" } */
+/* Test CHERI extensions are handled by -Wformat. */
+
+void base1(void *p) { __builtin_printf ("%p", p); }
+void base2(char *p) { __builtin_printf ("%p", p); }
+void base3(int *p) { __builtin_printf ("%p", p); }
+void base4(const void *p) { __builtin_printf ("%p", p); }
+void base5(const char *p) { __builtin_printf ("%p", p); }
+void base6(const int *p) { __builtin_printf ("%p", p); }
+void base7(const void * const p) { __builtin_printf ("%p", p); }
+void base_bad(int x)
+{
+  __builtin_printf ("%p", x);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'int'} "" {target *-*-*} .-1 } */
+}
+void hybrid_bad1 (void * __capability p)
+{
+  __builtin_printf ("%p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'void \* __capability'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void hybrid_bad2 (char * __capability p)
+{
+  __builtin_printf ("%p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'char \* __capability'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void hybrid_bad3 (int * __capability p)
+{
+  __builtin_printf ("%p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'int \* __capability'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void hybrid_bad4 (const void * __capability p)
+{
+  __builtin_printf ("%p", p);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'const void \* __capability'} "" {target cheri_capability_hybrid} .-1 } */
+}
+
+void alt1(void *p) { __builtin_printf ("%#p", p); }
+void alt2(char *p) { __builtin_printf ("%#p", p); }
+void alt3(int *p) { __builtin_printf ("%#p", p); }
+void alt_bad(int x)
+{
+  __builtin_printf ("%#p", x);
+  /* { dg-warning {format '%p' expects argument of type 'void \*', but argument 2 has type 'int'} "" {target *-*-*} .-1 } */
+}
+
+void ell1(void * __capability p) { __builtin_printf ("%lp", p); }
+void ell2(char * __capability p) { __builtin_printf ("%lp", p); }
+void ell3(int * __capability p) { __builtin_printf ("%lp", p); }
+void ell4(const void * __capability p) { __builtin_printf ("%lp", p); }
+
+void ell_bad1(void *p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'void \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void ell_bad2(char *p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'char \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void ell_bad3(int *p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'int \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void ell_bad4(int x)
+{
+  __builtin_printf ("%lp", x);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'int'} "" {target *-*-*} .-1 } */
+}
+void ell_bad5(const void *p)
+{
+  __builtin_printf ("%lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'const void \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+
+
+void both1(void * __capability p) { __builtin_printf ("%#lp", p); }
+void both2(char * __capability p) { __builtin_printf ("%#lp", p); }
+void both3(int * __capability p) { __builtin_printf ("%#lp", p); }
+void both4(const void * __capability p) { __builtin_printf ("%#lp", p); }
+void both5(const char * __capability p) { __builtin_printf ("%#lp", p); }
+void both6(const int * __capability p) { __builtin_printf ("%#lp", p); }
+
+void both_bad1 (void *p)
+{
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'void \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void both_bad2 (char *p)
+{
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'char \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void both_bad3 (float *p)
+{
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'float \*'} "" {target cheri_capability_hybrid} .-1 } */
+}
+void both_bad4 (int x)
+{
+  __builtin_printf ("%#lp", x);
+  /* { dg-warning {format '%lp' expects argument of type 'void \*( __capability)?', but argument 2 has type 'int'} "" {target *-*-*} .-1 } */
+}
+void both_bad5 (const void *p)
+{
+  __builtin_printf ("%#lp", p);
+  /* { dg-warning {format '%lp' expects argument of type 'void \* __capability', but argument 2 has type 'const void \*'} "" {target cheri_capability_hybrid} .-1 } */
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-03-13 18:12 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-13 18:12 [gcc(refs/vendors/ARM/heads/morello)] c-family: Handle CHERI printf extensions in -Wformat Alex Coplan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).