Implement P0482R5, char8_t: A type for UTF-8 characters and strings
authorTom Honermann <tom@honermann.net>
Mon, 14 Jan 2019 19:55:51 +0000 (19:55 +0000)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 14 Jan 2019 19:55:51 +0000 (14:55 -0500)
gcc/cp/
* cvt.c (type_promotes_to): Handle char8_t promotion.
* decl.c (grokdeclarator): Handle invalid type specifier
combinations involving char8_t.
* lex.c (init_reswords): Add char8_t as a reserved word.
* mangle.c (write_builtin_type): Add name mangling for char8_t (Du).
* parser.c (cp_keyword_starts_decl_specifier_p)
(cp_parser_simple_type_specifier): Recognize char8_t as a simple
type specifier.
(cp_parser_string_literal): Use char8_array_type_node for the type
of CPP_UTF8STRING.
(cp_parser_set_decl_spec_type): Tolerate char8_t typedefs in system
headers.
* rtti.c (emit_support_tinfos): type_info support for char8_t.
* tree.c (char_type_p): Recognize char8_t as a character type.
* typeck.c (string_conv_p): Handle conversions of u8 string
literals of char8_t type.
(check_literal_operator_args): Handle UDLs with u8 string literals
of char8_t type.
* typeck2.c (ordinary_char_type_p): New.
(digest_init_r): Disallow initializing a char array with a u8 string
literal.
gcc/c-family/
* c-common.c (c_common_reswords): Add char8_t.
(fix_string_type): Use char8_t for the type of u8 string literals.
(c_common_get_alias_set): char8_t doesn't alias.
(c_common_nodes_and_builtins): Define char8_t as a builtin type in
C++.
(c_stddef_cpp_builtins): Add __CHAR8_TYPE__.
(keyword_begins_type_specifier): Add RID_CHAR8.
* c-common.h (rid): Add RID_CHAR8.
(c_tree_index): Add CTI_CHAR8_TYPE and CTI_CHAR8_ARRAY_TYPE.
Define D_CXX_CHAR8_T and D_CXX_CHAR8_T_FLAGS.
Define char8_type_node and char8_array_type_node.
* c-cppbuiltin.c (cpp_atomic_builtins): Predefine
__GCC_ATOMIC_CHAR8_T_LOCK_FREE.
(c_cpp_builtins): Predefine __cpp_char8_t.
* c-lex.c (lex_string): Use char8_array_type_node as the type of
CPP_UTF8STRING.
(lex_charconst): Use char8_type_node as the type of CPP_UTF8CHAR.
* c-opts.c: If not otherwise specified, enable -fchar8_t when
targeting C++2a.
* c.opt: Add the -fchar8_t command line option.
libiberty/
* cp-demangle.c (cplus_demangle_builtin_types)
(cplus_demangle_type): Add name demangling for char8_t (Du).
* cp-demangle.h: Increase D_BUILTIN_TYPE_COUNT to accommodate the
new char8_t type.

From-SVN: r267923

74 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-cppbuiltin.c
gcc/c-family/c-lex.c
gcc/c-family/c-opts.c
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/lex.c
gcc/cp/mangle.c
gcc/cp/parser.c
gcc/cp/rtti.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/defaults.h
gcc/doc/invoke.texi
gcc/testsuite/c-c++-common/raw-string-13.c
gcc/testsuite/c-c++-common/raw-string-15.c
gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg-char8_t.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/udlit-resolve-char8_t.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/udlit-string-length.C
gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.C
gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.h
gcc/testsuite/g++.dg/cpp1z/udlit-utf8char.C
gcc/testsuite/g++.dg/cpp1z/utf8.C
gcc/testsuite/g++.dg/cpp2a/char8_t1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/char8_t2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
gcc/testsuite/g++.dg/ext/char8_t-aliasing-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-deduction-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-deduction-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-init-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-init-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-keyword-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-keyword-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-limits-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-overload-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-overload-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-sizeof-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-specialization-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-specialization-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-string-literal-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-string-literal-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-type-specifier-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-type-specifier-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-typedef-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-typedef-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-udl-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/char8_t-udl-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/utf-array-short-wchar.C
gcc/testsuite/g++.dg/ext/utf-array.C
gcc/testsuite/g++.dg/ext/utf-cvt-char8_t.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/utf-cxx98.C
gcc/testsuite/g++.dg/ext/utf-dflt.C
gcc/testsuite/g++.dg/ext/utf-gnuxx98.C
gcc/testsuite/g++.dg/ext/utf-type-char8_t.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/utf8-1.C
gcc/testsuite/g++.dg/ext/utf8-2.C
gcc/testsuite/g++.dg/warn/Wformat-ranges-c++11.C
libiberty/ChangeLog
libiberty/cp-demangle.c
libiberty/cp-demangle.h

index 869ab248d9fa1cf48a9aa51f746abc8329457603..aea7143dc91e01bdecf84ef68927e24b8b2252bb 100644 (file)
@@ -1,3 +1,7 @@
+2019-01-14  Tom Honermann  <tom@honermann.net>
+
+       * defaults.h: Define CHAR8_TYPE.
+
 2019-01-14  Martin Sebor  <msebor@redhat.com>
 
        PR target/88638
index fe4c81f9da49322124b17eee9423a78a2f9ee18c..0ff16ab4a3fce4e0fa57f73e3a3a6a139a599191 100644 (file)
@@ -1,3 +1,27 @@
+2019-01-14  Tom Honermann  <tom@honermann.net>
+
+       Implement P0482R5, char8_t: A type for UTF-8 characters and strings
+       * c-common.c (c_common_reswords): Add char8_t.
+       (fix_string_type): Use char8_t for the type of u8 string literals.
+       (c_common_get_alias_set): char8_t doesn't alias.
+       (c_common_nodes_and_builtins): Define char8_t as a builtin type in
+       C++.
+       (c_stddef_cpp_builtins): Add __CHAR8_TYPE__.
+       (keyword_begins_type_specifier): Add RID_CHAR8.
+       * c-common.h (rid): Add RID_CHAR8.
+       (c_tree_index): Add CTI_CHAR8_TYPE and CTI_CHAR8_ARRAY_TYPE.
+       Define D_CXX_CHAR8_T and D_CXX_CHAR8_T_FLAGS.
+       Define char8_type_node and char8_array_type_node.
+       * c-cppbuiltin.c (cpp_atomic_builtins): Predefine
+       __GCC_ATOMIC_CHAR8_T_LOCK_FREE.
+       (c_cpp_builtins): Predefine __cpp_char8_t.
+       * c-lex.c (lex_string): Use char8_array_type_node as the type of
+       CPP_UTF8STRING.
+       (lex_charconst): Use char8_type_node as the type of CPP_UTF8CHAR.
+       * c-opts.c: If not otherwise specified, enable -fchar8_t when
+       targeting C++2a.
+       * c.opt: Add the -fchar8_t command line option.
+
 2019-01-14  Martin Sebor  <msebor@redhat.com>
 
        PR target/88638
index d2ea384d65328b27c59e7e55659b8936127a8a0e..2a5a8e7defb3ed6b45c36cfaf2ea87818e61ad0b 100644 (file)
@@ -79,6 +79,7 @@ machine_mode c_default_pointer_mode = VOIDmode;
        tree signed_char_type_node;
        tree wchar_type_node;
 
+       tree char8_type_node;
        tree char16_type_node;
        tree char32_type_node;
 
@@ -128,6 +129,11 @@ machine_mode c_default_pointer_mode = VOIDmode;
 
        tree wchar_array_type_node;
 
+   Type `char8_t[SOMENUMBER]' or something like it.
+   Used when a UTF-8 string literal is created.
+
+       tree char8_array_type_node;
+
    Type `char16_t[SOMENUMBER]' or something like it.
    Used when a UTF-16 string literal is created.
 
@@ -452,6 +458,7 @@ const struct c_common_resword c_common_reswords[] =
   { "case",            RID_CASE,       0 },
   { "catch",           RID_CATCH,      D_CXX_OBJC | D_CXXWARN },
   { "char",            RID_CHAR,       0 },
+  { "char8_t",         RID_CHAR8,      D_CXX_CHAR8_T_FLAGS | D_CXXWARN },
   { "char16_t",                RID_CHAR16,     D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "char32_t",                RID_CHAR32,     D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "class",           RID_CLASS,      D_CXX_OBJC | D_CXXWARN },
@@ -748,6 +755,11 @@ fix_string_type (tree value)
       charsz = 1;
       e_type = char_type_node;
     }
