llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Zahira Ammarguellat (zahiraam)

<details>
<summary>Changes</summary>

This patch adds the #pragma CX_LIMITED_RANGE defined in the C specification. 

It also adds the options -f[no]cx-limited-range and -f[no]cx-fortran-rules. 
Their behavior is like the gcc’s command line options.


---

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


14 Files Affected:

- (modified) clang/include/clang/Basic/FPOptions.def (+2) 
- (modified) clang/include/clang/Basic/LangOptions.def (+3) 
- (modified) clang/include/clang/Basic/TokenKinds.def (+5) 
- (modified) clang/include/clang/Driver/Options.td (+17) 
- (modified) clang/include/clang/Parse/Parser.h (+4) 
- (modified) clang/include/clang/Sema/Sema.h (+4) 
- (modified) clang/lib/CodeGen/CGExprComplex.cpp (+135-23) 
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+34) 
- (modified) clang/lib/Parse/ParsePragma.cpp (+39-1) 
- (modified) clang/lib/Parse/ParseStmt.cpp (+10) 
- (modified) clang/lib/Parse/Parser.cpp (+3) 
- (modified) clang/lib/Sema/SemaAttr.cpp (+7) 
- (added) clang/test/CodeGen/cx-complex-range.c (+79) 
- (added) clang/test/CodeGen/pragma-cx-limited-range.c (+150) 


``````````diff
diff --git a/clang/include/clang/Basic/FPOptions.def 
b/clang/include/clang/Basic/FPOptions.def
index 5b923a1944e50..b633004386eb0 100644
--- a/clang/include/clang/Basic/FPOptions.def
+++ b/clang/include/clang/Basic/FPOptions.def
@@ -28,4 +28,6 @@ OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, 
AllowApproxFunc)
 OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, 
FPEvalMethod)
 OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, 
Float16ExcessPrecision)
 OPTION(MathErrno, bool, 1, BFloat16ExcessPrecision)
+OPTION(CxLimitedRange, bool, 1, MathErrno)
+OPTION(CxFortranRules, bool, 1, CxLimitedRange)
 #undef OPTION
