[clang] [Clang][C++23] Implement core language changes from P1467R9 extended floating-point types and standard names. (PR #78503)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 17 13:14:07 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-static-analyzer-1

@llvm/pr-subscribers-clang

Author: M. Zeeshan Siddiqui (codemzs)

<details>
<summary>Changes</summary>

Implements Core language changes based on [P1467R9](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1467r9.html) Extended floating-point types and standard names.

As per the proposal's definition the following two types are marked as extended floating point: `Float16` (aka `_Float16`) and `Bfloat16` (aka `decltype (0.0bf16)` or `__bf16`). Future work can extend this to support other floating-point types such as `Float32`, `Float64`, and `Float128`.

RFC: https://discourse.llvm.org/t/rfc-c-23-p1467r9-extended-floating-point-types-and-standard-names/70033

This pull request is a carryover from the now offline phabricator differential revision: https://reviews.llvm.org/D149573

---

Patch is 86.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/78503.diff


18 Files Affected:

- (modified) clang/include/clang/AST/ASTContext.h (+41-7) 
- (modified) clang/include/clang/AST/Type.h (+7) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+1) 
- (modified) clang/include/clang/Lex/LiteralSupport.h (+1) 
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h (+4-3) 
- (modified) clang/lib/AST/ASTContext.cpp (+129-8) 
- (modified) clang/lib/AST/StmtPrinter.cpp (+1) 
- (modified) clang/lib/AST/Type.cpp (+27) 
- (modified) clang/lib/Frontend/InitPreprocessor.cpp (+5-1) 
- (modified) clang/lib/Lex/LiteralSupport.cpp (+17) 
- (modified) clang/lib/Sema/Sema.cpp (+17) 
- (modified) clang/lib/Sema/SemaCast.cpp (+13) 
- (modified) clang/lib/Sema/SemaChecking.cpp (+11-6) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+47-13) 
- (modified) clang/lib/Sema/SemaOverload.cpp (+79-2) 
- (added) clang/test/CodeGenCXX/cxx23-fp-ext-std-names-p1467r9.cpp (+499) 
- (added) clang/test/CodeGenCXX/cxx23-vector-bfloat16.cpp (+67) 
- (added) clang/test/Sema/cxx23-fp-ext-std-names-p1467r9.cpp (+505) 