+  else if (flag_char8_t && TREE_TYPE (value) == char8_array_type_node)
+    {
+      charsz = TYPE_PRECISION (char8_type_node) / BITS_PER_UNIT;
+      e_type = char8_type_node;
+    }
   else if (TREE_TYPE (value) == char16_array_type_node)
     {
       charsz = TYPE_PRECISION (char16_type_node) / BITS_PER_UNIT;
@@ -828,7 +840,8 @@ fix_string_type (tree value)
    CPP_STRING16, or CPP_STRING32.  Return CPP_OTHER in case of error.
    This may not be exactly the string token type that initially created
    the string, since CPP_WSTRING is indistinguishable from the 16/32 bit
-   string type at this point.
+   string type, and CPP_UTF8STRING is indistinguishable from CPP_STRING
+   at this point.
 
    This effectively reverses part of the logic in lex_string and
    fix_string_type.  */
@@ -3640,8 +3653,12 @@ c_common_get_alias_set (tree t)
   if (!TYPE_P (t))
     return -1;
 
+  /* Unlike char, char8_t doesn't alias. */
+  if (flag_char8_t && t == char8_type_node)
+    return -1;
+
   /* The C standard guarantees that any object may be accessed via an
-     lvalue that has character type.  */
+     lvalue that has narrow character type (except char8_t).  */
   if (t == char_type_node
       || t == signed_char_type_node
       || t == unsigned_char_type_node)
@@ -4050,6 +4067,7 @@ c_get_ident (const char *id)
 void
 c_common_nodes_and_builtins (void)
 {
+  int char8_type_size;
   int char16_type_size;
   int char32_type_size;
   int wchar_type_size;
@@ -4341,6 +4359,22 @@ c_common_nodes_and_builtins (void)
   wchar_array_type_node
     = build_array_type (wchar_type_node, array_domain_type);
 
+  /* Define 'char8_t'.  */
+  char8_type_node = get_identifier (CHAR8_TYPE);
+  char8_type_node = TREE_TYPE (identifier_global_value (char8_type_node));
+  char8_type_size = TYPE_PRECISION (char8_type_node);
+  if (c_dialect_cxx ())
+    {
+      char8_type_node = make_unsigned_type (char8_type_size);
+
+      if (flag_char8_t)
+        record_builtin_type (RID_CHAR8, "char8_t", char8_type_node);
+    }
+
+  /* This is for UTF-8 string constants.  */
+  char8_array_type_node
+    = build_array_type (char8_type_node, array_domain_type);
+
   /* Define 'char16_t'.  */
   char16_type_node = get_identifier (CHAR16_TYPE);
   char16_type_node = TREE_TYPE (identifier_global_value (char16_type_node));
@@ -5138,6 +5172,8 @@ c_stddef_cpp_builtins(void)
   builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0);
   builtin_define_with_value ("__INTMAX_TYPE__", INTMAX_TYPE, 0);
   builtin_define_with_value ("__UINTMAX_TYPE__", UINTMAX_TYPE, 0);
+  if (flag_char8_t)
+    builtin_define_with_value ("__CHAR8_TYPE__", CHAR8_TYPE, 0);
   builtin_define_with_value ("__CHAR16_TYPE__", CHAR16_TYPE, 0);
   builtin_define_with_value ("__CHAR32_TYPE__", CHAR32_TYPE, 0);
   if (SIG_ATOMIC_TYPE)
@@ -7856,6 +7892,7 @@ keyword_begins_type_specifier (enum rid keyword)
     case RID_ACCUM:
     case RID_BOOL:
     case RID_WCHAR:
+    case RID_CHAR8:
     case RID_CHAR16:
     case RID_CHAR32:
     case RID_SAT:
index 9f790bc6a1485e45f3b5f2a9a36a6991fa75f75f..9fe90f32b163aaa4ec5e83475ea8912718deab08 100644 (file)
@@ -180,6 +180,9 @@ enum rid
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
+  /* char8_t */
+  RID_CHAR8,
+
   /* C++ concepts */
   RID_CONCEPT, RID_REQUIRES,
 
@@ -287,6 +290,7 @@ extern GTY ((length ("(int) RID_MAX"))) tree *ridpointers;
 
 enum c_tree_index
 {
+    CTI_CHAR8_TYPE,
     CTI_CHAR16_TYPE,
     CTI_CHAR32_TYPE,
     CTI_WCHAR_TYPE,
@@ -330,6 +334,7 @@ enum c_tree_index
     CTI_UINTPTR_TYPE,
 
     CTI_CHAR_ARRAY_TYPE,
+    CTI_CHAR8_ARRAY_TYPE,
     CTI_CHAR16_ARRAY_TYPE,
     CTI_CHAR32_ARRAY_TYPE,
     CTI_WCHAR_ARRAY_TYPE,
@@ -409,20 +414,22 @@ extern machine_mode c_default_pointer_mode;
    mask) is _true_.  Thus for keywords which are present in all
    languages the disable field is zero.  */
 
-#define D_CONLY                0x001   /* C only (not in C++).  */
-#define D_CXXONLY      0x002   /* C++ only (not in C).  */
-#define D_C99          0x004   /* In C, C99 only.  */
-#define D_CXX11         0x008  /* In C++, C++11 only.  */
-#define D_EXT          0x010   /* GCC extension.  */
-#define D_EXT89                0x020   /* GCC extension incorporated in C99.  */
-#define D_ASM          0x040   /* Disabled by -fno-asm.  */
-#define D_OBJC         0x080   /* In Objective C and neither C nor C++.  */
-#define D_CXX_OBJC     0x100   /* In Objective C, and C++, but not C.  */
-#define D_CXXWARN      0x200   /* In C warn with -Wcxx-compat.  */
-#define D_CXX_CONCEPTS  0x400   /* In C++, only with concepts. */
-#define D_TRANSMEM     0X800   /* C++ transactional memory TS.  */
+#define D_CONLY                0x0001  /* C only (not in C++).  */
+#define D_CXXONLY      0x0002  /* C++ only (not in C).  */
+#define D_C99          0x0004  /* In C, C99 only.  */
+#define D_CXX11         0x0008 /* In C++, C++11 only.  */
+#define D_EXT          0x0010  /* GCC extension.  */
+#define D_EXT89                0x0020  /* GCC extension incorporated in C99.  */
+#define D_ASM          0x0040  /* Disabled by -fno-asm.  */
+#define D_OBJC         0x0080  /* In Objective C and neither C nor C++.  */
+#define D_CXX_OBJC     0x0100  /* In Objective C, and C++, but not C.  */
+#define D_CXXWARN      0x0200  /* In C warn with -Wcxx-compat.  */
+#define D_CXX_CONCEPTS  0x0400 /* In C++, only with concepts.  */
+#define D_TRANSMEM     0X0800  /* C++ transactional memory TS.  */
+#define D_CXX_CHAR8_T  0X1000  /* In C++, only with -fchar8_t.  */
 
 #define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
+#define D_CXX_CHAR8_T_FLAGS D_CXXONLY | D_CXX_CHAR8_T
 
 /* The reserved keyword table.  */
 extern const struct c_common_resword c_common_reswords[];
@@ -430,6 +437,7 @@ extern const struct c_common_resword c_common_reswords[];
 /* The number of items in the reserved keyword table.  */
 extern const unsigned int num_c_common_reswords;
 
+#define char8_type_node                        c_global_trees[CTI_CHAR8_TYPE]
 #define char16_type_node               c_global_trees[CTI_CHAR16_TYPE]
 #define char32_type_node               c_global_trees[CTI_CHAR32_TYPE]
 #define wchar_type_node                        c_global_trees[CTI_WCHAR_TYPE]
@@ -475,6 +483,7 @@ extern const unsigned int num_c_common_reswords;
 #define truthvalue_false_node          c_global_trees[CTI_TRUTHVALUE_FALSE]
 
 #define char_array_type_node           c_global_trees[CTI_CHAR_ARRAY_TYPE]
+#define char8_array_type_node          c_global_trees[CTI_CHAR8_ARRAY_TYPE]
 #define char16_array_type_node         c_global_trees[CTI_CHAR16_ARRAY_TYPE]
 #define char32_array_type_node         c_global_trees[CTI_CHAR32_ARRAY_TYPE]
 #define wchar_array_type_node          c_global_trees[CTI_WCHAR_ARRAY_TYPE]
index 25b5c1a7406d7fbef3f645ac4cff91261e16e5f2..c9b63caeb2db186300f145051432f754e3d27485 100644 (file)
@@ -702,6 +702,9 @@ cpp_atomic_builtins (cpp_reader *pfile)
                        (have_swap[SWAP_INDEX (boolean_type_node)]? 2 : 1));
   builtin_define_with_int_value ("__GCC_ATOMIC_CHAR_LOCK_FREE", 
                        (have_swap[SWAP_INDEX (signed_char_type_node)]? 2 : 1));
+  if (flag_char8_t)
+    builtin_define_with_int_value ("__GCC_ATOMIC_CHAR8_T_LOCK_FREE",
+                       (have_swap[SWAP_INDEX (char8_type_node)]? 2 : 1));
   builtin_define_with_int_value ("__GCC_ATOMIC_CHAR16_T_LOCK_FREE", 
                        (have_swap[SWAP_INDEX (char16_type_node)]? 2 : 1));
   builtin_define_with_int_value ("__GCC_ATOMIC_CHAR32_T_LOCK_FREE", 
@@ -1000,6 +1003,8 @@ c_cpp_builtins (cpp_reader *pfile)
        cpp_define (pfile, "__cpp_template_template_args=201611");
       if (flag_threadsafe_statics)
        cpp_define (pfile, "__cpp_threadsafe_static_init=200806");
+      if (flag_char8_t)
+        cpp_define (pfile, "__cpp_char8_t=201811");
     }
   /* Note that we define this for C as well, so that we know if
      __attribute__((cleanup)) will interface with EH.  */
