diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -841,6 +841,11 @@ // 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/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -749,6 +749,10 @@ /// #pragma STDC FENV_ROUND... void HandlePragmaFEnvRound(); + /// Handle the annotation token produced for + /// #pragma STDC CX_LIMITED_RANGE... + void HandlePragmaComplexLimitedRange(); + /// 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 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10176,6 +10176,11 @@ /// \#pragma STDC FENV_ACCESS void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled); + /// ActOnPragmaComplexLimitedRange - Called on well formed + /// \#pragma STDC CX_LIMITED_RANGE + void ActOnPragmaComplexLimitedRange(SourceLocation Loc, + LangOptions::ComplexRangeKind Range); + /// Called on well formed '\#pragma clang fp' that has option 'exceptions'. void ActOnPragmaFPExceptions(SourceLocation Loc, LangOptions::FPExceptionModeKind); diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -1023,8 +1023,10 @@ // Verify that this is followed by EOD. LexUnexpandedToken(Tok); - if (Tok.isNot(tok::eod)) + if (Tok.isNot(tok::eod)) { Diag(Tok, diag::ext_pragma_syntax_eod); + DiscardUntilEndOfDirective(); + } return false; } diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -135,7 +135,19 @@ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { tok::OnOffSwitch OOS; - PP.LexOnOffSwitch(OOS); + if (PP.LexOnOffSwitch(OOS)) + return; + + MutableArrayRef Toks(PP.getPreprocessorAllocator().Allocate(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( + static_cast(OOS))); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } }; @@ -799,6 +811,30 @@ Actions.setRoundingMode(PragmaLoc, RM); } +void Parser::HandlePragmaComplexLimitedRange() { + assert(Tok.is(tok::annot_pragma_cx_limited_range)); + tok::OnOffSwitch OOS = + static_cast( + reinterpret_cast(Tok.getAnnotationValue())); + + LangOptions::ComplexRangeKind Range; + switch (OOS) { + case tok::OOS_ON: + Range = LangOptions::CX_Limited; + break; + case tok::OOS_OFF: + Range = LangOptions::CX_Full; + break; + case tok::OOS_DEFAULT: + // Section 7.3.4 says the default is "OFF" here, not implementation-defined. + Range = LangOptions::CX_Full; + break; + } + + SourceLocation PragmaLoc = ConsumeAnnotationToken(); + Actions.ActOnPragmaComplexLimitedRange(PragmaLoc, Range); +} + StmtResult Parser::HandlePragmaCaptured() { assert(Tok.is(tok::annot_pragma_captured)); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -388,6 +388,12 @@ ConsumeAnnotationToken(); return StmtError(); + case tok::annot_pragma_cx_limited_range: + ProhibitAttributes(Attrs); + Diag(Tok, diag::err_pragma_file_or_compound_scope) << "STDC CX_LIMITED_RANGE"; + ConsumeAnnotationToken(); + return StmtError(); + case tok::annot_pragma_float_control: ProhibitAttributes(Attrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control"; @@ -964,6 +970,9 @@ case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); break; + case tok::annot_pragma_cx_limited_range: + HandlePragmaComplexLimitedRange(); + break; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); break; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -791,6 +791,9 @@ case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); return nullptr; + case tok::annot_pragma_cx_limited_range: + HandlePragmaComplexLimitedRange(); + return nullptr; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); return nullptr; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -1165,6 +1165,14 @@ CurFPFeatures = NewFPFeatures.applyOverrides(LO); } +void Sema::ActOnPragmaComplexLimitedRange(SourceLocation Loc, + LangOptions::ComplexRangeKind Range) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + NewFPFeatures.setComplexRangeOverride(Range); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); +} + void Sema::ActOnPragmaFPExceptions(SourceLocation Loc, LangOptions::FPExceptionModeKind FPE) { setExceptionMode(Loc, FPE); diff --git a/clang/test/CodeGen/cx-limited-range-pragma.c b/clang/test/CodeGen/cx-limited-range-pragma.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/cx-limited-range-pragma.c @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=limited -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-LIMITED +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=nonan -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-NO-NAN +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=full -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-FULL + +_Complex float range_limited(_Complex float a, _Complex float b) { +// CHECK-COMMON: @range_limited +// CHECK-COMMON: call{{.*}}complex.fmul{{.*}} #[[LIMITED:[0-9]+]] +// CHECK-COMMON: call{{.*}}complex.fdiv{{.*}} #[[LIMITED]] +#pragma STDC CX_LIMITED_RANGE ON + return a * b + a / b; +} + +_Complex float range_full(_Complex float a, _Complex float b) { +// CHECK-COMMON: @range_full +// CHECK-COMMON: call{{.*}}complex.fmul{{.*}} #[[FULL:[0-9]+]] +// CHECK-COMMON: call{{.*}}complex.fdiv{{.*}} #[[FULL]] +#pragma STDC CX_LIMITED_RANGE OFF + return a * b + a / b; +} + +_Complex float range_default(_Complex float a, _Complex float b) { +// CHECK-LIMITED: @range_default +// CHECK-LIMITED: call{{.*}}complex.fmul{{.*}} #[[LIMITED]] +// CHECK-LIMITED: call{{.*}}complex.fdiv{{.*}} #[[LIMITED]] +// CHECK-NO-NAN: @range_default +// CHECK-NO-NAN: call{{.*}}complex.fmul{{.*}} #[[LIMITED]] +// CHECK-NO-NAN: call{{.*}}complex.fdiv{{.*}} #[[NONAN:[0-9]+]] +// CHECK-FULL: @range_default +// CHECK-FULL: call{{.*}}complex.fmul{{.*}} #[[FULL]] +// CHECK-FULL: call{{.*}}complex.fdiv{{.*}} #[[FULL]] + return a * b + a / b; +} + +_Complex float range_scoped(_Complex float a, _Complex float b) { +// CHECK-COMMON: @range_scoped +// CHECK-COMMON: call{{.*}}complex.fmul{{.*}} #[[FULL]] +// CHECK-COMMON: call{{.*}}complex.fdiv{{.*}} #[[FULL]] +#pragma STDC CX_LIMITED_RANGE OFF + _Complex float res = a * b; + { +#pragma STDC CX_LIMITED_RANGE DEFAULT + res += a / b; + } + return res; +} + +// CHECK-COMMON: attributes #[[LIMITED]] = { "complex-range"="limited" } +// CHECK-COMMON: attributes #[[FULL]] = { "complex-range"="full" } +// CHECK-NO-NAN: attributes #[[NONAN]] = { "complex-range"="no-nan" }