diff --git a/clang/include/clang/Basic/LangOptions.def 
b/clang/include/clang/Basic/LangOptions.def
index c0ea4ecb9806a..5ac0b9143e223 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -219,6 +219,9 @@ BENIGN_LANGOPT(NoSignedZero      , 1, 0, "Permit Floating 
Point optimization wit
 BENIGN_LANGOPT(AllowRecip        , 1, 0, "Permit Floating Point reciprocal")
 BENIGN_LANGOPT(ApproxFunc        , 1, 0, "Permit Floating Point approximation")
 
+LANGOPT(CxLimitedRange, 1, 0, "Enable use of algebraic expansions of complex 
arithmetics.")
+LANGOPT(CxFortranRules, 1, 0, "Enable use of range reduction for complex 
arithmetics.")
+
 BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for 
__weak/__strong ivars")
 
 BENIGN_LANGOPT(AccessControl     , 1, 1, "C++ access control")
diff --git a/clang/include/clang/Basic/TokenKinds.def 
b/clang/include/clang/Basic/TokenKinds.def
index 94db56a9fd5d7..5cd81a66ab57b 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -904,6 +904,11 @@ PRAGMA_ANNOTATION(pragma_fenv_access_ms)
 // handles them.
 PRAGMA_ANNOTATION(pragma_fenv_round)
 
+// Annotation for #pragma STDC CX_LIMITED_RANGE
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+PRAGMA_ANNOTATION(pragma_cx_limited_range)
+
 // Annotation for #pragma float_control
 // The lexer produces these so that they only take effect when the parser
 // handles them.
diff --git a/clang/include/clang/Driver/Options.td 
b/clang/include/clang/Driver/Options.td
index ff2130c93f28e..5efce223d4b8e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1001,6 +1001,23 @@ defm offload_uniform_block : 
BoolFOption<"offload-uniform-block",
   NegFlag<SetFalse, [], [ClangOption, CC1Option], "Don't assume">,
   BothFlags<[], [ClangOption], " that kernels are launched with uniform block 
sizes (default true for CUDA/HIP and false otherwise)">>;
 
+def fcx_limited_range : Joined<["-"], "fcx-limited-range">,
+  Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Basic algebraic expansions of complex arithmetic operations "
+           "involving are enabled.">,
+  MarshallingInfoFlag<LangOpts<"CxLimitedRange">>;
+def fno_cx_limited_range : Joined<["-"], "fno-cx-limited-range">,
+  Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Basic algebraic expansions of complex arithmetic operations "
+           "involving are enabled.">;
+def fcx_fortran_rules : Joined<["-"], "fcx-fortran-rules">,
+  Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Range reduction is enabled for complex arithmetic operations.">,
+  MarshallingInfoFlag<LangOpts<"CxFortranRules">>;
+def fno_cx_fortran_rules : Joined<["-"], "fno-cx-fortran-rules">,
+  Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Range reduction is disabled for complex arithmetic operations.">;
+
 // OpenCL-only Options
 def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 0e969f341bbe1..8f2b4d50fd59e 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -767,6 +767,10 @@ class Parser : public CodeCompletionHandler {
   /// #pragma STDC FENV_ROUND...
   void HandlePragmaFEnvRound();
 
+  /// Handle the annotation token produced for
+  /// #pragma STDC CX_LIMITED_RANGE...
+  void HandlePragmaCXLimitedRange();
+
   /// Handle the annotation token produced for
   /// #pragma float_control
   void HandlePragmaFloatControl();
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5bef0335f7891..f206f5de1310e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10948,6 +10948,10 @@ class Sema final {
   /// \#pragma STDC FENV_ACCESS
   void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled);
 
+  /// ActOnPragmaCXLimitedRange - Called on well formed
+  /// \#pragma STDC CX_LIMITED_RANGE
+  void ActOnPragmaCXLimitedRange(SourceLocation Loc, bool IsEnabled);
+
   /// Called on well formed '\#pragma clang fp' that has option 'exceptions'.
   void ActOnPragmaFPExceptions(SourceLocation Loc,
                                LangOptions::FPExceptionModeKind);
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp 
b/clang/lib/CodeGen/CGExprComplex.cpp
index f3cbd1d0451eb..4b559a5dc7479 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -275,6 +275,10 @@ class ComplexExprEmitter
   ComplexPairTy EmitBinSub(const BinOpInfo &Op);
   ComplexPairTy EmitBinMul(const BinOpInfo &Op);
   ComplexPairTy EmitBinDiv(const BinOpInfo &Op);
+  ComplexPairTy EmitAlgebraicDiv(llvm::Value *A, llvm::Value *B, llvm::Value 
*C,
+                                 llvm::Value *D);
+  ComplexPairTy EmitRangeReductionDiv(llvm::Value *A, llvm::Value *B,
+                                      llvm::Value *C, llvm::Value *D);
 
   ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName,
                                         const BinOpInfo &Op);
@@ -761,6 +765,21 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const 
BinOpInfo &Op) {
 
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
     if (Op.LHS.second && Op.RHS.second) {
+      // (a+ib)*(c+id) = (ac-bd)+i(bc+ad)
+      if (Op.FPFeatures.getCxLimitedRange() ||
+          CGF.getLangOpts().CxLimitedRange) {
+        llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second;
+        llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second;
+
+        llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // ac
+        llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // bd
+        llvm::Value *DSTr = Builder.CreateFSub(AC, BD);   // ac-bd
+
+        llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // bc
+        llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // ad
+        llvm::Value *DSTi = Builder.CreateFAdd(BC, AD);   // bc+ad
+        return ComplexPairTy(DSTr, DSTi);
+      }
       // If both operands are complex, emit the core math directly, and then
       // test for NaNs. If we find NaNs in the result, we delegate to a libcall
       // to carefully re-compute the correct infinity representation if
@@ -846,6 +865,105 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const 
BinOpInfo &Op) {
   return ComplexPairTy(ResR, ResI);
 }
 
+ComplexPairTy ComplexExprEmitter::EmitAlgebraicDiv(llvm::Value *LHSr,
+                                                   llvm::Value *LHSi,
+                                                   llvm::Value *RHSr,
+                                                   llvm::Value *RHSi) {
+  // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
+  llvm::Value *DSTr, *DSTi;
+
+  llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
+  llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
+  llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD);  // ac+bd
+
+  llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
+  llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
+  llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD);  // cc+dd
+
+  llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
+  llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
+  llvm::Value *BCmAD = Builder.CreateFSub(BC, AD);  // bc-ad
+
+  DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
+  DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
+  return ComplexPairTy(DSTr, DSTi);
+}
+
+/// EmitFAbs - Emit a call to @llvm.fabs.
+static llvm::Value *EmitllvmFAbs(CodeGenFunction &CGF, llvm::Value *Value) {
+  llvm::Function *Func =
+      CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Value->getType());
+  llvm::Value *Call = CGF.Builder.CreateCall(Func, Value);
+  return Call;
+}
+
+ComplexPairTy ComplexExprEmitter::EmitRangeReductionDiv(llvm::Value *LHSr,
+                                                        llvm::Value *LHSi,
+                                                        llvm::Value *RHSr,
+                                                        llvm::Value *RHSi) {
+  // (a + ib) / (c + id) = (e + if)
+  llvm::Value *FAbsRHSr = EmitllvmFAbs(CGF, RHSr); // |c|
+  llvm::Value *FAbsRHSi = EmitllvmFAbs(CGF, RHSi); // |d|
+  // |c| >= |d|
+  llvm::Value *IsR = Builder.CreateFCmpUGT(FAbsRHSr, FAbsRHSi, "abs_cmp");
+
+  llvm::BasicBlock *TrueBB = CGF.createBasicBlock("true_bb_name");
+  llvm::BasicBlock *FalseBB = CGF.createBasicBlock("false_bb_name");
+  llvm::BasicBlock *ContBB = CGF.createBasicBlock("cont_bb");
+  Builder.CreateCondBr(IsR, TrueBB, FalseBB);
+
+  CGF.EmitBlock(TrueBB);
+  // abs(c) >= abs(d)
+  // r = d/c
+  // tmp = c + rd
+  // e = (a + br)/tmp
+  // f = (b - ar)/tmp
+  llvm::Value *DdC = Builder.CreateFDiv(RHSi, RHSr); // d/c
+
+  llvm::Value *RD = Builder.CreateFMul(DdC, RHSi);   // (d/c)d
+  llvm::Value *CpRD = Builder.CreateFAdd(RHSr, RD);  // c+((d/c)d)
+
+  llvm::Value *T3 = Builder.CreateFMul(LHSi, DdC);   // b(d/c)
+  llvm::Value *T4 = Builder.CreateFAdd(LHSr, T3);    // a+b(d/c)
+  llvm::Value *DSTTr = Builder.CreateFDiv(T4, CpRD); // (a+b(d/c))/(c+(d/c)d)
+
+  llvm::Value *T5 = Builder.CreateFMul(LHSr, DdC);   // ar
+  llvm::Value *T6 = Builder.CreateFSub(LHSi, T5);    // b-ar
+  llvm::Value *DSTTi = Builder.CreateFDiv(T6, CpRD); // (b-a(d/c))/(c+(d/c)d)
+  Builder.CreateBr(ContBB);
+
+  CGF.EmitBlock(FalseBB);
+  // abs(c) < abs(d)
+  // r = c/d
+  // tmp = d + rc
+  // e = (ar + b)/tmp
+  // f = (br - a)/tmp
+  llvm::Value *CdD = Builder.CreateFDiv(RHSr, RHSi);  // c/d
+
+  llvm::Value *RC = Builder.CreateFMul(CdD, RHSr);    // (c/d)c
+  llvm::Value *DpRC = Builder.CreateFAdd(RHSi, RC);   // d+(c/d)c
+
+  llvm::Value *T7 = Builder.CreateFAdd(CdD, RHSi);    // (c/d)+b
+  llvm::Value *T8 = Builder.CreateFMul(LHSr, T7);     // a((c/d)+b)
+  llvm::Value *DSTFr = Builder.CreateFDiv(T8, DpRC);  // 
(a((c/d)+b)/(d+(c/d)c))
+
+  llvm::Value *T9 = Builder.CreateFSub(CdD, LHSr);    // (c/d)-a
+  llvm::Value *T10 = Builder.CreateFMul(RHSi, T9);    // b((c/d)-a)
+  llvm::Value *DSTFi =
+      Builder.CreateFDiv(T10, DpRC); // (b((c/d)-a))/(d+(c/d)c))
+  Builder.CreateBr(ContBB);
+
+  // Phi together the computation paths.
+  CGF.EmitBlock(ContBB);
+  llvm::PHINode *VALr = Builder.CreatePHI(DSTTr->getType(), 2);
+  VALr->addIncoming(DSTTr, TrueBB);
+  VALr->addIncoming(DSTFr, FalseBB);
+  llvm::PHINode *VALi = Builder.CreatePHI(DSTTi->getType(), 2);
+  VALi->addIncoming(DSTTi, TrueBB);
+  VALi->addIncoming(DSTFi, FalseBB);
+  return ComplexPairTy(VALr, VALi);
+}
+
 // See C11 Annex G.5.1 for the semantics of multiplicative operators on complex
 // typed values.
 ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