``````````diff
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 3e46a5da3fc043..beec40b4a8197b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -52,6 +52,16 @@ template <typename T, unsigned N> class SmallPtrSet;
 
 namespace clang {
 
+// Conversion ranks introduced in C++23 6.8.6p2 [conv.rank]
+enum FloatingRankCompareResult {
+  FRCR_Unordered,
+  FRCR_Lesser,
+  FRCR_Greater,
+  FRCR_Equal,
+  FRCR_Equal_Lesser_Subrank,
+  FRCR_Equal_Greater_Subrank,
+};
+
 class APValue;
 class ASTMutationListener;
 class ASTRecordLayout;
@@ -1105,8 +1115,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
   CanQualType SatUnsignedShortFractTy, SatUnsignedFractTy,
       SatUnsignedLongFractTy;
   CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
-  CanQualType BFloat16Ty;
-  CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
+  CanQualType BFloat16Ty; // [C++23 6.8.3p5][basic.extended.fp]
+  CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 and [C++23 6.8.3p5][basic.extended.fp]
   CanQualType VoidPtrTy, NullPtrTy;
   CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
   CanQualType BuiltinFnTy;
@@ -2803,14 +2813,38 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// Compare the rank of the two specified floating point types,
   /// ignoring the domain of the type (i.e. 'double' == '_Complex double').
   ///
-  /// If \p LHS > \p RHS, returns 1.  If \p LHS == \p RHS, returns 0.  If
-  /// \p LHS < \p RHS, return -1.
-  int getFloatingTypeOrder(QualType LHS, QualType RHS) const;
+  /// If \p LHS > \p RHS, returns FRCR_Greater. If \p LHS == \p RHS, returns
+  /// FRCR_Equal.  If \p LHS < \p RHS, return FRCR_Lesser. If \p LHS and \p RHS
+  /// are unordered, return FRCR_Unordered. If \p LHS and \p RHS are equal but
+  /// the subrank of \p LHS is greater than \p RHS, return
+  /// FRCR_Equal_Greater_Subrank. If \p LHS and \p RHS are equal but the subrank
+  /// of \p LHS is less than \p RHS, return FRCR_Equal_Lesser_Subrank. Subrank
+  /// and Unordered comparison were introduced in C++23.
+  FloatingRankCompareResult getFloatingTypeOrder(QualType LHS,
+                                                 QualType RHS) const;
 
   /// Compare the rank of two floating point types as above, but compare equal
   /// if both types have the same floating-point semantics on the target (i.e.
-  /// long double and double on AArch64 will return 0).
-  int getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const;
+  /// long double and double on AArch64 will return FRCR_Equal).
+  FloatingRankCompareResult getFloatingTypeSemanticOrder(QualType LHS,
+                                                         QualType RHS) const;
+
+  /// C++23 6.8.2p12 [basic.fundamental]
+  /// Checks if extended floating point rules apply to a pair of types.
+  /// It returns true if both the types are C++23 floating point types and
+  /// at least one of them is a C++23 extended floating point type. It returns
+  /// false for pairs of standard C++23 floating point types.
+  bool doCXX23ExtendedFpTypesRulesApply(QualType T1, QualType T2) const;
+
+  /// C++23 6.8.2p12 [basic.fundamental]
+  /// Returns true if \p Result is FRCR_Lesser or FRCR_Unordered rank.
+  bool
+  isCXX23SmallerOrUnorderedFloatingPointRank(FloatingRankCompareResult Result) const;
+
+  /// C++23 6.8.2p12 [basic.fundamental]
+  /// Returns true if \p Result is FRCR_Equal, FRCR_Equal_Lesser_Subrank or
+  /// FRCR_Equal_Greater_Subrank.
+  bool isCXX23EqualFloatingPointRank(FloatingRankCompareResult Result) const;
 
   unsigned getTargetAddressSpace(LangAS AS) const;
 
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index a7efe78591635e..5dc3ac9e3c7498 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2242,6 +2242,13 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
   bool isComplexType() const;      // C99 6.2.5p11 (complex)
   bool isAnyComplexType() const;   // C99 6.2.5p11 (complex) + Complex Int.
   bool isFloatingType() const;     // C99 6.2.5p11 (real floating + complex)
+  /// C++23 6.8.2p12 [basic.fundamental] (standard floating point + extended
+  /// floating point)
+  bool isCXX23FloatingPointType(const ASTContext &Ctx) const;
+  /// C++23 6.8.2p12 [basic.fundamental] (standard floating point)
+  bool isCXX23StandardFloatingPointType(const ASTContext &Ctx) const;
+  /// C++23 6.8.2p12 [basic.fundamental] (extended floating point)
+  bool isCXX23ExtendedFloatingPointType(const ASTContext &Ctx) const;
   bool isHalfType() const;         // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
   bool isFloat16Type() const;      // C11 extension ISO/IEC TS 18661
   bool isBFloat16Type() const;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 03b0122d1c08f7..d635ea14004284 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8982,6 +8982,7 @@ def err_cast_pointer_to_non_pointer_int : Error<
 def err_nullptr_cast : Error<
   "cannot cast an object of type %select{'nullptr_t' to %1|%1 to 'nullptr_t'}0"
 >;
+def err_cxx23_invalid_implicit_floating_point_cast : Error<"floating point cast results in loss of precision">;
 def err_typecheck_expect_scalar_operand : Error<
   "operand of type %0 where arithmetic or pointer type is required">;
 def err_typecheck_cond_incompatible_operands : Error<
diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h
index 643ddbdad8c87d..c1301e56af97f3 100644
--- a/clang/include/clang/Lex/LiteralSupport.h
+++ b/clang/include/clang/Lex/LiteralSupport.h
@@ -81,6 +81,7 @@ class NumericLiteralParser {
   bool isFract : 1;         // 1.0hr/r/lr/uhr/ur/ulr
   bool isAccum : 1;         // 1.0hk/k/lk/uhk/uk/ulk
   bool isBitInt : 1;        // 1wb, 1uwb (C23)
+  bool isBFloat16 : 1;      // 1.0bf
   uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
 
 
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
index fcc9c02999b3b0..b2cd4cd7c76f12 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
 
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -775,11 +776,11 @@ class SMTConv {
     // If we have two real floating types, convert the smaller operand to the
     // bigger result
     // Note: Safe to skip updating bitwidth because this must terminate
-    int order = Ctx.getFloatingTypeOrder(LTy, RTy);
-    if (order > 0) {
+    FloatingRankCompareResult order = Ctx.getFloatingTypeOrder(LTy, RTy);
+    if ((order == FRCR_Greater) || (order == FRCR_Equal_Greater_Subrank)) {
       RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
       RTy = LTy;
-    } else if (order == 0) {
+    } else if ((order == FRCR_Equal) || (order == FRCR_Equal_Lesser_Subrank)) {
       LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
       LTy = RTy;
     } else {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index d9cefcaa84d7e5..989dee9fca148d 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -112,6 +112,85 @@ enum FloatingRank {
   Ibm128Rank
 };
 
+constexpr unsigned CXX23FloatRankToIndex(clang::BuiltinType::Kind Kind) {
+  switch (Kind) {
+  case clang::BuiltinType::Float16:
+    return 0;
+  case clang::BuiltinType::BFloat16:
+    return 1;
+  case clang::BuiltinType::Float:
+    return 2;
+  case clang::BuiltinType::Double:
+    return 3;
+  case clang::BuiltinType::LongDouble:
+    return 4;
+  default:
+    // Both __float128 and __ibm128 are compiler extensions, not extended floating points.
+    // __float128 also predates the invention of floating-point types.
+    llvm_unreachable("Not a CXX23+ floating point builtin type");
+  }
+}
+
+// C++23 6.8.6p2 [conv.rank]
+// Grid to determine the rank of a floating point type when compared with
+// another floating point type.
+constexpr std::array<std::array<FloatingRankCompareResult, 5>, 5>
+    CXX23FloatingPointConversionRankMap = {
+        {// Float16 x Float16
+         // Float16 x BFloat16
+         // Float16 x Float
+         // Float16 x Double
+         // Float16 x LongDouble
+         {{FloatingRankCompareResult::FRCR_Equal,
+           FloatingRankCompareResult::FRCR_Unordered,
+           FloatingRankCompareResult::FRCR_Lesser,
+           FloatingRankCompareResult::FRCR_Lesser,
+           FloatingRankCompareResult::FRCR_Lesser}},
+
+         // BFloat16 x Float16
+         // BFloat16 x BFloat16
+         // BFloat16 x Float
+         // BFloat16 x Double
+         // BFloat16 x LongDouble
+         {{FloatingRankCompareResult::FRCR_Unordered,
+           FloatingRankCompareResult::FRCR_Equal,
+           FloatingRankCompareResult::FRCR_Lesser,
+           FloatingRankCompareResult::FRCR_Lesser,
+           FloatingRankCompareResult::FRCR_Lesser}},
+
+         // Float x Float16
+         // Float x BFloat16
+         // Float x Float
+         // Float x Double
+         // Float x LongDouble
+         {{FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Equal,
+           FloatingRankCompareResult::FRCR_Lesser,
+           FloatingRankCompareResult::FRCR_Lesser}},
+
+         // Double x Float16
+         // Double x BFloat16
+         // Double x Float
+         // Double x Double
+         // Double x LongDouble
+         {{FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Equal,
+           FloatingRankCompareResult::FRCR_Lesser}},
+
+         // LongDouble x Float16
+         // LongDouble x BFloat16
+         // LongDouble x Float
+         // LongDouble x Double
+         // LongDouble x LongDouble
+         {{FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Greater,
+           FloatingRankCompareResult::FRCR_Equal}}}};
+
 /// \returns The locations that are relevant when searching for Doc comments
 /// related to \p D.
 static SmallVector<SourceLocation, 2>
@@ -7007,27 +7086,69 @@ static FloatingRank getFloatingRank(QualType T) {
   }
 }
 
+/// C++23 6.8.5 [conv.rank]
 /// getFloatingTypeOrder - Compare the rank of the two specified floating
 /// point types, ignoring the domain of the type (i.e. 'double' ==
-/// '_Complex double').  If LHS > RHS, return 1.  If LHS == RHS, return 0. If
-/// LHS < RHS, return -1.
-int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const {
+/// '_Complex double').
+/// If LHS > RHS, return FRCR_Greater.  If LHS == RHS, return FRCR_Equal. If
+/// LHS < RHS, return FRCR_Lesser. If the values representedable by the two
+/// are not subset of each other, return FRCR_Unordered. If LHS == RHS but
+/// LHS has a higher subrank than RHS return FRCR_Equal_Greater_Subrank else
+/// return FRCR_Equal_Lesser_Subrank.
+FloatingRankCompareResult ASTContext::getFloatingTypeOrder(QualType LHS,
+                                                           QualType RHS) const {
+  if (LHS->isCXX23FloatingPointType(*this) &&
+      RHS->isCXX23FloatingPointType(*this)) {
+    BuiltinType::Kind LHSKind;
+    BuiltinType::Kind RHSKind;
+    if (const auto *CT = LHS->getAs<ComplexType>())
+      LHSKind = CT->getElementType()->castAs<BuiltinType>()->getKind();
+    else
+      LHSKind = LHS->castAs<BuiltinType>()->getKind();
+    if (const auto *CT = RHS->getAs<ComplexType>())
+      RHSKind = CT->getElementType()->castAs<BuiltinType>()->getKind();
+    else
+      RHSKind = RHS->castAs<BuiltinType>()->getKind();
+    return CXX23FloatingPointConversionRankMap[CXX23FloatRankToIndex(LHSKind)]
+                                              [CXX23FloatRankToIndex(RHSKind)];
+  }
+
   FloatingRank LHSR = getFloatingRank(LHS);
   FloatingRank RHSR = getFloatingRank(RHS);
 
   if (LHSR == RHSR)
-    return 0;
+    return FRCR_Equal;
   if (LHSR > RHSR)
-    return 1;
-  return -1;
+    return FRCR_Greater;
+  return FRCR_Lesser;
 }
 
-int ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const {
+FloatingRankCompareResult
+ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const {
   if (&getFloatTypeSemantics(LHS) == &getFloatTypeSemantics(RHS))
-    return 0;
+    return FRCR_Equal;
   return getFloatingTypeOrder(LHS, RHS);
 }
 
+bool ASTContext::doCXX23ExtendedFpTypesRulesApply(QualType T1,
+                                                  QualType T2) const {
+  return (((T1->isCXX23FloatingPointType(*this) &&
+            T2->isCXX23FloatingPointType(*this))) &&
+          (T1->isCXX23ExtendedFloatingPointType(*this) ||
+           T2->isCXX23ExtendedFloatingPointType(*this)));
+}
+
+bool ASTContext::isCXX23SmallerOrUnorderedFloatingPointRank(
+    FloatingRankCompareResult Result) const {
+  return (Result == FRCR_Lesser) || (Result == FRCR_Unordered);
+}
+
+bool ASTContext::isCXX23EqualFloatingPointRank(
+    FloatingRankCompareResult Result) const {
+  return (Result == FRCR_Equal) || (Result == FRCR_Equal_Greater_Subrank) ||
+         (Result == FRCR_Equal_Lesser_Subrank);
+}
+
 /// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
 /// routine will assert if passed a built-in type that isn't an integer or enum,
 /// or if it is not canonicalized.
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index c04cb313c3387a..b762b581857abf 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1358,6 +1358,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
   case BuiltinType::Float:      OS << 'F'; break;
   case BuiltinType::LongDouble: OS << 'L'; break;
   case BuiltinType::Float128:   OS << 'Q'; break;
+  case BuiltinType::BFloat16:   OS << "BF16"; break;
   }
 }
 
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index b419fc8836b032..d15b04e46a9c5c 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2192,6 +2192,33 @@ bool Type::isFloatingType() const {
   return false;
 }
 
+bool Type::isCXX23StandardFloatingPointType(const ASTContext &Ctx) const {
+  if (!Ctx.getLangOpts().CPlusPlus23)
+    return false;
+  if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+    return BT->getKind() >= BuiltinType::Float &&
+           BT->getKind() <= BuiltinType::LongDouble;
+  if (const auto *CT = dyn_cast<ComplexType>(CanonicalType))
+    return CT->getElementType()->isCXX23StandardFloatingPointType(Ctx);
+  return false;
+}
+
+bool Type::isCXX23ExtendedFloatingPointType(const ASTContext &Ctx) const {
+  if (!Ctx.getLangOpts().CPlusPlus23)
+    return false;
+  if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+    return BT->getKind() == BuiltinType::Float16 ||
+           BT->getKind() == BuiltinType::BFloat16;
+  if (const auto *CT = dyn_cast<ComplexType>(CanonicalType))
+    return CT->getElementType()->isCXX23ExtendedFloatingPointType(Ctx);
+  return false;
+}
+
+bool Type::isCXX23FloatingPointType(const ASTContext &Ctx) const {
+  return isCXX23StandardFloatingPointType(Ctx) ||
+         isCXX23ExtendedFloatingPointType(Ctx);
+}
+
 bool Type::hasFloatingRepresentation() const {
   if (const auto *VT = dyn_cast<VectorType>(CanonicalType))
     return VT->getElementType()->isFloatingType();
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index d83128adb511ef..f22ba2f5eae8f2 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -453,8 +453,12 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
     if (LangOpts.CPlusPlus26)
       // FIXME: Use correct value for C++26.
       Builder.defineMacro("__cplusplus", "202400L");
-    else if (LangOpts.CPlusPlus23)
+    else if (LangOpts.CPlusPlus23) {
       Builder.defineMacro("__cplusplus", "202302L");
+      // [C++23] 15.11p2 [cpp.predefined]
+      Builder.defineMacro("__STDCPP_FLOAT16_T__", "1");
+      Builder.defineMacro("__STDCPP_BFLOAT16_T__", "1");
+    }
     //      [C++20] The integer literal 202002L.
     else if (LangOpts.CPlusPlus20)
       Builder.defineMacro("__cplusplus", "202002L");
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index 0a78638f680511..21734c2c19fb54 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -925,6 +925,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
   isAccum = false;
   hadError = false;
   isBitInt = false;
+  isBFloat16 = false;
 
   // This routine assumes that the range begin/end matches the regex for integer
   // and FP constants (specifically, the 'pp-number' regex), and assumes that
@@ -1029,6 +1030,21 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
 
       isFloat = true;
       continue;  // Success.
+    // C++23 5.13.4 [lex.fcon]
+    case 'b':
+    case 'B':
+      if (!isFPConstant)
+        break; // Error for integer constant.
+      if (s + 3 < ThisTokEnd && (s[1] == 'f' || s[1] == 'F') && s[2] == '1' &&
+          s[3] == '6') {
+        if (HasSize)
+          break;
+        HasSize = true;
+        s += 3;
+        isBFloat16 = true;
+        continue;
+      }
+      break;
     case 'q':    // FP Suffix for "__float128"
     case 'Q':
       if (!isFPConstant) break;  // Error for integer constant.
@@ -1161,6 +1177,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
         saw_fixed_point_suffix = false;
         isFract = false;
         isAccum = false;
+        isBFloat16 = false;
       }
 
       saw_ud_suffix = true;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index cafbecebc8a119..e8aeca735260c0 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -700,6 +700,23 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
     }
   }
 
+  // C++23 7.3.10 [conv.double]
+  // A prvalue of floating-point type can be converted to a prvalue of another
+  // floating-point type with a greater or equal conversion rank ([conv.rank]).
+  // A prvalue of standard floating-point type can be converted to a prvalue of
+  // another standard floating-point type
+  if (Context.doCXX23ExtendedFpTypesRulesApply(ExprTy, TypeTy) &&
+      Kind == CK_FloatingCast && E->isPRValue() &&
+      (CCK == CCK_ImplicitConversion)) {
+    if (Context.isCXX23SmallerOrUnorderedFloatingPointRank(
+            Context.getFloatingTypeOrder(TypeTy, ExprTy))) {
+      Diag(E->getExprLoc(),
+           diag::err_cxx23_invalid_implicit_floating_point_cast)
+          << E->getSourceRange();
+      return ExprError();
+    }
+  }
+
   if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
     if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) {
       ImpCast->setType(Ty);
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 9d85568d97b2d2..c905d11b8af82a 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1386,6 +1386,19 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
     }
   }
 
+  // [expr.static.cast] 7.6.1.9p11, A prvalue of floating-point type can
+  // be explicitly converted to any other floating-point type.
+  // Conversion between fp16 and bf16 is not supported yet.
+  if (SrcExpr.get()->isPRValue() &&
+      Self.Context.doCXX23ExtendedFpTypesRulesApply(DestType, SrcType)) {
+    // FIXME: Support for cast between fp16 and bf16 doesn't exist yet.
+    if (!((DestType->isBFloat16Type() || DestType->isFloat16Type()) &&
+          (SrcType->isBFloat16Type() || SrcType->isFlo...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/78503


More information about the cfe-commits mailing list