[clang] [C2y] Remove support for _Imaginary (PR #97436)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 2 09:37:39 PDT 2024


https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/97436

WG14 N3274 removed _Imaginary from Annex G. Clang has never fully supported Annex G or _Imaginary, so removal is pretty trivial for us.

Note, we are keeping _Imaginary as a keyword so that we get better diagnostic behavior. This is still conforming because _I makes it a reserved identifier, so it's not available for users to use as an identifier anyway.

>From 1e7a4900130117dc4c215e5ee1fab481f129a01a Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Tue, 2 Jul 2024 12:34:12 -0400
Subject: [PATCH] [C2y] Remove support for _Imaginary

WG14 N3274 removed _Imaginary from Annex G. Clang has never fully
supported Annex G or _Imaginary, so removal is pretty trivial for us.

Note, we are keeping _Imaginary as a keyword so that we get better
diagnostic behavior. This is still conforming because _I makes it a
reserved identifier, so it's not available for users to use as an
identifier anyway.
---
 .../include/clang/Basic/DiagnosticSemaKinds.td |  1 -
 clang/include/clang/Basic/TokenKinds.def       |  5 +++++
 clang/include/clang/Sema/DeclSpec.h            |  4 ++--
 clang/lib/CodeGen/CGExprComplex.cpp            |  5 -----
 clang/lib/Sema/DeclSpec.cpp                    |  6 +++---
 clang/lib/Sema/SemaCodeComplete.cpp            |  3 ++-
 clang/lib/Sema/SemaLookup.cpp                  |  5 ++++-
 clang/lib/Sema/SemaType.cpp                    |  4 +++-
 clang/test/C/C2y/n3274.c                       | 18 ++++++++++++++++++
 clang/www/c_status.html                        |  2 +-
 10 files changed, 38 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/C/C2y/n3274.c

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3df64b2ecef1b..39655bd4f9ef4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7696,7 +7696,6 @@ def err_qualified_objc_access : Error<
 def ext_freestanding_complex : Extension<
   "complex numbers are an extension in a freestanding C99 implementation">;
 
-// FIXME: Remove when we support imaginary.
 def err_imaginary_not_supported : Error<"imaginary types are not supported">;
 
 // Obj-c expressions
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 37d570ca5e75b..e605442590909 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -331,6 +331,11 @@ KEYWORD(_Atomic                     , KEYALL|KEYNOOPENCL)
 KEYWORD(_Bool                       , KEYNOCXX)
 KEYWORD(_Complex                    , KEYALL)
 KEYWORD(_Generic                    , KEYALL)
+// Note, C2y removed support for _Imaginary; we retain it as a keyword because
+// 1) it's a reserved identifier, so we're allowed to steal it, 2) there's no
+// good way to specify a keyword in earlier but not later language modes within
+// this file, 3) this allows us to provide a better diagnostic in case a user
+// does use the keyword.
 KEYWORD(_Imaginary                  , KEYALL)
 KEYWORD(_Noreturn                   , KEYALL)
 KEYWORD(_Static_assert              , KEYALL)
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 23bc780e04979..425b6e2a0b30c 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -269,7 +269,7 @@ class DeclSpec {
 
   enum TSC {
     TSC_unspecified,
-    TSC_imaginary,
+    TSC_imaginary, // Unsupported
     TSC_complex
   };
 
@@ -875,7 +875,7 @@ class DeclSpec {
   }
 
   /// Finish - This does final analysis of the declspec, issuing diagnostics for
-  /// things like "_Imaginary" (lacking an FP type).  After calling this method,
+  /// things like "_Complex" (lacking an FP type).  After calling this method,
   /// DeclSpec is guaranteed self-consistent, even if an error occurred.
   void Finish(Sema &S, const PrintingPolicy &Policy);
 
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 84ad3b566b647..000d4ff5c0698 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -817,8 +817,6 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
     //
     // But we can fold away components which would be zero due to a real
     // operand according to C11 Annex G.5.1p2.
-    // FIXME: C11 also provides for imaginary types which would allow folding
-    // still more of this within the type system.
 
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
     if (Op.LHS.second && Op.RHS.second) {
@@ -1049,9 +1047,6 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
       // delegate to a libcall to handle all of the complexities and minimize
       // underflow/overflow cases. When FastMath is allowed we construct the
       // divide inline using the same algorithm as for integer operands.
-      //
-      // FIXME: We would be able to avoid the libcall in many places if we
-      // supported imaginary types in addition to complex types.
       BinOpInfo LibCallOp = Op;
       // If LHS was a real, supply a null imaginary part.
       if (!LHSi)
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 96c90a60b9682..9a4d52d4b6b71 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -1146,7 +1146,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
 }
 
 /// Finish - This does final analysis of the declspec, rejecting things like
-/// "_Imaginary" (lacking an FP type). After calling this method, DeclSpec is
+/// "_Complex" (lacking an FP type). After calling this method, DeclSpec is
 /// guaranteed to be self-consistent, even if an error occurred.
 void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
   // Before possibly changing their values, save specs as written.
@@ -1331,8 +1331,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
     break;
   }
 
-  // TODO: if the implementation does not implement _Complex or _Imaginary,
-  // disallow their use.  Need information about the backend.
+  // TODO: if the implementation does not implement _Complex, disallow their
+  // use. Need information about the backend.
   if (TypeSpecComplex != TSC_unspecified) {
     if (TypeSpecType == TST_unspecified) {
       S.Diag(TSCLoc, diag::ext_plain_complex)
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index cd1c5f9391ccd..0e4e466aca678 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1805,7 +1805,8 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
   if (LangOpts.C99) {
     // C99-specific
     Results.AddResult(Result("_Complex", CCP_Type));
-    Results.AddResult(Result("_Imaginary", CCP_Type));
+    if (!LangOpts.C2y)
+      Results.AddResult(Result("_Imaginary", CCP_Type));
     Results.AddResult(Result("_Bool", CCP_Type));
     Results.AddResult(Result("restrict", CCP_Type));
   }
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index a4acf3b4fbf41..7851c5d080cf3 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -4983,7 +4983,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
     static const char *const CTypeSpecs[] = {
       "char", "const", "double", "enum", "float", "int", "long", "short",
       "signed", "struct", "union", "unsigned", "void", "volatile",
-      "_Complex", "_Imaginary",
+      "_Complex",
       // storage-specifiers as well
       "extern", "inline", "static", "typedef"
     };
@@ -4991,6 +4991,9 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
     for (const auto *CTS : CTypeSpecs)
       Consumer.addKeywordResult(CTS);
 
+    if (SemaRef.getLangOpts().C99 && !SemaRef.getLangOpts().C2y)
+      Consumer.addKeywordResult("_Imaginary");
+
     if (SemaRef.getLangOpts().C99)
       Consumer.addKeywordResult("restrict");
     if (SemaRef.getLangOpts().Bool || SemaRef.getLangOpts().CPlusPlus)
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 50c15a1aa89e8..b9a975fb3073f 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1423,7 +1423,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
     Result = Context.getVectorType(Result, 128/typeSize, VecKind);
   }
 
-  // FIXME: Imaginary.
+  // _Imaginary was a feature of C99 through C23 but was never supported in
+  // Clang. The feature was removed in C2y, but we retain the unsupported
+  // diagnostic for an improved user experience.
   if (DS.getTypeSpecComplex() == DeclSpec::TSC_imaginary)
     S.Diag(DS.getTypeSpecComplexLoc(), diag::err_imaginary_not_supported);
 
diff --git a/clang/test/C/C2y/n3274.c b/clang/test/C/C2y/n3274.c
new file mode 100644
index 0000000000000..ccdb89f4069de
--- /dev/null
+++ b/clang/test/C/C2y/n3274.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -verify -std=c23 -Wall -pedantic %s
+// RUN: %clang_cc1 -verify -std=c2y -Wall -pedantic %s
+
+/* WG14 N3274: Yes
+ * Remove imaginary types
+ */
+
+// Clang has never supported _Imaginary.
+#ifdef __STDC_IEC_559_COMPLEX__
+#error "When did this happen?"
+#endif
+
+_Imaginary float i; // expected-error {{imaginary types are not supported}}
+
+// _Imaginary is a keyword in older language modes, but doesn't need to be one
+// in C2y or later. However, to improve diagnostic behavior, we retain it as a
+// keyword in all language modes -- it is not available as an identifier.
+static_assert(!__is_identifier(_Imaginary));
diff --git a/clang/www/c_status.html b/clang/www/c_status.html
index ccb39a15b25aa..cf2edb317b4a6 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -1292,7 +1292,7 @@ <h2 id="c2y">C2y implementation status</h2>
     <tr>
       <td>Remove imaginary types</td>
       <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3274.pdf">N3274</a></td>
-      <td class="unknown" align="center">Unknown</td>
+      <td class="full" align="center">Yes</td>
     </tr>
 </table>
 </details>



More information about the cfe-commits mailing list