Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -659,6 +659,10 @@ def warn_cxx20_compat_consteval_if : Warning< "consteval if is incompatible with C++ standards before C++2b">, InGroup, DefaultIgnore; +def err_type_definition_cannot_be_modified : Error< + "%0 type definition cannot be modified inside a scope containing " + "'#pragma clang fp eval_method(%1)' when a command line " + "option 'ffp-eval-method=%2' is used">; def ext_init_statement : ExtWarn< "'%select{if|switch}0' initialization statements are a C++17 extension">, Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -1111,6 +1111,19 @@ return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult); } +StringRef EvalMethodValToStr(LangOptions::FPEvalMethodKind Kind) { + switch (Kind) { + case LangOptions::FPEvalMethodKind::FEM_Double: + return "double"; + case LangOptions::FPEvalMethodKind::FEM_Extended: + return "extended"; + case LangOptions::FPEvalMethodKind::FEM_Source: + return "source"; + default: + llvm_unreachable("unexpected eval method value"); + } +} + /// ParseCompoundStatementBody - Parse a sequence of statements optionally /// followed by a label and invoke the ActOnCompoundStmt action. This expects /// the '{' to be the current token, and consume the '}' at the end of the @@ -1182,6 +1195,19 @@ continue; StmtResult R; + if (Tok.is(tok::identifier)) { + if (Tok.getIdentifierInfo()->getName().str() == "float_t" || + Tok.getIdentifierInfo()->getName().str() == "double_t") { + if (getLangOpts().getFPEvalMethod() != + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine && + PP.getLastFPEvalPragmaLocation().isValid() && + PP.getCurrentFPEvalMethod() != getLangOpts().getFPEvalMethod()) + Diag(Tok.getLocation(), diag::err_type_definition_cannot_be_modified) + << Tok.getIdentifierInfo()->getName().str() + << EvalMethodValToStr(PP.getCurrentFPEvalMethod()) + << EvalMethodValToStr(getLangOpts().getFPEvalMethod()); + } + } if (Tok.isNot(tok::kw___extension__)) { R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); } else { Index: clang/test/CodeGen/Inputs/math.h =================================================================== --- /dev/null +++ clang/test/CodeGen/Inputs/math.h @@ -0,0 +1,43 @@ +#ifdef __FLT_EVAL_METHOD__ +#if __FLT_EVAL_METHOD__ == -1 +#define __GLIBC_FLT_EVAL_METHOD 2 +#else +#define __GLIBC_FLT_EVAL_METHOD __FLT_EVAL_METHOD__ +#endif +#elif defined __x86_64__ +#define __GLIBC_FLT_EVAL_METHOD 0 +#else +#define __GLIBC_FLT_EVAL_METHOD 2 +#endif + +# if __GLIBC_FLT_EVAL_METHOD == 0 || __GLIBC_FLT_EVAL_METHOD == 16 +typedef float float_t; +typedef double double_t; +# elif __GLIBC_FLT_EVAL_METHOD == 1 +typedef double float_t; +typedef double double_t; +# elif __GLIBC_FLT_EVAL_METHOD == 2 +typedef long double float_t; +typedef long double double_t; +# elif __GLIBC_FLT_EVAL_METHOD == 32 +typedef _Float32 float_t; +typedef double double_t; +# elif __GLIBC_FLT_EVAL_METHOD == 33 +typedef _Float32x float_t; +typedef _Float32x double_t; +# elif __GLIBC_FLT_EVAL_METHOD == 64 +typedef _Float64 float_t; +typedef _Float64 double_t; +# elif __GLIBC_FLT_EVAL_METHOD == 65 +typedef _Float64x float_t; +typedef _Float64x double_t; +# elif __GLIBC_FLT_EVAL_METHOD == 128 +typedef _Float128 float_t; +typedef _Float128 double_t; +# elif __GLIBC_FLT_EVAL_METHOD == 129 +typedef _Float128x float_t; +typedef _Float128x double_t; +# else +# error "Unknown __GLIBC_FLT_EVAL_METHOD" +# endif + Index: clang/test/CodeGen/abi-check-1.c =================================================================== --- /dev/null +++ clang/test/CodeGen/abi-check-1.c @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -emit-llvm -o - %s | FileCheck %s + +// RUN: %clang_cc1 -isystem %S/Inputs -ffp-eval-method=source \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s + +// RUN: not %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -ffp-eval-method=double -emit-obj -o %t %s 2>&1 \ +// RUN: | FileCheck -check-prefix=ERROR-1 %s + +// RUN: not %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -ffp-eval-method=extended -emit-obj -o %t %s 2>&1 \ +// RUN: | FileCheck -check-prefix=ERROR-2 %s + +#include + +float foo1() { +#pragma clang fp eval_method(source) + + float_t a; + double_t b; + // CHECK: alloca float + // CHECK: alloca double + // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when a command line option 'ffp-eval-method=double' is used + // ERROR-1: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when a command line option 'ffp-eval-method=double' is used + // ERROR-2: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when a command line option 'ffp-eval-method=extended' is used + // ERROR-2: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(source)' when a command line option 'ffp-eval-method=extended' is used + return a - b; +} + Index: clang/test/CodeGen/abi-check-2.c =================================================================== --- /dev/null +++ clang/test/CodeGen/abi-check-2.c @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -emit-llvm -o - %s | FileCheck %s + +// RUN: not %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -ffp-eval-method=source -emit-obj -o %t %s 2>&1 \ +// RUN: | FileCheck -check-prefix=ERROR-1 %s + +// RUN: %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -ffp-eval-method=double -emit-llvm -o - %s \ +// RUN: | FileCheck -check-prefix=CHECK-DBL %s + +// RUN: not %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -ffp-eval-method=extended -emit-obj -o %t %s 2>&1 \ +// RUN: | FileCheck -check-prefix=ERROR-2 %s + +#include + +float foo1() { +#pragma clang fp eval_method(double) + + float_t a; + double_t b; + // CHECK: alloca float + // CHECK: alloca double + // CHECK-DBL: alloca double + // CHECK-DBL: alloca double + // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when a command line option 'ffp-eval-method=source' is used + // ERROR-1: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when a command line option 'ffp-eval-method=source' is used + // ERROR-2: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when a command line option 'ffp-eval-method=extended' is used + // ERROR-2: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(double)' when a command line option 'ffp-eval-method=extended' is used + return a - b; +} + Index: clang/test/CodeGen/abi-check-3.c =================================================================== --- /dev/null +++ clang/test/CodeGen/abi-check-3.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -emit-llvm -o - %s | FileCheck %s + +// RUN: not %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -ffp-eval-method=source -emit-obj -o %t %s 2>&1 \ +// RUN: | FileCheck -check-prefix=ERROR-1 %s + +// RUN: not %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -ffp-eval-method=double -emit-obj -o %t %s 2>&1 \ +// RUN: | FileCheck -check-prefix=ERROR-2 %s + +// RUN: %clang_cc1 -isystem %S/Inputs -triple x86_64-linux-gnu \ +// RUN: -ffp-eval-method=extended -emit-llvm -o - %s \ +// RUN: | FileCheck -check-prefix=CHECK-EXT %s + +#include + +float foo1() { +#pragma clang fp eval_method(extended) + + float_t a; + double_t b; + // CHECK: alloca float + // CHECK: alloca double + // CHECK-EXT: alloca x86_fp80 + // CHECK-EXT: alloca x86_fp80 + // ERROR-1: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when a command line option 'ffp-eval-method=source' is used + // ERROR-1: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when a command line option 'ffp-eval-method=source' is used + // ERROR-2: error: float_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when a command line option 'ffp-eval-method=double' is used + // ERROR-2: error: double_t type definition cannot be modified inside a scope containing '#pragma clang fp eval_method(extended)' when a command line option 'ffp-eval-method=double' is used + + return a - b; +} +