index d5ce9e9a032ff1b0020d10cd07bcc55b38952ecb..0a368a33a5839fedab872850d14e4fdf3268b457 100644 (file)
@@ -1281,9 +1281,14 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate)
     {
     default:
     case CPP_STRING:
-    case CPP_UTF8STRING:
       TREE_TYPE (value) = char_array_type_node;
       break;
+    case CPP_UTF8STRING:
+      if (flag_char8_t)
+        TREE_TYPE (value) = char8_array_type_node;
+      else
+        TREE_TYPE (value) = char_array_type_node;
+      break;
     case CPP_STRING16:
       TREE_TYPE (value) = char16_array_type_node;
       break;
@@ -1323,7 +1328,12 @@ lex_charconst (const cpp_token *token)
   else if (token->type == CPP_CHAR16)
     type = char16_type_node;
   else if (token->type == CPP_UTF8CHAR)
-    type = char_type_node;
+    {
+      if (flag_char8_t)
+        type = char8_type_node;
+      else
+        type = char_type_node;
+    }
   /* In C, a character constant has type 'int'.
      In C++ 'char', but multi-char charconsts have type 'int'.  */
   else if (!c_dialect_cxx () || chars_seen > 1)
index 2c22574b730fcabf0468ff11578a48513da8c026..9660f51867a5eab8fc7d60dd62cc20c5a6c7b415 100644 (file)
@@ -996,6 +996,10 @@ c_common_post_options (const char **pfilename)
   if (flag_sized_deallocation == -1)
     flag_sized_deallocation = (cxx_dialect >= cxx14);
 
+  /* char8_t support is new in C++2A.  */
+  if (flag_char8_t == -1)
+    flag_char8_t = (cxx_dialect >= cxx2a);
+
   if (flag_extern_tls_init)
     {
       if (!TARGET_SUPPORTS_ALIASES || !SUPPORTS_WEAK)
index d118e74ab07f40b6b14ed512552d08a2129a8924..858beff53d6dd2bc39e6fd42048eaabbcfa16db4 100644 (file)
@@ -1300,6 +1300,11 @@ fcanonical-system-headers
 C ObjC C++ ObjC++
 Where shorter, use canonicalized paths to systems headers.
 
+fchar8_t
+C++ ObjC++ Var(flag_char8_t) Init(-1)
+Enable the char8_t fundamental type and use it as the type for UTF-8 string
+and character literals.
+
 fcheck-pointer-bounds
 C ObjC C++ ObjC++ LTO Deprecated
 Deprecated in GCC 9.  This switch has no effect.
index 82412a789263d7b333a91b9da12f90260cd2324c..5d0ef1217bb105bed26428fae53d8ed245b5b23f 100644 (file)
@@ -1,3 +1,28 @@
+2019-01-14  Tom Honermann  <tom@honermann.net>
+
+       Implement P0482R5, char8_t: A type for UTF-8 characters and strings
+       * cvt.c (type_promotes_to): Handle char8_t promotion.
+       * decl.c (grokdeclarator): Handle invalid type specifier
+       combinations involving char8_t.
+       * lex.c (init_reswords): Add char8_t as a reserved word.
+       * mangle.c (write_builtin_type): Add name mangling for char8_t (Du).
+       * parser.c (cp_keyword_starts_decl_specifier_p)
+       (cp_parser_simple_type_specifier): Recognize char8_t as a simple
+       type specifier.
+       (cp_parser_string_literal): Use char8_array_type_node for the type
+       of CPP_UTF8STRING.
+       (cp_parser_set_decl_spec_type): Tolerate char8_t typedefs in system
+       headers.
+       * rtti.c (emit_support_tinfos): type_info support for char8_t.
+       * tree.c (char_type_p): Recognize char8_t as a character type.
+       * typeck.c (string_conv_p): Handle conversions of u8 string
+       literals of char8_t type.
+       (check_literal_operator_args): Handle UDLs with u8 string literals
+       of char8_t type.
+       * typeck2.c (ordinary_char_type_p): New.
+       (digest_init_r): Disallow initializing a char array with a u8 string
+       literal.
+
 2019-01-14  Martin Liska  <mliska@suse.cz>
 
        PR gcov-profile/88263
index 56489465c0c295452dfb53bef4e84ec6b70f638a..6a2004330d23d0ac5ac7a12efb45159fb6d55bab 100644 (file)
@@ -7488,6 +7488,7 @@ extern tree store_init_value                      (tree, tree, vec<tree, va_gc>**, int);
 extern tree split_nonconstant_init             (tree, tree);
 extern bool check_narrowing                    (tree, tree, tsubst_flags_t,
                                                 bool = false);
+extern bool ordinary_char_type_p               (tree);
 extern tree digest_init                                (tree, tree, tsubst_flags_t);
 extern tree digest_init_flags                  (tree, tree, int, tsubst_flags_t);
 extern tree digest_nsdmi_init                  (tree, tree, tsubst_flags_t);
index 449ce50d9e4ebed8ea1e64e49a5e26f7c4c07d8f..9142811939809e6604ae66a49a8bf4342a7fe694 100644 (file)
@@ -1877,6 +1877,7 @@ type_promotes_to (tree type)
      wider.  Scoped enums don't promote, but pretend they do for backward
      ABI bug compatibility wrt varargs.  */
   else if (TREE_CODE (type) == ENUMERAL_TYPE
+          || type == char8_type_node
           || type == char16_type_node
           || type == char32_type_node
           || type == wchar_type_node)
index 6e75c3d3d93a29ff4cf0d145849571eb179e2000..41972aa09553ae2846dfc78f8eeb8f7db363ec29 100644 (file)
@@ -10770,7 +10770,9 @@ grokdeclarator (const cp_declarator *declarator,
          error_at (&richloc, "%<long%> and %<short%> specified together");
        }
       else if (TREE_CODE (type) != INTEGER_TYPE
-              || type == char16_type_node || type == char32_type_node
+              || type == char8_type_node
+              || type == char16_type_node
+              || type == char32_type_node
               || ((long_p || short_p)
                   && (explicit_char || explicit_intN)))
        error_at (loc, "%qs specified with %qT", key, type);
index 36ffa37e0378ea262ec921ac6559a9ab92bb8856..369ecc05df2b2fe69877f9f3accdbaa05f9f89f3 100644 (file)
@@ -233,6 +233,8 @@ init_reswords (void)
     mask |= D_CXX_CONCEPTS;
   if (!flag_tm)
     mask |= D_TRANSMEM;
+  if (!flag_char8_t)
+    mask |= D_CXX_CHAR8_T;
   if (flag_no_asm)
     mask |= D_ASM | D_EXT;
   if (flag_no_gnu_keywords)
index 919f7b3f2fb33db03f423738e129bf07603714d3..00bde4ee59a5cae1b7b87cad83db4c92fefde301 100644 (file)
@@ -2473,10 +2473,12 @@ write_builtin_type (tree type)
       break;
 
     case INTEGER_TYPE:
-      /* TYPE may still be wchar_t, char16_t, or char32_t, since that
+      /* TYPE may still be wchar_t, char8_t, char16_t, or char32_t, since that
         isn't in integer_type_nodes.  */
       if (type == wchar_type_node)
        write_char ('w');
+      else if (type == char8_type_node)
+       write_string ("Du");
       else if (type == char16_type_node)
        write_string ("Ds");
       else if (type == char32_type_node)
index be669f2f321422c0f36503bf55dedbe98faef3ef..7d7b02926502135f6c7035a1ad5e616940f609ed 100644 (file)
@@ -948,6 +948,7 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_TYPENAME:
       /* Simple type specifiers.  */
     case RID_CHAR:
+    case RID_CHAR8:
     case RID_CHAR16:
     case RID_CHAR32:
     case RID_WCHAR:
@@ -4235,9 +4236,14 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
        {
        default:
        case CPP_STRING:
-       case CPP_UTF8STRING:
          TREE_TYPE (value) = char_array_type_node;
          break;
+       case CPP_UTF8STRING:
+         if (flag_char8_t)
+           TREE_TYPE (value) = char8_array_type_node;
+         else
+           TREE_TYPE (value) = char_array_type_node;
+         break;
        case CPP_STRING16:
          TREE_TYPE (value) = char16_array_type_node;
          break;
@@ -17504,6 +17510,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
        decl_specs->explicit_char_p = true;
       type = char_type_node;
       break;
+    case RID_CHAR8:
+      type = char8_type_node;
+      break;
     case RID_CHAR16:
       type = char16_type_node;
       break;
@@ -28919,14 +28928,15 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
 {
   decl_specs->any_specifiers_p = true;
 
-  /* If the user tries to redeclare bool, char16_t, char32_t, or wchar_t
-     (with, for example, in "typedef int wchar_t;") we remember that
+  /* If the user tries to redeclare bool, char8_t, char16_t, char32_t, or
+     wchar_t (with, for example, in "typedef int wchar_t;") we remember that
      this is what happened.  In system headers, we ignore these
      declarations so that G++ can work with system headers that are not
      C++-safe.  */
   if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef)
       && !type_definition_p
       && (type_spec == boolean_type_node
+         || type_spec == char8_type_node
          || type_spec == char16_type_node
          || type_spec == char32_type_node
          || type_spec == wchar_type_node)
index a6d32b914a782bf686b9be4dc184b0478db8a481..c4aabea70038575e2b6eadf1ff42ffce5087badd 100644 (file)
@@ -1539,7 +1539,7 @@ emit_support_tinfos (void)
   {
     &void_type_node,
     &boolean_type_node,
-    &wchar_type_node, &char16_type_node, &char32_type_node,
+    &wchar_type_node, &char8_type_node, &char16_type_node, &char32_type_node,
     &char_type_node, &signed_char_type_node, &unsigned_char_type_node,
     &short_integer_type_node, &short_unsigned_type_node,
     &integer_type_node, &unsigned_type_node,
index 4db89a4e5a65980165e03cf65763f7973cf1ff63..50002161500577c3319a63f2bfb23c4ffc28ceff 100644 (file)
@@ -5022,6 +5022,7 @@ char_type_p (tree type)
   return (same_type_p (type, char_type_node)
          || same_type_p (type, unsigned_char_type_node)
          || same_type_p (type, signed_char_type_node)
+         || same_type_p (type, char8_type_node)
          || same_type_p (type, char16_type_node)
          || same_type_p (type, char32_type_node)
          || same_type_p (type, wchar_type_node));
index 43d2899a3c4ddb08df15f15cc07f952aef2fe125..88e2cd6ab9bcff2367f3d9e3d4556088de06b119 100644 (file)
@@ -2216,6 +2216,7 @@ string_conv_p (const_tree totype, const_tree exp, int warn)
 
   t = TREE_TYPE (totype);
   if (!same_type_p (t, char_type_node)
+      && !same_type_p (t, char8_type_node)
       && !same_type_p (t, char16_type_node)
       && !same_type_p (t, char32_type_node)
       && !same_type_p (t, wchar_type_node))
@@ -10288,6 +10289,7 @@ check_literal_operator_args (const_tree decl,
              t = TYPE_MAIN_VARIANT (t);
              if ((maybe_raw_p = same_type_p (t, char_type_node))
                  || same_type_p (t, wchar_type_node)
+                 || same_type_p (t, char8_type_node)
                  || same_type_p (t, char16_type_node)
                  || same_type_p (t, char32_type_node))
                {
@@ -10320,6 +10322,8 @@ check_literal_operator_args (const_tree decl,
            max_arity = 1;
          else if (same_type_p (t, wchar_type_node))
            max_arity = 1;
+         else if (same_type_p (t, char8_type_node))
+           max_arity = 1;
          else if (same_type_p (t, char16_type_node))
            max_arity = 1;
          else if (same_type_p (t, char32_type_node))
index ecc313b2355f0cef1ae0e55f20203a4dbad08e7a..cd4313295d5816cf4caf95d2e1489af178be15ab 100644 (file)
@@ -1026,6 +1026,17 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain, bool const_only)
   return ok;
 }
 
+/* True iff TYPE is a C++2a "ordinary" character type.  */
+
+bool
+ordinary_char_type_p (tree type)
+{
+  type = TYPE_MAIN_VARIANT (type);
+  return (type == char_type_node
+         || type == signed_char_type_node
+         || type == unsigned_char_type_node);
+}
+
 /* Process the initializer INIT for a variable of type TYPE, emitting
    diagnostics for invalid initializers and converting the initializer as
    appropriate.
@@ -1091,36 +1102,30 @@ digest_init_r (tree type, tree init, int nested, int flags,
          && TREE_CODE (stripped_init) == STRING_CST)
        {
          tree char_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+         bool incompat_string_cst = false;
 
-         if (TYPE_PRECISION (typ1) == BITS_PER_UNIT)
+         if (typ1 != char_type)
            {
-             if (char_type != char_type_node
-                 && char_type != signed_char_type_node
-                 && char_type != unsigned_char_type_node)
-               {
-                 if (complain & tf_error)
-                   error_at (loc, "char-array initialized from wide string");
-                 return error_mark_node;
-               }
+             /* The array element type does not match the initializing string
+                literal element type; this is only allowed when both types are
+                ordinary character type.  There are no string literals of
+                signed or unsigned char type in the language, but we can get
+                them internally from converting braced-init-lists to
+                STRING_CST.  */
+             if (ordinary_char_type_p (typ1)
+                 && ordinary_char_type_p (char_type))
+               /* OK */;
+             else
+               incompat_string_cst = true;
            }
-         else
+
+         if (incompat_string_cst)
            {
-             if (char_type == char_type_node
-                 || char_type == signed_char_type_node
-                 || char_type == unsigned_char_type_node)
-               {
-                 if (complain & tf_error)
-                   error_at (loc,
-                             "int-array initialized from non-wide string");
-                 return error_mark_node;
-               }
-             else if (char_type != typ1)
-               {
-                 if (complain & tf_error)
-                   error_at (loc, "int-array initialized from incompatible "
-                             "wide string");
-                 return error_mark_node;
-               }
+             if (complain & tf_error)
+               error_at (loc, "cannot initialize array of %qT from "
+                         "a string literal with type array of %qT",
+                         typ1, char_type);
+             return error_mark_node;
            }
 
          if (nested == 2 && !TYPE_DOMAIN (type))
index 2a1a5b8d1dfcd9f58826dd91b8fcd4f99109ba3f..b7534256119bd7834f2fa9d5f32863822d3b393a 100644 (file)
@@ -583,6 +583,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    affect C++ name mangling because in C++ these are distinct types
    not typedefs.  */
 
+#ifndef CHAR8_TYPE
+#define CHAR8_TYPE "unsigned char"
+#endif
+
 #ifdef UINT_LEAST16_TYPE
 #define CHAR16_TYPE UINT_LEAST16_TYPE
 #else
index 5ed1d1334206978cc610ffb00aad7d6e81301ee8..1151708aaf083788aa9c5830cdb93f55b3d888e7 100644 (file)
@@ -206,7 +206,7 @@ in the following sections.
 @item C++ Language Options
 @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
 @gccoptlist{-fabi-version=@var{n}  -fno-access-control @gol
--faligned-new=@var{n}  -fargs-in-order=@var{n}  -fcheck-new @gol
+-faligned-new=@var{n}  -fargs-in-order=@var{n}  -fchar8_t  -fcheck-new @gol
 -fconstexpr-depth=@var{n}  -fconstexpr-loop-limit=@var{n} @gol
 -fno-elide-constructors @gol
 -fno-enforce-eh-specs @gol
@@ -2426,6 +2426,60 @@ but few users will need to override the default of
 
 This flag is enabled by default for @option{-std=c++17}.
 
+@item -fchar8_t
+@itemx -fno-char8_t
+@opindex fchar8_t
+@opindex fno-char8_t
+Enable support for @code{char8_t} as adopted for C++2a.  This includes
+the addition of a new @code{char8_t} fundamental type, changes to the
+types of UTF-8 string and character literals, new signatures for
+user-defined literals, associated standard library updates, and new
+@code{__cpp_char8_t} and @code{__cpp_lib_char8_t} feature test macros.
+
+This option enables functions to be overloaded for ordinary and UTF-8
+strings:
+
+@smallexample
+int f(const char *);    // #1
+int f(const char8_t *); // #2
+int v1 = f("text");     // Calls #1
+int v2 = f(u8"text");   // Calls #2
+@end smallexample
+
+@noindent
+and introduces new signatures for user-defined literals:
+
+@smallexample
+int operator""_udl1(char8_t);
+int v3 = u8'x'_udl1;
+int operator""_udl2(const char8_t*, std::size_t);
+int v4 = u8"text"_udl2;
+template<typename T, T...> int operator""_udl3();
+int v5 = u8"text"_udl3;
+@end smallexample
+
+@noindent
+The change to the types of UTF-8 string and character literals introduces
+incompatibilities with ISO C++11 and later standards.  For example, the
+following code is well-formed under ISO C++11, but is ill-formed when
+@option{-fchar8_t} is specified.
+
+@smallexample
+char ca[] = u8"xx";     // error: char-array initialized from wide
+                        //        string
+const char *cp = u8"xx";// error: invalid conversion from
+                        //        `const char8_t*' to `const char*'
+int f(const char*);
+auto v = f(u8"xx");     // error: invalid conversion from
+                        //        `const char8_t*' to `const char*'
+std::string s@{u8"xx"@};  // error: no matching function for call to
+                        //        `std::basic_string<char>::basic_string()'
+using namespace std::literals;
+s = u8"xx"s;            // error: conversion from
+                        //        `basic_string<char8_t>' to non-scalar
+                        //        type `basic_string<char>' requested
+@end smallexample
+
 @item -fcheck-new
 @opindex fcheck-new
 Check that the pointer returned by @code{operator new} is non-null
index 1b37405cee9cfd7e7a6e3530d9667f7e8acb85a4..fa11edaa7aab28acfc509525849be8a60d86c309 100644 (file)
@@ -62,6 +62,47 @@ const char s16[] = R"??(??)??";
 const char s17[] = R"?(?)??)?";
 const char s18[] = R"??(??)??)??)??";
 
+const char u800[] = u8R"??=??(??<??>??)??'??!??-\
+(a)#[{}]^|~";
+)??=??";
+const char u801[] = u8R"a(
+)\
+a"
+)a";
+const char u802[] = u8R"a(
+)a\
+"
+)a";
+const char u803[] = u8R"ab(
+)a\
+b"
+)ab";
+const char u804[] = u8R"a??/(x)a??/";
+const char u805[] = u8R"abcdefghijklmn??(abc)abcdefghijklmn??";
+const char u806[] = u8R"abcdefghijklm??/(abc)abcdefghijklm??/";
+const char u807[] = u8R"abc(??)\
+abc";)abc";
+const char u808[] = u8R"def(de)\
+def";)def";
+const char u809[] = u8R"a(??)\
+a"
+)a";
+const char u810[] = u8R"a(??)a\
+"
+)a";
+const char u811[] = u8R"ab(??)a\
+b"
+)ab";
+const char u812[] = u8R"a#(a#)a??=)a#";
+const char u813[] = u8R"a#(??)a??=??)a#";
+const char u814[] = u8R"??/(x)??/
+";)??/";
+const char u815[] = u8R"??/(??)??/
+";)??/";
+const char u816[] = u8R"??(??)??";
+const char u817[] = u8R"?(?)??)?";
+const char u818[] = u8R"??(??)??)??)??";
+
 const char16_t u00[] = uR"??=??(??<??>??)??'??!??-\
 (a)#[{}]^|~";
 )??=??";