@@ -854,15 +972,23 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const 
BinOpInfo &Op) {
 
   llvm::Value *DSTr, *DSTi;
   if (LHSr->getType()->isFloatingPointTy()) {
-    // If we have a complex operand on the RHS and FastMath is not allowed, we
-    // 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.
     CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
-    if (RHSi && !CGF.getLangOpts().FastMath) {
+    if (RHSi && CGF.getLangOpts().CxFortranRules &&
+        !Op.FPFeatures.getCxLimitedRange()) {
+      return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi);
+    } else if (RHSi && (Op.FPFeatures.getCxLimitedRange() ||
+                 CGF.getLangOpts().CxLimitedRange)) {
+      if (!LHSi)
+        LHSi = llvm::Constant::getNullValue(RHSi->getType());
+      return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
+    } else if (RHSi && !CGF.getLangOpts().FastMath) {
+      // If we have a complex operand on the RHS and FastMath is not allowed, 
we
+      // 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)
@@ -888,21 +1014,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const 
BinOpInfo &Op) {
       if (!LHSi)
         LHSi = llvm::Constant::getNullValue(RHSi->getType());
 
-      // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
-      llvm::Value *AC = Builder.CreateFMul(LHSr, RHSr); // a*c
-      llvm::Value *BD = Builder.CreateFMul(LHSi, RHSi); // b*d
-      llvm::Value *ACpBD = Builder.CreateFAdd(AC, BD); // ac+bd
-
-      llvm::Value *CC = Builder.CreateFMul(RHSr, RHSr); // c*c
-      llvm::Value *DD = Builder.CreateFMul(RHSi, RHSi); // d*d
-      llvm::Value *CCpDD = Builder.CreateFAdd(CC, DD); // cc+dd
-
-      llvm::Value *BC = Builder.CreateFMul(LHSi, RHSr); // b*c
-      llvm::Value *AD = Builder.CreateFMul(LHSr, RHSi); // a*d
-      llvm::Value *BCmAD = Builder.CreateFSub(BC, AD); // bc-ad
-
-      DSTr = Builder.CreateFDiv(ACpBD, CCpDD);
-      DSTi = Builder.CreateFDiv(BCmAD, CCpDD);
+      return EmitAlgebraicDiv(LHSr, LHSi, RHSr, RHSi);
     } else {
       assert(LHSi && "Can have at most one non-complex operand!");
 
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 129adfb9fcc74..495ccc82e8c45 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -2807,6 +2807,9 @@ static void RenderFloatingPointOptions(const ToolChain 
&TC, const Driver &D,
   bool StrictFPModel = false;
   StringRef Float16ExcessPrecision = "";
   StringRef BFloat16ExcessPrecision = "";
+  StringRef CxLimitedRange = "NoCxLimiteRange";
+  StringRef CxFortranRules = "NoCxFortranRules";
+  StringRef Range = "";
 
   if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
     CmdArgs.push_back("-mlimit-float-precision");
@@ -2819,6 +2822,28 @@ static void RenderFloatingPointOptions(const ToolChain 
&TC, const Driver &D,
     switch (optID) {
     default:
       break;
+    case options::OPT_fcx_limited_range: {
+      if (Range == "")
+        Range = "CxLimitedRange";
+      else
+        D.Diag(clang::diag::err_drv_incompatible_options)
+            << "fcx-limited-range" << Range;
+      break;
+    }
+    case options::OPT_fno_cx_limited_range:
+      Range = "NoCxLimitedRange";
+      break;
+    case options::OPT_fcx_fortran_rules: {
+      if (Range == "")
+        Range = "CxFortranRules";
+      else
+        D.Diag(clang::diag::err_drv_incompatible_options)
+            << "fcx-fortan-rules" << Range;
+      break;
+    }
+    case options::OPT_fno_cx_fortran_rules:
+      CxFortranRules = "NoCxFortranRules";
+      break;
     case options::OPT_ffp_model_EQ: {
       // If -ffp-model= is seen, reset to fno-fast-math
       HonorINFs = true;
@@ -3240,6 +3265,15 @@ static void RenderFloatingPointOptions(const ToolChain 
&TC, const Driver &D,
   if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow,
                    options::OPT_fstrict_float_cast_overflow, false))
     CmdArgs.push_back("-fno-strict-float-cast-overflow");
+
+   if (const Arg *A = Args.getLastArg(options::OPT_fcx_limited_range))
+        CmdArgs.push_back("-fcx-limited-range");
+   if (const Arg *A = Args.getLastArg(options::OPT_fcx_fortran_rules))
+     CmdArgs.push_back("-fcx-fortran-rules");
+   if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_limited_range))
+     CmdArgs.push_back("-fno-cx-limited-range");
+   if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_fortran_rules))
+     CmdArgs.push_back("-fno-cx-fortran-rules");
 }
 
 static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index b3178aef64d72..6e4db5da9fdbc 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -137,7 +137,20 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public 
PragmaHandler {
   void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
                     Token &Tok) override {
     tok::OnOffSwitch OOS;
-    PP.LexOnOffSwitch(OOS);
+    if (PP.LexOnOffSwitch(OOS))
+      return;
+
+    MutableArrayRef<Token> Toks(
+        PP.getPreprocessorAllocator().Allocate<Token>(1), 1);
+
+    Toks[0].startToken();
+    Toks[0].setKind(tok::annot_pragma_cx_limited_range);
+    Toks[0].setLocation(Tok.getLocation());
+    Toks[0].setAnnotationEndLoc(Tok.getLocation());
+    Toks[0].setAnnotationValue(
+        reinterpret_cast<void *>(static_cast<uintptr_t>(OOS)));
+    PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
+                        /*IsReinject=*/false);
   }
 };
 
