[clang] [C2y] Add octal prefixes, deprecate unprefixed octals (PR #131626)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 17 10:20:24 PDT 2025
================
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 -verify=expected,c2y -pedantic -std=c2y %s
+// RUN: %clang_cc1 -verify=expected,c2y,compat -Wpre-c2y-compat -std=c2y %s
+// RUN: %clang_cc1 -verify=expected,ext -pedantic -std=c23 %s
+// RUN: %clang_cc1 -verify=expected,cpp -pedantic -x c++ -Wno-c11-extensions %s
+
+
+/* WG14 N3353: Clang 21
+ * Obsolete implicitly octal literals and add delimited escape sequences
+ */
+
+constexpr int i = 0234; // c2y-warning {{octal literals without a '0o' prefix are deprecated}}
+constexpr int j = 0o234; /* ext-warning {{octal integer literals are a C2y extension}}
+ cpp-warning {{octal integer literals are a Clang extension}}
+ compat-warning {{octal integer literals are incompatible with standards before C2y}}
+ */
+
+static_assert(i == 156);
+static_assert(j == 156);
+
+// Show that 0O is the same as Oo (tested above)
+static_assert(0O1234 == 0o1234); /* ext-warning 2 {{octal integer literals are a C2y extension}}
+ cpp-warning 2 {{octal integer literals are a Clang extension}}
+ compat-warning 2 {{octal integer literals are incompatible with standards before C2y}}
+ */
+
+// Demonstrate that it works fine in the preprocessor.
+#if 0o123 != 0x53 /* ext-warning {{octal integer literals are a C2y extension}}
+ cpp-warning {{octal integer literals are a Clang extension}}
+ compat-warning {{octal integer literals are incompatible with standards before C2y}}
+ */
+#error "oh no, math stopped working!"
+#endif
+
+// 0 by itself is not deprecated, of course.
+int k = 0;
+
+// Make sure there are no surprises with auto and type deduction. Promotion
+// turns this into an 'int', and 'constexpr' implies 'const'.
+constexpr auto l = 0o1234567; /* ext-warning {{octal integer literals are a C2y extension}}
+ cpp-warning {{octal integer literals are a Clang extension}}
+ compat-warning {{octal integer literals are incompatible with standards before C2y}}
+ */
+static_assert(l == 0x53977);
+static_assert(__extension__ _Generic(typeof(0o1), typeof(01) : 1, default : 0)); /* c2y-warning {{octal literals without a '0o' prefix are deprecated}}
+ compat-warning {{passing a type argument as the first operand to '_Generic' is incompatible with C standards before C2y}}
+ compat-warning {{octal integer literals are incompatible with standards before C2y}}
+ */
+static_assert(__extension__ _Generic(typeof(l), const int : 1, default : 0)); // compat-warning {{passing a type argument as the first operand to '_Generic' is incompatible with C standards before C2y}}
+
+// Note that 0o by itself is an invalid literal.
+int m = 0o; /* expected-error {{invalid suffix 'o' on integer constant}}
+ c2y-warning {{octal literals without a '0o' prefix are deprecated}}
+ */
+
+// Ensure negation works as expected.
+static_assert(-0o1234 == -668); /* ext-warning {{octal integer literals are a C2y extension}}
+ cpp-warning {{octal integer literals are a Clang extension}}
+ compat-warning {{octal integer literals are incompatible with standards before C2y}}
+ */
+
+// FIXME: it would be better to not diagnose the compat and ext warnings when
+// the octal literal is invalid.
+// We expect diagnostics for non-octal digits.
+int n = 0o18; /* expected-error {{invalid digit '8' in octal constant}}
+ compat-warning {{octal integer literals are incompatible with standards before C2y}}
+ ext-warning {{octal integer literals are a C2y extension}}
+ cpp-warning {{octal integer literals are a Clang extension}}
+ */
+int o1 = 0o8; /* expected-error {{invalid suffix 'o8' on integer constant}}
+ c2y-warning {{octal literals without a '0o' prefix are deprecated}}
+ */
+// FIXME: however, it matches the behavior for hex literals in terms of the
+// error reported. Unfortunately, we then go on to think 0 is an octal literal
+// without a prefix, which is again a bit confusing.
+int o2 = 0xG; /* expected-error {{invalid suffix 'xG' on integer constant}}
+ c2y-warning {{octal literals without a '0o' prefix are deprecated}}
+ */
+
+// Ensure digit separators work as expected.
+constexpr int p = 0o0'1'2'3'4'5'6'7; /* compat-warning {{octal integer literals are incompatible with standards before C2y}}
+ ext-warning {{octal integer literals are a C2y extension}}
+ cpp-warning {{octal integer literals are a Clang extension}}
+ */
+static_assert(p == 01234567); // c2y-warning {{octal literals without a '0o' prefix are deprecated}}
+int q = 0o'0'1; /* expected-error {{invalid suffix 'o'0'1' on integer constant}}
+ c2y-warning {{octal literals without a '0o' prefix are deprecated}}
+ */
+
+#define M 0o123
+int r = M; /* compat-warning {{octal integer literals are incompatible with standards before C2y}}
+ ext-warning {{octal integer literals are a C2y extension}}
+ cpp-warning {{octal integer literals are a Clang extension}}
+ */
+
+// Also, test delimited escape sequences. Note, this paper added a delimited
+// escape sequence for octal *and* hex.
+auto a = "\x{12}\o{12}"; /* compat-warning 2 {{delimited escape sequences are incompatible with C standards before C2y}}
----------------
AaronBallman wrote:
Yes, we should, but what does this have to do with octal and hexadecimal escape sequences? ;-) I'll add it as a drive-by.
https://github.com/llvm/llvm-project/pull/131626
More information about the cfe-commits
mailing list