@@ -211,6 +252,25 @@ main (void)
   TEST (s16, "??");
   TEST (s17, "?)??");
   TEST (s18, "??"")??"")??");
+  TEST (u800, u8"??""<??"">??"")??""'??""!??""-\\\n(a)#[{}]^|~\";\n");
+  TEST (u801, u8"\n)\\\na\"\n");
+  TEST (u802, u8"\n)a\\\n\"\n");
+  TEST (u803, u8"\n)a\\\nb\"\n");
+  TEST (u804, u8"x");
+  TEST (u805, u8"abc");
+  TEST (u806, u8"abc");
+  TEST (u807, u8"??"")\\\nabc\";");
+  TEST (u808, u8"de)\\\ndef\";");
+  TEST (u809, u8"??"")\\\na\"\n");
+  TEST (u810, u8"??"")a\\\n\"\n");
+  TEST (u811, u8"??"")a\\\nb\"\n");
+  TEST (u812, u8"a#)a??""=");
+  TEST (u813, u8"??"")a??""=??");
+  TEST (u814, u8"x)??""/\n\";");
+  TEST (u815, u8"??"")??""/\n\";");
+  TEST (u816, u8"??");
+  TEST (u817, u8"?)??");
+  TEST (u818, u8"??"")??"")??");
   TEST (u00, u"??""<??"">??"")??""'??""!??""-\\\n(a)#[{}]^|~\";\n");
   TEST (u01, u"\n)\\\na\"\n");
   TEST (u02, u"\n)a\\\n\"\n");
index 9dfdaabd87df9af037f76bcd1295d9d19e2badad..1d101dc8393534494913e4e77fd90cd8b1c9f6d0 100644 (file)
@@ -62,6 +62,47 @@ const char s16[] = R"??(??)??";
 const char s17[] = R"?(?)??)?";
 const char s18[] = R"??(??)??)??)??";
 
+const char u800[] = u8R"??=??(??<??>??)??'??!??-\
+(a)#[{}]^|~";
+)??=??";
+const char u801[] = u8R"a(
+)\
+a"
+)a";
+const char u802[] = u8R"a(
+)a\
+"
+)a";
+const char u803[] = u8R"ab(
+)a\
+b"
+)ab";
+const char u804[] = u8R"a??/(x)a??/";
+const char u805[] = u8R"abcdefghijklmn??(abc)abcdefghijklmn??";
+const char u806[] = u8R"abcdefghijklm??/(abc)abcdefghijklm??/";
+const char u807[] = u8R"abc(??)\
+abc";)abc";
+const char u808[] = u8R"def(de)\
+def";)def";
+const char u809[] = u8R"a(??)\
+a"
+)a";
+const char u810[] = u8R"a(??)a\
+"
+)a";
+const char u811[] = u8R"ab(??)a\
+b"
+)ab";
+const char u812[] = u8R"a#(a#)a??=)a#";
+const char u813[] = u8R"a#(??)a??=??)a#";
+const char u814[] = u8R"??/(x)??/
+";)??/";
+const char u815[] = u8R"??/(??)??/
+";)??/";
+const char u816[] = u8R"??(??)??";
+const char u817[] = u8R"?(?)??)?";
+const char u818[] = u8R"??(??)??)??)??";
+
 const char16_t u00[] = uR"??=??(??<??>??)??'??!??-\
 (a)#[{}]^|~";
 )??=??";
@@ -211,6 +252,25 @@ main (void)
   TEST (s16, "??");
   TEST (s17, "?)??");
   TEST (s18, "??"")??"")??");
+  TEST (u800, u8"??""<??"">??"")??""'??""!??""-\\\n(a)#[{}]^|~\";\n");
+  TEST (u801, u8"\n)\\\na\"\n");
+  TEST (u802, u8"\n)a\\\n\"\n");
+  TEST (u803, u8"\n)a\\\nb\"\n");
+  TEST (u804, u8"x");
+  TEST (u805, u8"abc");
+  TEST (u806, u8"abc");
+  TEST (u807, u8"??"")\\\nabc\";");
+  TEST (u808, u8"de)\\\ndef\";");
+  TEST (u809, u8"??"")\\\na\"\n");
+  TEST (u810, u8"??"")a\\\n\"\n");
+  TEST (u811, u8"??"")a\\\nb\"\n");
+  TEST (u812, u8"a#)a??""=");
+  TEST (u813, u8"??"")a??""=??");
+  TEST (u814, u8"x)??""/\n\";");
+  TEST (u815, u8"??"")??""/\n\";");
+  TEST (u816, u8"??");
+  TEST (u817, u8"?)??");
+  TEST (u818, u8"??"")??"")??");
   TEST (u00, u"??""<??"">??"")??""'??""!??""-\\\n(a)#[{}]^|~\";\n");
   TEST (u01, u"\n)\\\na\"\n");
   TEST (u02, u"\n)a\\\n\"\n");
index 4055e0ee8ecaaa6d1bcba041466b74625b2dcafa..b878918a9f3a44e11bbddc7eaed5bd0f0f7815b0 100644 (file)
@@ -4,3 +4,4 @@
 constexpr wchar_t c1 = L"hi"[3];       // { dg-error "array subscript" }
 constexpr char16_t c2 = u"hi"[3];      // { dg-error "array subscript" }
 constexpr char32_t c3 = U"hi"[3];      // { dg-error "array subscript" }
+constexpr char c4 = u8"hi"[3];         // { dg-error "array subscript" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg-char8_t.C b/gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg-char8_t.C
new file mode 100644 (file)
index 0000000..b917b5f
--- /dev/null
@@ -0,0 +1,81 @@
+// { dg-options "-std=c++17 -fchar8_t" }
+
+#include <cstdint>
+
+int operator"" _bar (long double);
+
+double operator"" _foo (long long unsigned);
+
+int i = 12_bar; // { dg-error "unable to find numeric literal operator|with|argument" }
+
+double d = 1.2_foo; // { dg-error "unable to find numeric literal operator|with|argument" }
+
+int operator"" _char(char);
+
+int operator"" _char8_t(char8_t);
+
+int operator"" _wchar_t(wchar_t);
+
+int operator"" _char16_t(char16_t);
+
+int operator"" _char32_t(char32_t);
+
+int cwcx = 'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" }
+int cc8  = 'c'_char8_t; // { dg-error "unable to find character literal operator|with|argument" }
+int cc16 = 'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" }
+int cc32 = 'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int wccx = L'c'_char; // { dg-error "unable to find character literal operator|with|argument" }
+int wcc8 = L'c'_char8_t; // { dg-error "unable to find character literal operator|with|argument" }
+int wcc16 = L'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" }
+int wcc32 = L'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int c8c  = u8'c'_char; // { dg-error "unable to find character literal operator|with|argument" }
+int c8wc = u8'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" }
+int c8c16 = u8'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" }
+int c8c32 = u8'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int c16c = u'c'_char; // { dg-error "unable to find character literal operator|with|argument" }
+int c16c8 = u'c'_char8_t; // { dg-error "unable to find character literal operator|with|argument" }
+int c16wc = u'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" }
+int c16c32 = u'c'_char32_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int c32c = U'c'_char; // { dg-error "unable to find character literal operator|with|argument" }
+int c32c8 = U'c'_char8_t; // { dg-error "unable to find character literal operator|with|argument" }
+int c32wc = U'c'_wchar_t; // { dg-error "unable to find character literal operator|with|argument" }
+int c32c16 = U'c'_char16_t; // { dg-error "unable to find character literal operator|with|argument" }
+
+int operator"" _char_str(const char*, std::size_t);
+
+int operator"" _wchar_t_str(const wchar_t*, std::size_t);
+
+int operator"" _char8_t_str(const char8_t*, std::size_t);
+
+int operator"" _char16_t_str(const char16_t*, std::size_t);
+
+int operator"" _char32_t_str(const char32_t*, std::size_t);
+
+int strwstr = "str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int strstr8 = "str"_char8_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int strstr16 = "str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int strstr32 = "str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+
+int str8str = u8"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str8wstr = u8"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str8str16 = u8"str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str8str32 = u8"str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+
+int wstrstr = L"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int wstrstr8 = L"str"_char8_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int wstrstr16 = L"str"_char16_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int wstrstr32 = L"str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+
+int str16str = u"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str16wstr = u"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str16str8 = u"str"_char8_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str16str32 = u"str"_char32_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+
+int str32str = U"str"_char_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str32wstr = U"str"_wchar_t_str; // { dg-error "unable to find string literal operator|with|arguments" }
+int str32str8 = U"str"_char8_t_str; // { dg-error "unable to find string literal operator string operator|with|arguments" }
+int str32str16 = U"str"_char16_t_str; // { dg-error "unable to find string literal operator string operator|with|arguments" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-resolve-char8_t.C b/gcc/testsuite/g++.dg/cpp0x/udlit-resolve-char8_t.C
new file mode 100644 (file)
index 0000000..19cbd51
--- /dev/null
@@ -0,0 +1,38 @@
+// { dg-options "-std=c++17 -fchar8_t" }
+
+#include <cstdint>
+#include <cassert>
+
+int operator"" _foo(const char*)                  { return 0; }
+int operator"" _foo(unsigned long long int)       { return 1; }
+int operator"" _foo(long double)                  { return 2; }
+int operator"" _foo(char)                         { return 3; }
+int operator"" _foo(wchar_t)                      { return 4; }
+int operator"" _foo(char8_t)                      { return 5; }
+int operator"" _foo(char16_t)                     { return 6; }
+int operator"" _foo(char32_t)                     { return 7; }
+int operator"" _foo(const char*, std::size_t)     { return 8; }
+int operator"" _foo(const wchar_t*, std::size_t)  { return 9; }
+int operator"" _foo(const char8_t*, std::size_t)  { return 10; }
+int operator"" _foo(const char16_t*, std::size_t) { return 11; }
+int operator"" _foo(const char32_t*, std::size_t) { return 12; }
+template<char...> int operator"" _foo2()          { return 20; }
+int operator"" _foo2(unsigned long long int)      { return 21; }
+
+int
+main()
+{
+  assert(123_foo == 1);
+  assert(0.123_foo == 2);
+  assert('c'_foo == 3);
+  assert(L'c'_foo == 4);
+  assert(u8'c'_foo == 5);
+  assert(u'c'_foo == 6);
+  assert(U'c'_foo == 7);
+  assert("abc"_foo == 8);
+  assert(L"abc"_foo == 9);
+  assert(u8"abc"_foo == 10);
+  assert(u"abc"_foo == 11);
+  assert(U"abc"_foo == 12);
+  assert(123_foo2 == 21);
+}
index acfda45d5fec6c56e63bafff29e36bed4fd5319e..c76b0af9a2879e0ca433cbca544a1bca2018b206 100644 (file)
@@ -9,6 +9,14 @@ operator"" _len(const char*, size_type len)
   return len;
 }
 