@@ -846,6 +859,31 @@ void Parser::HandlePragmaFEnvRound() {
   Actions.ActOnPragmaFEnvRound(PragmaLoc, RM);
 }
 
+void Parser::HandlePragmaCXLimitedRange() {
+  assert(Tok.is(tok::annot_pragma_cx_limited_range));
+  tok::OnOffSwitch OOS = static_cast<tok::OnOffSwitch>(
+      reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+
+  bool IsEnabled;
+  switch (OOS) {
+  case tok::OOS_ON:
+    IsEnabled = true;
+    break;
+  case tok::OOS_OFF:
+    IsEnabled = false;
+    break;
+  case tok::OOS_DEFAULT:
+    // According to ISO C99 standard chapter 7.3.4, the default value
+    // for the pragma is ``off'. In GCC, the option -fcx-limited-range
+    // controls the default setting of the pragma.
+    IsEnabled = getLangOpts().CxLimitedRange ? true : false;
+    break;
+  }
+
+  SourceLocation PragmaLoc = ConsumeAnnotationToken();
+  Actions.ActOnPragmaCXLimitedRange(PragmaLoc, IsEnabled);
+}
+
 StmtResult Parser::HandlePragmaCaptured()
 {
   assert(Tok.is(tok::annot_pragma_captured));
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 2531147c23196..b6c987c4b046b 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -447,6 +447,13 @@ StmtResult 
Parser::ParseStatementOrDeclarationAfterAttributes(
     ConsumeAnnotationToken();
     return StmtError();
 
+  case tok::annot_pragma_cx_limited_range:
+    ProhibitAttributes(CXX11Attrs);
+    Diag(Tok, diag::err_pragma_file_or_compound_scope)
+        << "STDC CX_LIMITED_RANGE";
+    ConsumeAnnotationToken();
+    return StmtError();
+
   case tok::annot_pragma_float_control:
     ProhibitAttributes(CXX11Attrs);
     ProhibitAttributes(GNUAttrs);
@@ -1047,6 +1054,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
     case tok::annot_pragma_fenv_round:
       HandlePragmaFEnvRound();
       break;
+    case tok::annot_pragma_cx_limited_range:
+      HandlePragmaCXLimitedRange();
+      break;
     case tok::annot_pragma_float_control:
       HandlePragmaFloatControl();
       break;
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 0f930248e7717..befa6eba0885f 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -836,6 +836,9 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
   case tok::annot_pragma_fenv_round:
     HandlePragmaFEnvRound();
     return nullptr;
+  case tok::annot_pragma_cx_limited_range:
+    HandlePragmaCXLimitedRange();
+    return nullptr;
   case tok::annot_pragma_float_control:
     HandlePragmaFloatControl();
     return nullptr;
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clan...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/68820
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to