summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Honermann <tom@honermann.net>2019-01-14 19:55:51 +0000
committerJason Merrill <jason@gcc.gnu.org>2019-01-14 14:55:51 -0500
commit2d91f79dc990f81dcea89a5087cad566238b2456 (patch)
treeae9137b811a3a0bdada65dbb8a6ed5dba9d24b0e
parent23db6ced33c245c38c147c31011bbafa392e4328 (diff)
Implement P0482R5, char8_t: A type for UTF-8 characters and strings
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
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/c-family/ChangeLog24
-rw-r--r--gcc/c-family/c-common.c41
-rw-r--r--gcc/c-family/c-common.h33
-rw-r--r--gcc/c-family/c-cppbuiltin.c5
-rw-r--r--gcc/c-family/c-lex.c14
-rw-r--r--gcc/c-family/c-opts.c4
-rw-r--r--gcc/c-family/c.opt5
-rw-r--r--gcc/cp/ChangeLog25
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/cvt.c1
-rw-r--r--gcc/cp/decl.c4
-rw-r--r--gcc/cp/lex.c2
-rw-r--r--gcc/cp/mangle.c4
-rw-r--r--gcc/cp/parser.c16
-rw-r--r--gcc/cp/rtti.c2
-rw-r--r--gcc/cp/tree.c1
-rw-r--r--gcc/cp/typeck.c4
-rw-r--r--gcc/cp/typeck2.c57
-rw-r--r--gcc/defaults.h4
-rw-r--r--gcc/doc/invoke.texi56
-rw-r--r--gcc/testsuite/c-c++-common/raw-string-13.c60
-rw-r--r--gcc/testsuite/c-c++-common/raw-string-15.c60
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C1
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg-char8_t.C81
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/udlit-resolve-char8_t.C38
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/udlit-string-length.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.h6
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/udlit-utf8char.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/utf8.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/char8_t1.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/char8_t2.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C8
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-aliasing-1.C8
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-deduction-1.C30
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-deduction-2.C30
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-1.C8
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C10
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-init-1.C21
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-init-2.C33
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-keyword-1.C5
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-keyword-2.C5
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-limits-1.C9
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-overload-1.C26
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-overload-2.C26
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-1.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-2.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-sizeof-1.C7
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-specialization-1.C8
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-specialization-2.C17
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-string-literal-1.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-string-literal-2.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-type-specifier-1.C5
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-type-specifier-2.C16
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-typedef-1.C6
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-typedef-2.C6
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-udl-1.C19
-rw-r--r--gcc/testsuite/g++.dg/ext/char8_t-udl-2.C21
-rw-r--r--gcc/testsuite/g++.dg/ext/utf-array-short-wchar.C54
-rw-r--r--gcc/testsuite/g++.dg/ext/utf-array.C54
-rw-r--r--gcc/testsuite/g++.dg/ext/utf-cvt-char8_t.C39
-rw-r--r--gcc/testsuite/g++.dg/ext/utf-cxx98.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/utf-dflt.C16
-rw-r--r--gcc/testsuite/g++.dg/ext/utf-gnuxx98.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/utf-type-char8_t.C11
-rw-r--r--gcc/testsuite/g++.dg/ext/utf8-1.C33
-rw-r--r--gcc/testsuite/g++.dg/ext/utf8-2.C38
-rw-r--r--gcc/testsuite/g++.dg/warn/Wformat-ranges-c++11.C1
-rw-r--r--libiberty/ChangeLog7
-rw-r--r--libiberty/cp-demangle.c18
-rw-r--r--libiberty/cp-demangle.h2
74 files changed, 1132 insertions, 142 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 869ab248d9f..aea7143dc91 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index fe4c81f9da4..0ff16ab4a3f 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -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
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index d2ea384d653..2a5a8e7defb 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -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:
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 9f790bc6a14..9fe90f32b16 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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]
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 25b5c1a7406..c9b63caeb2d 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -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. */
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index d5ce9e9a032..0a368a33a58 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -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)
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 2c22574b730..9660f51867a 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -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)
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index d118e74ab07..858beff53d6 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -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.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 82412a78926..5d0ef1217bb 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 56489465c0c..6a2004330d2 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 449ce50d9e4..91428119398 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -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)
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 6e75c3d3d93..41972aa0955 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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);
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 36ffa37e037..369ecc05df2 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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)
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 919f7b3f2fb..00bde4ee59a 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -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)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index be669f2f321..7d7b0292650 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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)
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index a6d32b914a7..c4aabea7003 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -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,
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 4db89a4e5a6..50002161500 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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));
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 43d2899a3c4..88e2cd6ab9b 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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))
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index ecc313b2355..cd4313295d5 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -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))
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 2a1a5b8d1df..b7534256119 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -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
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5ed1d133420..1151708aaf0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
diff --git a/gcc/testsuite/c-c++-common/raw-string-13.c b/gcc/testsuite/c-c++-common/raw-string-13.c
index 1b37405cee9..fa11edaa7aa 100644
--- a/gcc/testsuite/c-c++-common/raw-string-13.c
+++ b/gcc/testsuite/c-c++-common/raw-string-13.c
@@ -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");
diff --git a/gcc/testsuite/c-c++-common/raw-string-15.c b/gcc/testsuite/c-c++-common/raw-string-15.c
index 9dfdaabd87d..1d101dc8393 100644
--- a/gcc/testsuite/c-c++-common/raw-string-15.c
+++ b/gcc/testsuite/c-c++-common/raw-string-15.c
@@ -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");
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
index 4055e0ee8ec..b878918a9f3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
@@ -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
index 00000000000..b917b5f6b90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-implicit-conv-neg-char8_t.C
@@ -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
index 00000000000..19cbd519a86
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-resolve-char8_t.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-string-length.C b/gcc/testsuite/g++.dg/cpp0x/udlit-string-length.C
index acfda45d5fe..c76b0af9a28 100644
--- a/gcc/testsuite/g++.dg/cpp0x/udlit-string-length.C
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-string-length.C
@@ -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)
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.C b/gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.C
index 734a0f38ad0..ab65dd08714 100644
--- a/gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.C
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.h b/gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.h
index e61034ec4ef..c8725fa9f46 100644
--- a/gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.h
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-string-literal.h
@@ -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}; }
diff --git a/gcc/testsuite/g++.dg/cpp1z/udlit-utf8char.C b/gcc/testsuite/g++.dg/cpp1z/udlit-utf8char.C
index 0e921963835..093e32345cd 100644
--- a/gcc/testsuite/g++.dg/cpp1z/udlit-utf8char.C
+++ b/gcc/testsuite/g++.dg/cpp1z/udlit-utf8char.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp1z/utf8.C b/gcc/testsuite/g++.dg/cpp1z/utf8.C
index e08fbb9c86e..ed413f30976 100644
--- a/gcc/testsuite/g++.dg/cpp1z/utf8.C
+++ b/gcc/testsuite/g++.dg/cpp1z/utf8.C
@@ -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
index 00000000000..aa0860b9f63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/char8_t1.C
@@ -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
index 00000000000..71eea7952d3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/char8_t2.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
index b80cc342364..8e1ea48bb1d 100644
--- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
+++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
@@ -471,3 +471,11 @@
#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
index 00000000000..9252ef9dfa6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-aliasing-1.C
@@ -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
index 00000000000..8ed85ccfdcd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C
@@ -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
index 00000000000..7861736689c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C
@@ -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
index 00000000000..27f19fe2dc9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-deduction-1.C
@@ -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
index 00000000000..1daf2969d61
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-deduction-2.C
@@ -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
index 00000000000..6107cb61ecc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-1.C
@@ -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
index 00000000000..df1063f6aa1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-feature-test-macro-2.C
@@ -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
index 00000000000..e2fd67bac72
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-init-1.C
@@ -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
index 00000000000..c713bc12266
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-init-2.C
@@ -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
index 00000000000..f2475094aa5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-keyword-1.C
@@ -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
index 00000000000..8c84e1e79dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-keyword-2.C
@@ -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
index 00000000000..0d6df34d23f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-limits-1.C
@@ -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
index 00000000000..48aa44a6691
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-overload-1.C
@@ -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
index 00000000000..15e28cd6db2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-overload-2.C
@@ -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
index 00000000000..36d411b20db
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-1.C
@@ -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
index 00000000000..06d9b246794
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-predefined-macros-2.C
@@ -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
index 00000000000..c4bc4cb3872
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-sizeof-1.C
@@ -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
index 00000000000..1c2fe360abc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-specialization-1.C
@@ -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
index 00000000000..969e09ecc18
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-specialization-2.C
@@ -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
index 00000000000..6cfb47be3a9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-string-literal-1.C
@@ -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
index 00000000000..f51df72d7ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-string-literal-2.C
@@ -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
index 00000000000..dac4a47eea3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-type-specifier-1.C
@@ -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
index 00000000000..ecc5d1c67c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-type-specifier-2.C
@@ -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
index 00000000000..b77d9a2e6c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-typedef-1.C
@@ -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
index 00000000000..bb20499c26e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-typedef-2.C
@@ -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
index 00000000000..627c263bafe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-udl-1.C
@@ -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
index 00000000000..74cc775e87c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/char8_t-udl-2.C
@@ -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");
diff --git a/gcc/testsuite/g++.dg/ext/utf-array-short-wchar.C b/gcc/testsuite/g++.dg/ext/utf-array-short-wchar.C
index 2ce774abc4a..f37f93c8b73 100644
--- a/gcc/testsuite/g++.dg/ext/utf-array-short-wchar.C
+++ b/gcc/testsuite/g++.dg/ext/utf-array-short-wchar.C
@@ -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." } */
diff --git a/gcc/testsuite/g++.dg/ext/utf-array.C b/gcc/testsuite/g++.dg/ext/utf-array.C
index 21e438693a2..0e403db7e05 100644
--- a/gcc/testsuite/g++.dg/ext/utf-array.C
+++ b/gcc/testsuite/g++.dg/ext/utf-array.C
@@ -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
index 00000000000..0170b36da14
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/utf-cvt-char8_t.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/ext/utf-cxx98.C b/gcc/testsuite/g++.dg/ext/utf-cxx98.C
index 365118e3964..ada97be5ef6 100644
--- a/gcc/testsuite/g++.dg/ext/utf-cxx98.C
+++ b/gcc/testsuite/g++.dg/ext/utf-cxx98.C
@@ -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 () {}
diff --git a/gcc/testsuite/g++.dg/ext/utf-dflt.C b/gcc/testsuite/g++.dg/ext/utf-dflt.C
index c2b127d5dda..6bf020f7cdb 100644
--- a/gcc/testsuite/g++.dg/ext/utf-dflt.C
+++ b/gcc/testsuite/g++.dg/ext/utf-dflt.C
@@ -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 () {}
diff --git a/gcc/testsuite/g++.dg/ext/utf-gnuxx98.C b/gcc/testsuite/g++.dg/ext/utf-gnuxx98.C
index b3be121e2dc..dc9a814c161 100644
--- a/gcc/testsuite/g++.dg/ext/utf-gnuxx98.C
+++ b/gcc/testsuite/g++.dg/ext/utf-gnuxx98.C
@@ -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
index 00000000000..a7d8b16a285
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/utf-type-char8_t.C
@@ -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();
+}
diff --git a/gcc/testsuite/g++.dg/ext/utf8-1.C b/gcc/testsuite/g++.dg/ext/utf8-1.C
index a1a3518a497..089465fa518 100644
--- a/gcc/testsuite/g++.dg/ext/utf8-1.C
+++ b/gcc/testsuite/g++.dg/ext/utf8-1.C
@@ -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
diff --git a/gcc/testsuite/g++.dg/ext/utf8-2.C b/gcc/testsuite/g++.dg/ext/utf8-2.C
index bafe6e8351c..b13d55f1139 100644
--- a/gcc/testsuite/g++.dg/ext/utf8-2.C
+++ b/gcc/testsuite/g++.dg/ext/utf8-2.C
@@ -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.";
diff --git a/gcc/testsuite/g++.dg/warn/Wformat-ranges-c++11.C b/gcc/testsuite/g++.dg/warn/Wformat-ranges-c++11.C
index a4d3fff2967..653171b4357 100644
--- a/gcc/testsuite/g++.dg/warn/Wformat-ranges-c++11.C
+++ b/gcc/testsuite/g++.dg/warn/Wformat-ranges-c++11.C
@@ -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. */
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 2206b91d3ba..bcc0227bdd8 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -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
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index ddcd3be6b8f..b34b4856922 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -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;
diff --git a/libiberty/cp-demangle.h b/libiberty/cp-demangle.h
index b739bdfb8a4..92191cf3ea8 100644
--- a/libiberty/cp-demangle.h
+++ b/libiberty/cp-demangle.h
@@ -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