+#if __cpp_char8_t
+constexpr size_type
+operator"" _len(const char8_t*, size_type len)
+{
+  return len;
+}
+#endif
+
 constexpr size_type
 operator"" _len(const wchar_t*, size_type len)
 {
index 734a0f38ad062e4d2ca789091e1eb31de647bf12..ab65dd08714a6741dc9769455fefee7d96885c81 100644 (file)
@@ -7,7 +7,9 @@
 using namespace my_string_literals;
 
 decltype("Hello, World!"s) s;
+#if !__cpp_char8_t == !__cpp_lib_char8_t
 decltype(u8"Hello, World!"s) s8;
+#endif
 decltype(L"Hello, World!"s) ws;
 decltype(u"Hello, World!"s) s16;
 decltype(U"Hello, World!"s) s32;
index e61034ec4ef5e807f816ee2fa69b150b708253ec..c8725fa9f462fdc7b2ba516172ff4c395392623f 100644 (file)
@@ -8,6 +8,12 @@ inline namespace my_string_literals
   operator"" s(const char* str, std::size_t len)
   { return std::string{str, len}; }
 
+#if __cpp_lib_char8_t
+  std::u8string
+  operator"" s(const char8_t* str, std::size_t len)
+  { return std::u8string{str, len}; }
+#endif
+
   std::wstring
   operator"" s(const wchar_t* str, std::size_t len)
   { return std::wstring{str, len}; }
index 0e92196383522afe863f3354f6ceca076dffe2c6..093e32345cdbe086689792cc383d0a419aab60d0 100644 (file)
@@ -1,7 +1,9 @@
 // { dg-do compile { target c++17 } }
 
+typedef decltype(u8'c') u8_char_t;
+
 constexpr int
-operator""_foo(char c)
+operator""_foo(u8_char_t c)
 { return c * 100; }
 
 auto cc = u8'8'_foo;
index e08fbb9c86e5b6486a667a554022d6a20781bbc2..ed413f30976c124afbcfaa8ae0fb2d87da1d508d 100644 (file)
@@ -6,7 +6,11 @@
 auto c = 'c';
 auto u8c = u8'c';
 
+#if __cpp_char8_t
+static_assert(!std::experimental::is_same_v<decltype(u8c), decltype(c)>, "");
+#else
 static_assert(std::experimental::is_same_v<decltype(u8c), decltype(c)>, "");
+#endif
 
 auto u8s = u8"c";
 auto x = u8s[0];
diff --git a/gcc/testsuite/g++.dg/cpp2a/char8_t1.C b/gcc/testsuite/g++.dg/cpp2a/char8_t1.C
new file mode 100644 (file)
index 0000000..aa0860b
--- /dev/null
@@ -0,0 +1,5 @@
+// P0482R6
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+char8_t c8;
diff --git a/gcc/testsuite/g++.dg/cpp2a/char8_t2.C b/gcc/testsuite/g++.dg/cpp2a/char8_t2.C
new file mode 100644 (file)
index 0000000..71eea79
--- /dev/null
@@ -0,0 +1,5 @@
+// P0482R6
+// { dg-do compile }
+// { dg-options "-std=c++2a -fno-char8_t" }
+
+char8_t c8; // { dg-error "does not name a type" }
index b80cc34236468ca72fc50cbaf432f6d5cacbbe00..8e1ea48bb1d6d9039e4c824e78a15af3e719fc4e 100644 (file)
 #else
 #  error "__has_cpp_attribute"
 #endif
+
+// C++2A features:
+
+#ifndef __cpp_char8_t
+#  error "__cpp_char8_t"
+#elif __cpp_char8_t != 201811
+#  error "__cpp_char8_t != 201811"
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-aliasing-1.C b/gcc/testsuite/g++.dg/ext/char8_t-aliasing-1.C
new file mode 100644 (file)
index 0000000..9252ef9
--- /dev/null
@@ -0,0 +1,8 @@
+// Test that char8_t does not alias with other types when -fchar8_t is enabled.
+// { dg-do compile }
+// { dg-options "-fstrict-aliasing -Wstrict-aliasing=1 -fchar8_t" }
+
+extern long l;
+char8_t* f() {
+  return (char8_t*)&l; // { dg-warning "dereferencing type-punned pointer might break strict-aliasing rules" "char8_t" }
+}
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C
new file mode 100644 (file)
index 0000000..8ed85cc
--- /dev/null
@@ -0,0 +1,12 @@
+// Test that UTF-8 character literals have type char if -fchar8_t is not enabled.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fno-char8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+static_assert(is_same<decltype(u8'x'), char>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C
new file mode 100644 (file)
index 0000000..7861736
--- /dev/null
@@ -0,0 +1,12 @@
+// Test that UTF-8 character literals have type char8_t if -fchar8_t is enabled.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fchar8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+static_assert(is_same<decltype(u8'x'), char8_t>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-deduction-1.C b/gcc/testsuite/g++.dg/ext/char8_t-deduction-1.C
new file mode 100644 (file)
index 0000000..27f19fe
--- /dev/null
@@ -0,0 +1,30 @@
+// Test that char is deduced for UTF-8 character and string literals when
+// -fchar8_t is not in effect.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fno-char8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+template<typename T1, typename T2, typename T3>
+void ft(T1, T2, T3 &) {
+  static_assert(is_same<T1, char>::value, "Error");
+  static_assert(is_same<T2, const char*>::value, "Error");
+  static_assert(is_same<T3, const char[2]>::value, "Error");
+}
+
+auto x = (ft(u8'x', u8"x", u8"x"),0);
+
+auto c8 = u8'x';
+static_assert(is_same<decltype(c8), char>::value, "Error");
+
+auto c8p = u8"x";
+static_assert(is_same<decltype(c8p), const char*>::value, "Error");
+
+auto &c8a = u8"x";
+static_assert(is_same<decltype(c8a), const char(&)[2]>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-deduction-2.C b/gcc/testsuite/g++.dg/ext/char8_t-deduction-2.C
new file mode 100644 (file)
index 0000000..1daf296
--- /dev/null
@@ -0,0 +1,30 @@
+// Test that char8_t is deduced for UTF-8 character and string literals when
+// -fchar8_t is in effect.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fchar8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+template<typename T1, typename T2, typename T3>
+void ft(T1, T2, T3 &) {
+  static_assert(is_same<T1, char8_t>::value, "Error");
+  static_assert(is_same<T2, const char8_t*>::value, "Error");
+  static_assert(is_same<T3, const char8_t[2]>::value, "Error");
+}
+
+auto x = (ft(u8'x', u8"x", u8"x"),0);
+
+auto c8 = u8'x';
+static_assert(is_same<decltype(c8), char8_t>::value, "Error");
+
+auto c8p = u8"x";
+static_assert(is_same<decltype(c8p), const char8_t*>::value, "Error");
+
+auto &c8a = u8"x";
+static_assert(is_same<decltype(c8a), const char8_t(&)[2]>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-1.C b/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-1.C
new file mode 100644 (file)
index 0000000..6107cb6
--- /dev/null
@@ -0,0 +1,8 @@
+// Test that predefined feature test macros are not present when -fchar8_t is
+// not enabled.
+// { dg-do compile }
+// { dg-options "-fno-char8_t" }
+
+#if defined(__cpp_char8_t)
+#error __cpp_char8_t is defined!
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C b/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C
new file mode 100644 (file)
index 0000000..df1063f
--- /dev/null
@@ -0,0 +1,10 @@
+// Test that predefined feature test macros are present when -fchar8_t is
+// enabled.
+// { dg-do compile }
+// { dg-options "-fchar8_t" }
+
+#if !defined(__cpp_char8_t)
+#  error __cpp_char8_t is not defined!
+#elif __cpp_char8_t != 201811
+#  error __cpp_char8_t != 201811
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-init-1.C b/gcc/testsuite/g++.dg/ext/char8_t-init-1.C
new file mode 100644 (file)
index 0000000..e2fd67b
--- /dev/null
@@ -0,0 +1,21 @@
+// Test initialization from UTF-8 literals when -fchar8_t is not enabled.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fno-char8_t" }
+
+char c1 = 'x';
+char c2 = u8'x';
+
+const char *pc1 = "x";
+const char *pc2 = u8"x";
+
+const char (&rca1)[2] = "x";
+const char (&rca2)[2] = u8"x";
+
+char ca1[] = "x";
+char ca2[] = u8"x";
+
+signed char sca1[] = "x";
+signed char sca2[] = u8"x";
+
+unsigned char uca1[] = "x";
+unsigned char uca2[] = u8"x";
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-init-2.C b/gcc/testsuite/g++.dg/ext/char8_t-init-2.C
new file mode 100644 (file)
index 0000000..c713bc1
--- /dev/null
@@ -0,0 +1,33 @@
+// Test initialization from UTF-8 literals when -fchar8_t is enabled.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fchar8_t" }
+
+char c1 = 'x';
+char c2 = u8'x';
+char8_t c3 = 'x';
+char8_t c4 = u8'x';
+char8_t c5 = u'x';
+
+const char *pc1 = "x";
+const char *pc2 = u8"x"; // { dg-error "invalid conversion from .const char8_t.. to .const char.." "char8_t" }
+const char8_t *pc3 = "x"; // { dg-error "invalid conversion from .const char.. to .const char8_t.." "char8_t" }
+const char8_t *pc4 = u8"x";
+const char8_t *pc5 = u"x"; // { dg-error "cannot convert .const char16_t.. to .const char8_t.. in initialization" "char8_t" }
+
+const char (&rca1)[2] = "x";
+const char (&rca2)[2] = u8"x"; // { dg-error "invalid initialization of reference of type .const char ....... from expression of type .const char8_t ...." "char8_t" }
+const char8_t (&rca3)[2] = "x"; // { dg-error "invalid initialization of reference of type .const char8_t ....... from expression of type .const char ...." "char8_t" }
+const char8_t (&rca4)[2] = u8"x";
+const char8_t (&rca5)[2] = u"x"; // { dg-error "invalid initialization of reference of type .const char8_t ....... from expression of type .const char16_t ...." "char8_t" }
+
+char ca1[] = "x";
+char ca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" }
+char8_t ca3[] = "x"; // { dg-error "from a string literal with type array of .char." "char8_t" }
+char8_t ca4[] = u8"x";
+char8_t ca5[] = u"x"; // { dg-error "from a string literal with type array of .char16_t." "char8_t" }
+
+signed char sca1[] = "x";
+signed char sca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" }
+
+unsigned char uca1[] = "x";
+unsigned char uca2[] = u8"x"; // { dg-error "from a string literal with type array of .char8_t." "char8_t" }
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-keyword-1.C b/gcc/testsuite/g++.dg/ext/char8_t-keyword-1.C
new file mode 100644 (file)
index 0000000..f247509
--- /dev/null
@@ -0,0 +1,5 @@
+// Test that char8_t is not a keyword if -fchar8_t is not enabled.
+// { dg-do compile }
+// { dg-options "-fno-char8_t" }
+
+int char8_t;
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-keyword-2.C b/gcc/testsuite/g++.dg/ext/char8_t-keyword-2.C
new file mode 100644 (file)
index 0000000..8c84e1e
--- /dev/null
@@ -0,0 +1,5 @@
+// Test that char8_t is recognized as a keyword if -fchar8_t is enabled.
+// { dg-do compile }
+// { dg-options "-fchar8_t" }
+
+int char8_t; /* { dg-error "multiple types in one declaration|declaration does not declare anything" "char8_t" } */
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-limits-1.C b/gcc/testsuite/g++.dg/ext/char8_t-limits-1.C
new file mode 100644 (file)
index 0000000..0d6df34
--- /dev/null
@@ -0,0 +1,9 @@
+// Test for unsignedness and that the max limit of char8_t is at least 0xFF
+// when -fchar8_t is enabled.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fchar8_t" }
+
+static_assert(u8'\xFF' == 0xFF, "Error");
+static_assert(u8"\xFF"[0] == 0xFF, "Error");
+static_assert(char8_t(-1) >= 0, "Error");
+static_assert(char8_t{-1} >= 0, "Error"); // { dg-error "narrowing conversion of .-1. from .int. to .char8_t." "char8_t" }
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-overload-1.C b/gcc/testsuite/g++.dg/ext/char8_t-overload-1.C
new file mode 100644 (file)
index 0000000..48aa44a
--- /dev/null
@@ -0,0 +1,26 @@
+// Test overloading for UTF-8 literals when -fchar8_t is not in effect.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fno-char8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+int fc(char);
+long fc(unsigned char);
+static_assert(is_same<decltype(fc('x')), int>::value, "Error");
+static_assert(is_same<decltype(fc(u8'x')), int>::value, "Error");
+
+int fs(const char*);
+long fs(const unsigned char*);
+static_assert(is_same<decltype(fs("x")), int>::value, "Error");
+static_assert(is_same<decltype(fs(u8"x")), int>::value, "Error");
+
+int fr(const char(&)[2]);
+long fr(const unsigned char(&)[2]);
+static_assert(is_same<decltype(fr("x")), int>::value, "Error");
+static_assert(is_same<decltype(fr(u8"x")), int>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-overload-2.C b/gcc/testsuite/g++.dg/ext/char8_t-overload-2.C
new file mode 100644 (file)
index 0000000..15e28cd
--- /dev/null
@@ -0,0 +1,26 @@
+// Test overloading for UTF-8 literals when -fchar8_t is in effect.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fchar8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+int fc(char);
+long fc(char8_t);
+static_assert(is_same<decltype(fc('x')), int>::value, "Error");
+static_assert(is_same<decltype(fc(u8'x')), long>::value, "Error");
+
+int fs(const char*);
+long fs(const char8_t*);
+static_assert(is_same<decltype(fs("x")), int>::value, "Error");
+static_assert(is_same<decltype(fs(u8"x")), long>::value, "Error");
+
+int fr(const char(&)[2]);
+long fr(const char8_t(&)[2]);
+static_assert(is_same<decltype(fr("x")), int>::value, "Error");
+static_assert(is_same<decltype(fr(u8"x")), long>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-1.C b/gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-1.C
new file mode 100644 (file)
index 0000000..36d411b
--- /dev/null
@@ -0,0 +1,12 @@
+// Test that char8_t related predefined macros are not present when -fchar8_t is
+// not enabled.
+// { dg-do compile }
+// { dg-options "-fno-char8_t" }
+
+#if defined(__CHAR8_TYPE__)
+#error __CHAR8_TYPE__ is defined!
+#endif
+
+#if defined(__GCC_ATOMIC_CHAR8_T_LOCK_FREE)
+#error __GCC_ATOMIC_CHAR8_T_LOCK_FREE is defined!
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-2.C b/gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-2.C
new file mode 100644 (file)
index 0000000..06d9b24
--- /dev/null
@@ -0,0 +1,12 @@
+// Test that char8_t related predefined macros are present when -fchar8_t is
+// enabled.
+// { dg-do compile }
+// { dg-options "-fchar8_t" }
+
+#if !defined(__CHAR8_TYPE__)
+#error __CHAR8_TYPE__ is not defined!
+#endif
+
+#if !defined(__GCC_ATOMIC_CHAR8_T_LOCK_FREE)
+#error __GCC_ATOMIC_CHAR8_T_LOCK_FREE is not defined!
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-sizeof-1.C b/gcc/testsuite/g++.dg/ext/char8_t-sizeof-1.C
new file mode 100644 (file)
index 0000000..c4bc4cb
--- /dev/null
@@ -0,0 +1,7 @@
+// Test sizeof for char8_t.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fchar8_t" }
+
+static_assert(sizeof(u8'x') == 1);
+static_assert(sizeof(char8_t) == 1);
+static_assert(sizeof(__CHAR8_TYPE__) == 1);
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-specialization-1.C b/gcc/testsuite/g++.dg/ext/char8_t-specialization-1.C
new file mode 100644 (file)
index 0000000..1c2fe36
--- /dev/null
@@ -0,0 +1,8 @@
+// Test specialization for UTF-8 literals when -fchar8_t is not enabled.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fno-char8_t" }
+
+template<auto> struct ct { static constexpr int dm = 1; };
+template<> struct ct<'x'> { static constexpr int dm = 2; };
+static_assert(ct<'x'>::dm == 2, "Error");
+static_assert(ct<u8'x'>::dm == 2, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-specialization-2.C b/gcc/testsuite/g++.dg/ext/char8_t-specialization-2.C
new file mode 100644 (file)
index 0000000..969e09e
--- /dev/null
@@ -0,0 +1,17 @@
+// Test specialization for UTF-8 literals when -fchar8_t is enabled.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fchar8_t" }
+
+template<auto> struct ct { static constexpr int dm = 1; };
+template<> struct ct<'x'> { static constexpr int dm = 2; };
+template<> struct ct<u8'x'> { static constexpr int dm = 3; };
+static_assert(ct<'x'>::dm == 2, "Error");
+static_assert(ct<u8'x'>::dm == 3, "Error");
+
+template<typename T, const T *> struct ct2 { static constexpr int dm = 4; };
+template<const char *P> struct ct2<char,P> { static constexpr int dm = 5; };
+template<const char8_t *P> struct ct2<char8_t,P> { static constexpr int dm = 6; };
+constexpr const char s[] = "x";
+constexpr const char8_t s8[] = u8"x";
+static_assert(ct2<char,s>::dm == 5, "Error");
+static_assert(ct2<char8_t,s8>::dm == 6, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-string-literal-1.C b/gcc/testsuite/g++.dg/ext/char8_t-string-literal-1.C
new file mode 100644 (file)
index 0000000..6cfb47b
--- /dev/null
@@ -0,0 +1,12 @@
+// Test that UTF-8 string literals have type const char[] if -fchar8_t is not enabled.
+// { dg-do compile { target c++11 } }
+// { dg-options "-fno-char8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+static_assert(is_same<decltype(u8""), const char(&)[1]>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-string-literal-2.C b/gcc/testsuite/g++.dg/ext/char8_t-string-literal-2.C
new file mode 100644 (file)
index 0000000..f51df72
--- /dev/null
@@ -0,0 +1,12 @@
+// Test that UTF-8 string literals have type const char8_t[] if -fchar8_t is enabled.
+// { dg-do compile { target c++11 } }
+// { dg-options "-fchar8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+static_assert(is_same<decltype(u8""), const char8_t(&)[1]>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-type-specifier-1.C b/gcc/testsuite/g++.dg/ext/char8_t-type-specifier-1.C
new file mode 100644 (file)
index 0000000..dac4a47
--- /dev/null
@@ -0,0 +1,5 @@
+// Test that char8_t is not a type specifier if -fchar8_t is not enabled.
+// { dg-do compile }
+// { dg-options "-fno-char8_t" }
+
+char8_t c8; /* { dg-error ".char8_t. does not name a type" "no-char8_t" } */
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-type-specifier-2.C b/gcc/testsuite/g++.dg/ext/char8_t-type-specifier-2.C
new file mode 100644 (file)
index 0000000..ecc5d1c
--- /dev/null
@@ -0,0 +1,16 @@
+// Test that char8_t is recognized as a type specifier if -fchar8_t is enabled.
+// { dg-do compile }
+// { dg-options "-fchar8_t" }
+
+char8_t c8;
+
+signed char8_t         sc8;            /* { dg-error "signed" } */
+unsigned char8_t       uc8;            /* { dg-error "unsigned" } */
+
+short char8_t          shc8;           /* { dg-error "short" } */
+long char8_t           lgc8;           /* { dg-error "long" } */
+
+signed short char8_t   ssc8;           /* { dg-error "signed" } */
+signed long char8_t    slc8;           /* { dg-error "signed" } */
+unsigned short char8_t usc8;           /* { dg-error "unsigned" } */
+unsigned long char8_t  ulc8;           /* { dg-error "unsigned" } */
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-typedef-1.C b/gcc/testsuite/g++.dg/ext/char8_t-typedef-1.C
new file mode 100644 (file)
index 0000000..b77d9a2
--- /dev/null
@@ -0,0 +1,6 @@
+// Test that no error is issued for attempted char8_t typedef declarations
+// when -fchar8_t is not enabled.
+// { dg-do compile }
+// { dg-options "-fno-char8_t" }
+
+typedef unsigned char char8_t;
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-typedef-2.C b/gcc/testsuite/g++.dg/ext/char8_t-typedef-2.C
new file mode 100644 (file)
index 0000000..bb20499
--- /dev/null
@@ -0,0 +1,6 @@
+// Test that an error is issued for attempted char8_t typedef declarations
+// when -fchar8_t is enabled.
+// { dg-do compile }
+// { dg-options "-fchar8_t" }
+
+typedef unsigned char char8_t; // { dg-error "redeclaration" }
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-udl-1.C b/gcc/testsuite/g++.dg/ext/char8_t-udl-1.C
new file mode 100644 (file)
index 0000000..627c263
--- /dev/null
@@ -0,0 +1,19 @@
+// Test overloading for UTF-8 user defined literals when -fchar8_t is not in effect.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fno-char8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+int operator "" _udcl(char);
+static_assert(is_same<decltype('x'_udcl), int>::value, "Error");
+static_assert(is_same<decltype(u8'x'_udcl), int>::value, "Error");
+
+int operator "" _udsl(const char*, __SIZE_TYPE__);
+static_assert(is_same<decltype("x"_udsl), int>::value, "Error");
+static_assert(is_same<decltype(u8"x"_udsl), int>::value, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/char8_t-udl-2.C b/gcc/testsuite/g++.dg/ext/char8_t-udl-2.C
new file mode 100644 (file)
index 0000000..74cc775
--- /dev/null
@@ -0,0 +1,21 @@
+// Test overloading for UTF-8 user defined literals when -fchar8_t is in effect.
+// { dg-do compile }
+// { dg-options "-std=c++17 -fchar8_t" }
+
+template<typename T1, typename T2>
+  struct is_same
+  { static const bool value = false; };
+
+template<typename T>
+  struct is_same<T, T>
+  { static const bool value = true; };
+
+int operator "" _udcl(char);
+long operator "" _udcl(char8_t);
+static_assert(is_same<decltype('x'_udcl), int>::value, "Error");
+static_assert(is_same<decltype(u8'x'_udcl), long>::value, "Error");
+
+int operator "" _udsl(const char*, __SIZE_TYPE__);
+long operator "" _udsl(const char8_t*, __SIZE_TYPE__);
+static_assert(is_same<decltype("x"_udsl), int>::value, "Error");
+static_assert(is_same<decltype(u8"x"_udsl), long>::value, "Error");
index 2ce774abc4a43d2ce2ee256dee329e8bad80f7c7..f37f93c8b73299e2175a5e810075a322ca076561 100644 (file)
@@ -3,34 +3,44 @@
 /* { dg-do compile { target c++11 } } */
 /* { dg-options "-fshort-wchar" } */
 
+#if __cpp_char8_t
+typedef char8_t u8_char_t;
+#else
+typedef char u8_char_t;
+#endif
+
 const char     s_0[]   = "ab";
-const char     s_1[]   = u"ab";        /* { dg-error "from wide string" } */
-const char     s_2[]   = U"ab";        /* { dg-error "from wide string" } */
-const char     s_3[]   = L"ab";        /* { dg-error "from wide string" } */
+const char     s_1[]   = u"ab";        /* { dg-error "from a string literal with type array of .char16_t." } */
+const char     s_2[]   = U"ab";        /* { dg-error "from a string literal with type array of .char32_t." } */
+const char     s_3[]   = L"ab";        /* { dg-error "from a string literal with type array of .wchar_t." } */
+const u8_char_t        s_4[]   = u8"ab";
 
-const char16_t s16_0[] = "ab";         /* { dg-error "from non-wide" } */
+const char16_t s16_0[] = "ab";         /* { dg-error "from a string literal with type array of .char." } */
 const char16_t s16_1[] = u"ab";
-const char16_t s16_2[] = U"ab";        /* { dg-error "from incompatible" } */
-const char16_t s16_3[] = L"ab";        /* { dg-error "from incompatible" } */
+const char16_t s16_2[] = U"ab";        /* { dg-error "from a string literal with type array of .char32_t." } */
+const char16_t s16_3[] = L"ab";        /* { dg-error "from a string literal with type array of .wchar_t." } */
+const char16_t s16_4[] = u8"ab";       /* { dg-error "from a string literal with type array of .char." } */
 
-const char16_t s16_4[0] = u"ab";       /* { dg-error "chars is too long" } */
-const char16_t s16_5[1] = u"ab";       /* { dg-error "chars is too long" } */
-const char16_t s16_6[2] = u"ab";       /* { dg-error "chars is too long" } */
-const char16_t s16_7[3] = u"ab";
-const char16_t s16_8[4] = u"ab";
+const char16_t s16_5[0] = u"ab";       /* { dg-error "chars is too long" } */
+const char16_t s16_6[1] = u"ab";       /* { dg-error "chars is too long" } */
+const char16_t s16_7[2] = u"ab";       /* { dg-error "chars is too long" } */
+const char16_t s16_8[3] = u"ab";
+const char16_t s16_9[4] = u"ab";
 
-const char32_t s32_0[] = "ab";         /* { dg-error "from non-wide" } */
-const char32_t s32_1[] = u"ab";        /* { dg-error "from incompatible" } */
+const char32_t s32_0[] = "ab";         /* { dg-error "from a string literal with type array of .char." } */
+const char32_t s32_1[] = u"ab";        /* { dg-error "from a string literal with type array of .char16_t." } */
 const char32_t s32_2[] = U"ab";
-const char32_t s32_3[] = L"ab";        /* { dg-error "from incompatible" } */
+const char32_t s32_3[] = L"ab";        /* { dg-error "from a string literal with type array of .wchar_t." } */
+const char32_t s32_4[] = u8"ab";       /* { dg-error "from a string literal with type array of .char." } */
 
-const char32_t s32_4[0] = U"ab";       /* { dg-error "chars is too long" } */
-const char32_t s32_5[1] = U"ab";       /* { dg-error "chars is too long" } */
-const char32_t s32_6[2] = U"ab";       /* { dg-error "chars is too long" } */
-const char32_t s32_7[3] = U"ab";
-const char32_t s32_8[4] = U"ab";
+const char32_t s32_5[0] = U"ab";       /* { dg-error "chars is too long" } */
+const char32_t s32_6[1] = U"ab";       /* { dg-error "chars is too long" } */
+const char32_t s32_7[2] = U"ab";       /* { dg-error "chars is too long" } */
+const char32_t s32_8[3] = U"ab";
+const char32_t s32_9[4] = U"ab";
 
-const wchar_t  sw_0[]  = "ab";         /* { dg-error "from non-wide" } */
-const wchar_t  sw_1[]  = u"ab";        /* { dg-error "from incompatible" } */
-const wchar_t  sw_2[]  = U"ab";        /* { dg-error "from incompatible" } */
+const wchar_t  sw_0[]  = "ab";         /* { dg-error "from a string literal with type array of .char." } */
+const wchar_t  sw_1[]  = u"ab";        /* { dg-error "from a string literal with type array of .char16_t." } */
+const wchar_t  sw_2[]  = U"ab";        /* { dg-error "from a string literal with type array of .char32_t." } */
 const wchar_t  sw_3[]  = L"ab";
+const wchar_t  sw_4[]  = u8"ab";       /* { dg-error "from a string literal with type array of .char." } */
index 21e438693a2b6607149ad88e2834ca8f43188a5e..0e403db7e05e283118da5297912dd5ad63039041 100644 (file)
@@ -3,34 +3,44 @@
 /* { dg-do compile { target c++11 } } */
 // { dg-options "" }
 
+#if __cpp_char8_t
+typedef char8_t u8_char_t;
+#else
+typedef char u8_char_t;
+#endif
+
 const char     s_0[]   = "ab";
-const char     s_1[]   = u"ab";        /* { dg-error "from wide string" } */
-const char     s_2[]   = U"ab";        /* { dg-error "from wide string" } */
-const char     s_3[]   = L"ab";        /* { dg-error "from wide string" } */
+const char     s_1[]   = u"ab";        /* { dg-error "from a string literal with type array of .char16_t." } */
+const char     s_2[]   = U"ab";        /* { dg-error "from a string literal with type array of .char32_t." } */
+const char     s_3[]   = L"ab";        /* { dg-error "from a string literal with type array of .wchar_t." } */
+const u8_char_t        s_4[]   = u8"ab";
 
-const char16_t s16_0[] = "ab";         /* { dg-error "from non-wide" } */
+const char16_t s16_0[] = "ab";         /* { dg-error "from a string literal with type array of .char." } */
 const char16_t s16_1[] = u"ab";
-const char16_t s16_2[] = U"ab";        /* { dg-error "from incompatible" } */
-const char16_t s16_3[] = L"ab";        /* { dg-error "from incompatible" } */
+const char16_t s16_2[] = U"ab";        /* { dg-error "from a string literal with type array of .char32_t." } */
+const char16_t s16_3[] = L"ab";        /* { dg-error "from a string literal with type array of .wchar_t." } */
+const char16_t s16_4[] = u8"ab";       /* { dg-error "from a string literal with type array of .char." } */
 
-const char16_t s16_4[0] = u"ab";       /* { dg-error "chars is too long" } */
-const char16_t s16_5[1] = u"ab";       /* { dg-error "chars is too long" } */
-const char16_t s16_6[2] = u"ab";       /* { dg-error "chars is too long" } */
-const char16_t s16_7[3] = u"ab";
-const char16_t s16_8[4] = u"ab";
+const char16_t s16_5[0] = u"ab";       /* { dg-error "chars is too long" } */
+const char16_t s16_6[1] = u"ab";       /* { dg-error "chars is too long" } */
+const char16_t s16_7[2] = u"ab";       /* { dg-error "chars is too long" } */
+const char16_t s16_8[3] = u"ab";
+const char16_t s16_9[4] = u"ab";
 
-const char32_t s32_0[] = "ab";         /* { dg-error "from non-wide" } */
-const char32_t s32_1[] = u"ab";        /* { dg-error "from incompatible" } */
+const char32_t s32_0[] = "ab";         /* { dg-error "from a string literal with type array of .char." } */
+const char32_t s32_1[] = u"ab";        /* { dg-error "from a string literal with type array of .char16_t." } */
 const char32_t s32_2[] = U"ab";
-const char32_t s32_3[] = L"ab";        /* { dg-error "from incompatible" } */
+const char32_t s32_3[] = L"ab";        /* { dg-error "from a string literal with type array of .wchar_t." } */
+const char32_t s32_4[] = u8"ab";       /* { dg-error "from a string literal with type array of .char." } */
 
-const char32_t s32_4[0] = U"ab";       /* { dg-error "chars is too long" } */
-const char32_t s32_5[1] = U"ab";       /* { dg-error "chars is too long" } */
-const char32_t s32_6[2] = U"ab";       /* { dg-error "chars is too long" } */
-const char32_t s32_7[3] = U"ab";
-const char32_t s32_8[4] = U"ab";
+const char32_t s32_5[0] = U"ab";       /* { dg-error "chars is too long" } */
+const char32_t s32_6[1] = U"ab";       /* { dg-error "chars is too long" } */
+const char32_t s32_7[2] = U"ab";       /* { dg-error "chars is too long" } */
+const char32_t s32_8[3] = U"ab";
+const char32_t s32_9[4] = U"ab";
 
-const wchar_t  sw_0[]  = "ab";         /* { dg-error "from non-wide" } */
-const wchar_t  sw_1[]  = u"ab";        /* { dg-error "from incompatible" } */
-const wchar_t  sw_2[]  = U"ab";        /* { dg-error "from incompatible" } */
+const wchar_t  sw_0[]  = "ab";         /* { dg-error "from a string literal with type array of .char." } */
+const wchar_t  sw_1[]  = u"ab";        /* { dg-error "from a string literal with type array of .char16_t." } */
+const wchar_t  sw_2[]  = U"ab";        /* { dg-error "from a string literal with type array of .char32_t." } */
 const wchar_t  sw_3[]  = L"ab";
+const wchar_t  sw_4[]  = u8"ab";       /* { dg-error "from a string literal with type array of .char." } */
diff --git a/gcc/testsuite/g++.dg/ext/utf-cvt-char8_t.C b/gcc/testsuite/g++.dg/ext/utf-cvt-char8_t.C
new file mode 100644 (file)
index 0000000..0170b36
--- /dev/null
@@ -0,0 +1,39 @@
+/* Contributed by Kris Van Hees <kris.van.hees@oracle.com> */
+/* Test the char8_t promotion rules. */
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-fchar8_t -Wall -Wconversion -Wsign-conversion -Wsign-promo" } */
+
+extern void f_c (char);
+extern void fsc (signed char);
+extern void fuc (unsigned char);
+extern void f_s (short);
+extern void fss (signed short);
+extern void fus (unsigned short);
+extern void f_i (int);
+extern void fsi (signed int);
+extern void fui (unsigned int);
+extern void f_l (long);
+extern void fsl (signed long);
+extern void ful (unsigned long);
+extern void f_ll (long long);
+extern void fsll (signed long long);
+extern void full (unsigned long long);
+
+void m(char8_t c)
+{
+    f_c (c);   /* { dg-warning "change the sign" } */
+    fsc (c);   /* { dg-warning "change the sign" } */
+    fuc (c);
+    f_s (c);
+    fss (c);
+    fus (c);
+    f_i (c);
+    fsi (c);
+    fui (c);
+    f_l (c);
+    fsl (c);
+    ful (c);
+    f_ll (c);
+    fsll (c);
+    full (c);
+}
index 365118e3964589c7122dc2ccd889dbdc3c41ce8f..ada97be5ef646c82524700b1f13152f47b94c23a 100644 (file)
@@ -1,27 +1,33 @@
 /* Contributed by Kris Van Hees <kris.van.hees@oracle.com> */
 /* Expected errors for char16_t/char32_t in c++98. */
-/* Ensure u and U prefixes are parsed as separate tokens in c++98. */
+/* Ensure u8, u and U prefixes are parsed as separate tokens in c++98. */
 /* { dg-do compile } */
 /* { dg-options "-std=c++98" } */
 
 const static char16_t  c0      = 'a';  /* { dg-error "not name a type" } */
 const static char32_t  c1      = 'a';  /* { dg-error "not name a type" } */
 
-const unsigned short   c2      = u'a'; /* { dg-error "not declared" } */
-const unsigned long    c3      = U'a'; /* { dg-error "not declared" } */
+const unsigned short   c2      = u'a';         /* { dg-error "not declared" } */
+const unsigned long    c3      = U'a';         /* { dg-error "not declared" } */
+const unsigned char    c4      = u8'a';        /* { dg-error "not declared" } */
 
 #define u      1 +
 #define U      2 +
+#define u8     3 +
 
 const unsigned short   c5      = u'a';
 const unsigned long    c6      = U'a';
+const unsigned char    c7      = u8'a';
 
 #undef u
 #undef U
+#undef u8
 #define u      "a"
 #define U      "b"
+#define u8     "c"
 
 const void             *s0     = u"a";
 const void             *s1     = U"a";
+const void             *s2     = u8"a";
 
 int main () {}
index c2b127d5ddad084d1657be28dabdb92a4ec088f5..6bf020f7cdb2734df19c480d4a6b27df8fb79c6a 100644 (file)
@@ -1,27 +1,33 @@
 /* Contributed by Kris Van Hees <kris.van.hees@oracle.com> */
 /* Expected errors for char16_t/char32_t in default std. */
-/* Ensure u and U prefixes are parsed as separate tokens in default std. */
+/* Ensure u8, u and U prefixes are parsed as separate tokens in default std. */
 /* { dg-do compile } */
 /* { dg-options "-std=c++98" } */
 
 const static char16_t  c0      = 'a';  /* { dg-error "not name a type" } */
 const static char32_t  c1      = 'a';  /* { dg-error "not name a type" } */
 
-const unsigned short   c2      = u'a'; /* { dg-error "not declared" } */
-const unsigned long    c3      = U'a'; /* { dg-error "not declared" } */
+const unsigned short   c2      = u'a';         /* { dg-error "not declared" } */
+const unsigned long    c3      = U'a';         /* { dg-error "not declared" } */
+const unsigned char    c4      = u8'a';        /* { dg-error "not declared" } */
 
 #define u      1 +
 #define U      2 +
+#define u8     3 +
 
-const unsigned short   c4      = u'a';
-const unsigned long    c5      = U'a';
+const unsigned short   c5      = u'a';
+const unsigned long    c6      = U'a';
+const unsigned char    c7      = u8'a';
 
 #undef u
 #undef U
+#undef u8
 #define u      "a"
 #define U      "b"
+#define u8     "c"
 
 const void             *s0     = u"a";
 const void             *s1     = U"a";
+const void             *s2     = u8"a";
 
 int main () {}
index b3be121e2dcbb5d3a58f4548e3726e516cddd47d..dc9a814c1616f21a146f6cc8e9211eeffd57bcbd 100644 (file)
@@ -1,27 +1,33 @@
 /* Contributed by Kris Van Hees <kris.van.hees@oracle.com> */
 /* Expected errors for char16_t/char32_t in gnu++98. */
-/* Ensure u and U prefixes are parsed as separate tokens in gnu++98. */
+/* Ensure u8, u and U prefixes are parsed as separate tokens in gnu++98. */
 /* { dg-do compile } */
 /* { dg-options "-std=gnu++98" } */
 
 const static char16_t  c0      = 'a';  /* { dg-error "not name a type" } */
 const static char32_t  c1      = 'a';  /* { dg-error "not name a type" } */
 
-const unsigned short   c2      = u'a'; /* { dg-error "not declared" } */
-const unsigned long    c3      = U'a'; /* { dg-error "not declared" } */
+const unsigned short   c2      = u'a';         /* { dg-error "not declared" } */
+const unsigned long    c3      = U'a';         /* { dg-error "not declared" } */
+const unsigned char    c4      = u8'a';        /* { dg-error "not declared" } */
 
 #define u      1 +
 #define U      2 +
+#define u8     3 +
 
 const unsigned short   c5      = u'a';
 const unsigned long    c6      = U'a';
+const unsigned char    c7      = u8'a';
 
 #undef u
 #undef U
+#undef u8
 #define u      "a"
 #define U      "b"
+#define u8     "c"
 
 const void             *s0     = u"a";
 const void             *s1     = U"a";
+const void             *s2     = u8"a";
 
 int main () {}
diff --git a/gcc/testsuite/g++.dg/ext/utf-type-char8_t.C b/gcc/testsuite/g++.dg/ext/utf-type-char8_t.C
new file mode 100644 (file)
index 0000000..a7d8b16
--- /dev/null
@@ -0,0 +1,11 @@
+/* Ensure that __CHAR8_TYPE__ exists and matches the underlying type. */
+/* { dg-do run { target c++11 } } */
+/* { dg-options "-fchar8_t -Wall -Werror" } */
+
+extern "C" void abort (void);
+
+int main ()
+{
+    if (sizeof (__CHAR8_TYPE__) != sizeof (char8_t))
+       abort();
+}
index a1a3518a49712cdbe43907b146009b4f5893415a..089465fa518a47bfd561003b1a96f0fd707a5901 100644 (file)
@@ -2,15 +2,20 @@
 // { dg-require-iconv "ISO-8859-2" }
 // { dg-options "-fexec-charset=ISO-8859-2" }
 
+#if __cpp_char8_t
+typedef char8_t u8_char_t;
+#else
+typedef char u8_char_t;
+#endif
+
 const char *str1 = "h\u00e1\U0000010Dky ";
 const char *str2 = "\u010d\u00E1rky\n";
-const char *str3 = u8"h\u00e1\U0000010Dky ";
-const char *str4 = u8"\u010d\u00E1rky\n";
+const u8_char_t *str3 = u8"h\u00e1\U0000010Dky ";
+const u8_char_t *str4 = u8"\u010d\u00E1rky\n";
 const char *str5 = "h\u00e1\U0000010Dky " "\u010d\u00E1rky\n";
-const char *str6 = u8"h\u00e1\U0000010Dky " "\u010d\u00E1rky\n";
-const char *str7 = "h\u00e1\U0000010Dky " u8"\u010d\u00E1rky\n";
-#define u8
-const char *str8 = u8"h\u00e1\U0000010Dky " u8"\u010d\u00E1rky\n";
+const u8_char_t *str6 = u8"h\u00e1\U0000010Dky " "\u010d\u00E1rky\n";
+const u8_char_t *str7 = "h\u00e1\U0000010Dky " u8"\u010d\u00E1rky\n";
+const u8_char_t *str8 = u8"h\u00e1\U0000010Dky " u8"\u010d\u00E1rky\n";
 
 const char latin2_1[] = "\x68\xe1\xe8\x6b\x79\x20";
 const char latin2_2[] = "\xe8\xe1\x72\x6b\x79\n";
@@ -22,16 +27,16 @@ main (void)
 {
   if (__builtin_strcmp (str1, latin2_1) != 0
       || __builtin_strcmp (str2, latin2_2) != 0
-      || __builtin_strcmp (str3, utf8_1) != 0
-      || __builtin_strcmp (str4, utf8_2) != 0
+      || __builtin_memcmp (str3, utf8_1, sizeof (utf8_1) - 1) != 0
+      || __builtin_memcmp (str4, utf8_2, sizeof (utf8_2) - 1) != 0
       || __builtin_strncmp (str5, latin2_1, sizeof (latin2_1) - 1) != 0
       || __builtin_strcmp (str5 + sizeof (latin2_1) - 1, latin2_2) != 0
-      || __builtin_strncmp (str6, utf8_1, sizeof (utf8_1) - 1) != 0
-      || __builtin_strcmp (str6 + sizeof (utf8_1) - 1, utf8_2) != 0
-      || __builtin_strncmp (str7, utf8_1, sizeof (utf8_1) - 1) != 0
-      || __builtin_strcmp (str7 + sizeof (utf8_1) - 1, utf8_2) != 0
-      || __builtin_strncmp (str8, utf8_1, sizeof (utf8_1) - 1) != 0
-      || __builtin_strcmp (str8 + sizeof (utf8_1) - 1, utf8_2) != 0)
+      || __builtin_memcmp (str6, utf8_1, sizeof (utf8_1) - 1) != 0
+      || __builtin_memcmp (str6 + sizeof (utf8_1) - 1, utf8_2, sizeof (utf8_2) - 1) != 0
+      || __builtin_memcmp (str7, utf8_1, sizeof (utf8_1) - 1) != 0
+      || __builtin_memcmp (str7 + sizeof (utf8_1) - 1, utf8_2, sizeof (utf8_2) - 1) != 0
+      || __builtin_memcmp (str8, utf8_1, sizeof (utf8_1) - 1) != 0
+      || __builtin_memcmp (str8 + sizeof (utf8_1) - 1, utf8_2, sizeof (utf8_2) - 1) != 0)
     __builtin_abort ();
   if (sizeof ("a" u8"b"[0]) != 1
       || sizeof (u8"a" "b"[0]) != 1
index bafe6e8351c7e4be71d00d8741e0ef6124755826..b13d55f1139ba75315a2547881f829c3c1b39ce7 100644 (file)
@@ -1,21 +1,27 @@
 // { dg-do compile { target c++11 } }
 // { dg-options "" }
 
-const char     s0[]    = u8"ab";
-const char16_t s1[]    = u8"ab";       // { dg-error "from non-wide" }
-const char32_t  s2[]    = u8"ab";      // { dg-error "from non-wide" }
-const wchar_t   s3[]    = u8"ab";      // { dg-error "from non-wide" }
+#if __cpp_char8_t
+typedef char8_t u8_char_t;
+#else
+typedef char u8_char_t;
+#endif
 
-const char      t0[0]   = u8"ab";      // { dg-error "chars is too long" }
-const char      t1[1]   = u8"ab";      // { dg-error "chars is too long" }
-const char      t2[2]   = u8"ab";      // { dg-error "chars is too long" }
-const char      t3[3]   = u8"ab";
-const char      t4[4]   = u8"ab";
+const u8_char_t        s0[]    = u8"ab";
+const char16_t s1[]    = u8"ab";       // { dg-error "from a string literal with type array of .char." }
+const char32_t  s2[]    = u8"ab";      // { dg-error "from a string literal with type array of .char." }
+const wchar_t   s3[]    = u8"ab";      // { dg-error "from a string literal with type array of .char." }
 
-const char      u0[0]   = u8"\u2160."; // { dg-error "chars is too long" }
-const char      u1[1]   = u8"\u2160."; // { dg-error "chars is too long" }
-const char      u2[2]   = u8"\u2160."; // { dg-error "chars is too long" }
-const char      u3[3]   = u8"\u2160."; // { dg-error "chars is too long" }
-const char      u4[4]   = u8"\u2160."; // { dg-error "chars is too long" }
-const char      u5[5]   = u8"\u2160.";
-const char      u6[6]   = u8"\u2160.";
+const u8_char_t      t0[0]   = u8"ab"; // { dg-error "chars is too long" }
+const u8_char_t      t1[1]   = u8"ab"; // { dg-error "chars is too long" }
+const u8_char_t      t2[2]   = u8"ab"; // { dg-error "chars is too long" }
+const u8_char_t      t3[3]   = u8"ab";
+const u8_char_t      t4[4]   = u8"ab";
+
+const u8_char_t      u0[0]   = u8"\u2160.";    // { dg-error "chars is too long" }
+const u8_char_t      u1[1]   = u8"\u2160.";    // { dg-error "chars is too long" }
+const u8_char_t      u2[2]   = u8"\u2160.";    // { dg-error "chars is too long" }
+const u8_char_t      u3[3]   = u8"\u2160.";    // { dg-error "chars is too long" }
+const u8_char_t      u4[4]   = u8"\u2160.";    // { dg-error "chars is too long" }
+const u8_char_t      u5[5]   = u8"\u2160.";
+const u8_char_t      u6[6]   = u8"\u2160.";
index a4d3fff2967806ab2bf9e89af80a0e302031595e..653171b4357ce977dbf70d4ca1e00b9a0e612cd6 100644 (file)
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++11 } }
+// { dg-skip-if "char8_t" { c++2a } }
 /* { dg-options "-Wformat -fdiagnostics-show-caret" } */
 
 /* C++11-specific format tests. */
index 2206b91d3baec07767a433c908981248e779235b..bcc0227bdd81c74724a1f5bb24664d99850ee72f 100644 (file)
@@ -1,3 +1,10 @@
+2019-01-14  Tom Honermann  <tom@honermann.net>
+
+       * cp-demangle.c (cplus_demangle_builtin_types)
+       (cplus_demangle_type): Add name demangling for char8_t (Du).
+       * cp-demangle.h: Increase D_BUILTIN_TYPE_COUNT to accommodate the
+       new char8_t type.
+
 2019-01-09  Sandra Loosemore  <sandra@codesourcery.com>
 
        PR other/16615
index ddcd3be6b8f524c91a12f131d657e68cf0886100..b34b4856922349b25b8a55c094aafd8fbff84783 100644 (file)
@@ -2364,9 +2364,10 @@ cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
   /* 27 */ { NL ("decimal64"), NL ("decimal64"),       D_PRINT_DEFAULT },
   /* 28 */ { NL ("decimal128"),        NL ("decimal128"),      D_PRINT_DEFAULT },
   /* 29 */ { NL ("half"),      NL ("half"),            D_PRINT_FLOAT },
-  /* 30 */ { NL ("char16_t"),  NL ("char16_t"),        D_PRINT_DEFAULT },
-  /* 31 */ { NL ("char32_t"),  NL ("char32_t"),        D_PRINT_DEFAULT },
-  /* 32 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"),
+  /* 30 */ { NL ("char8_t"),   NL ("char8_t"),         D_PRINT_DEFAULT },
+  /* 31 */ { NL ("char16_t"),  NL ("char16_t"),        D_PRINT_DEFAULT },
+  /* 32 */ { NL ("char32_t"),  NL ("char32_t"),        D_PRINT_DEFAULT },
+  /* 33 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"),
             D_PRINT_DEFAULT },
 };
 
@@ -2654,14 +2655,19 @@ cplus_demangle_type (struct d_info *di)
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]);
          di->expansion += ret->u.s_builtin.type->len;
          break;
+       case 'u':
+         /* char8_t */
+         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
+         di->expansion += ret->u.s_builtin.type->len;
+         break;
        case 's':
          /* char16_t */
-         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
+         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
          di->expansion += ret->u.s_builtin.type->len;
          break;
        case 'i':
          /* char32_t */
-         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
+         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
          di->expansion += ret->u.s_builtin.type->len;
          break;
 
@@ -2687,7 +2693,7 @@ cplus_demangle_type (struct d_info *di)
 
         case 'n':
           /* decltype(nullptr) */
-         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
+         ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[33]);
          di->expansion += ret->u.s_builtin.type->len;
          break;
 
index b739bdfb8a4a17a738c8a2c54134d51611937687..92191cf3ea8a45a52f4d63943795b825963ce1aa 100644 (file)
@@ -176,7 +176,7 @@ d_advance (struct d_info *di, int i)
 extern const struct demangle_operator_info cplus_demangle_operators[];
 #endif
 
-#define D_BUILTIN_TYPE_COUNT (33)
+#define D_BUILTIN_TYPE_COUNT (34)
 
 CP_STATIC_IF_GLIBCPP_V3
 const struct demangle_builtin_type_info