mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-04 16:41:43 +00:00
When float_t and double_t types are used inside a scope with
a '#pragma clang fp eval_method, it can lead to ABI breakage. See https://godbolt.org/z/56zG4Wo91 This patch prevents this. Differential Revision: https://reviews.llvm.org/D153590
This commit is contained in:
parent
55d0411968
commit
63b0b82fd6
@ -4661,6 +4661,13 @@ The full syntax this pragma supports is
|
||||
a = b[i] * c[i] + e;
|
||||
}
|
||||
|
||||
Note: ``math.h`` defines the typedefs ``float_t`` and ``double_t`` based on the active
|
||||
evaluation method at the point where the header is included, not where the
|
||||
typedefs are used. Because of this, it is unwise to combine these typedefs with
|
||||
``#pragma clang fp eval_method``. To catch obvious bugs, Clang will emit an
|
||||
error for any references to these typedefs within the scope of this pragma;
|
||||
however, this is not a fool-proof protection, and programmers must take care.
|
||||
|
||||
The ``#pragma float_control`` pragma allows precise floating-point
|
||||
semantics and floating-point exception behavior to be specified
|
||||
for a section of the source code. This pragma can only appear at file or
|
||||
|
@ -4193,3 +4193,10 @@ def ReadOnlyPlacement : InheritableAttr {
|
||||
let Subjects = SubjectList<[Record]>;
|
||||
let Documentation = [ReadOnlyPlacementDocs];
|
||||
}
|
||||
|
||||
def AvailableOnlyInDefaultEvalMethod : InheritableAttr {
|
||||
let Spellings = [Clang<"available_only_in_default_eval_method">];
|
||||
let Subjects = SubjectList<[TypedefName], ErrorDiag>;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
|
@ -11558,6 +11558,10 @@ def err_objc_type_args_wrong_arity : Error<
|
||||
"too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">;
|
||||
}
|
||||
|
||||
def err_type_available_only_in_default_eval_method : Error<
|
||||
"cannot use type '%0' within '#pragma clang fp eval_method'; type is set "
|
||||
"according to the default eval method for the translation unit">;
|
||||
|
||||
def err_objc_type_arg_not_id_compatible : Error<
|
||||
"type argument %0 is neither an Objective-C object nor a block type">;
|
||||
|
||||
|
@ -798,13 +798,15 @@ OBJC_AT_KEYWORD(import)
|
||||
OBJC_AT_KEYWORD(available)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Interesting idenitifiers.
|
||||
// Interesting identifiers.
|
||||
//===----------------------------------------------------------------------===//
|
||||
INTERESTING_IDENTIFIER(not_interesting)
|
||||
INTERESTING_IDENTIFIER(FILE)
|
||||
INTERESTING_IDENTIFIER(jmp_buf)
|
||||
INTERESTING_IDENTIFIER(sigjmp_buf)
|
||||
INTERESTING_IDENTIFIER(ucontext_t)
|
||||
INTERESTING_IDENTIFIER(float_t)
|
||||
INTERESTING_IDENTIFIER(double_t)
|
||||
|
||||
// TODO: What to do about context-sensitive keywords like:
|
||||
// bycopy/byref/in/inout/oneway/out?
|
||||
|
@ -6777,6 +6777,10 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
|
||||
case tok::InterestingIdentifierKind::ucontext_t:
|
||||
Context.setucontext_tDecl(NewTD);
|
||||
break;
|
||||
case tok::InterestingIdentifierKind::float_t:
|
||||
case tok::InterestingIdentifierKind::double_t:
|
||||
NewTD->addAttr(AvailableOnlyInDefaultEvalMethodAttr::Create(Context));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -8369,6 +8369,12 @@ static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
|
||||
D->addAttr(FunctionReturnThunksAttr::Create(S.Context, Kind, AL));
|
||||
}
|
||||
|
||||
static void handleAvailableOnlyInDefaultEvalMethod(Sema &S, Decl *D,
|
||||
const ParsedAttr &AL) {
|
||||
assert(isa<TypedefNameDecl>(D) && "This attribute only applies to a typedef");
|
||||
handleSimpleAttribute<AvailableOnlyInDefaultEvalMethodAttr>(S, D, AL);
|
||||
}
|
||||
|
||||
static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
// The 'sycl_kernel' attribute applies only to function templates.
|
||||
const auto *FD = cast<FunctionDecl>(D);
|
||||
@ -9250,6 +9256,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
|
||||
handleFunctionReturnThunksAttr(S, D, AL);
|
||||
break;
|
||||
|
||||
case ParsedAttr::AT_AvailableOnlyInDefaultEvalMethod:
|
||||
handleAvailableOnlyInDefaultEvalMethod(S, D, AL);
|
||||
break;
|
||||
|
||||
// Microsoft attributes:
|
||||
case ParsedAttr::AT_LayoutVersion:
|
||||
handleLayoutVersion(S, D, AL);
|
||||
|
@ -374,6 +374,16 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
||||
|
||||
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
|
||||
|
||||
if (D->hasAttr<AvailableOnlyInDefaultEvalMethodAttr>()) {
|
||||
if (getLangOpts().getFPEvalMethod() !=
|
||||
LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine &&
|
||||
PP.getLastFPEvalPragmaLocation().isValid() &&
|
||||
PP.getCurrentFPEvalMethod() != getLangOpts().getFPEvalMethod())
|
||||
Diag(D->getLocation(),
|
||||
diag::err_type_available_only_in_default_eval_method)
|
||||
<< D->getName();
|
||||
}
|
||||
|
||||
if (auto *VD = dyn_cast<ValueDecl>(D))
|
||||
checkTypeSupport(VD->getType(), Loc, VD);
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
// CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function)
|
||||
// CHECK-NEXT: Assumption (SubjectMatchRule_function, SubjectMatchRule_objc_method)
|
||||
// CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
|
||||
// CHECK-NEXT: AvailableOnlyInDefaultEvalMethod (SubjectMatchRule_type_alias)
|
||||
// CHECK-NEXT: BPFPreserveAccessIndex (SubjectMatchRule_record)
|
||||
// CHECK-NEXT: BTFDeclTag (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record, SubjectMatchRule_field, SubjectMatchRule_type_alias)
|
||||
// CHECK-NEXT: BuiltinAlias (SubjectMatchRule_function)
|
||||
|
26
clang/test/Sema/attr-only-in-default-eval.cpp
Normal file
26
clang/test/Sema/attr-only-in-default-eval.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
typedef float float_t [[clang::available_only_in_default_eval_method]];
|
||||
using double_t __attribute__((available_only_in_default_eval_method)) = double;
|
||||
|
||||
// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
|
||||
class __attribute__((available_only_in_default_eval_method)) C1 {
|
||||
};
|
||||
// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
|
||||
class [[clang::available_only_in_default_eval_method]] C2 {
|
||||
};
|
||||
|
||||
// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
|
||||
struct [[clang::available_only_in_default_eval_method]] S1;
|
||||
// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
|
||||
struct __attribute__((available_only_in_default_eval_method)) S2;
|
||||
|
||||
// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
|
||||
void __attribute__((available_only_in_default_eval_method)) foo();
|
||||
// expected-error@+1{{'available_only_in_default_eval_method' attribute cannot be applied to types}}
|
||||
void [[clang::available_only_in_default_eval_method]] goo();
|
||||
// expected-error@+1{{'available_only_in_default_eval_method' attribute cannot be applied to types}}
|
||||
void bar() [[clang::available_only_in_default_eval_method]];
|
||||
// expected-error@+1{{'available_only_in_default_eval_method' attribute only applies to typedefs}}
|
||||
void barz() __attribute__((available_only_in_default_eval_method));
|
||||
|
102
clang/test/Sema/fp-eval-pragma-with-float-double_t-1.c
Normal file
102
clang/test/Sema/fp-eval-pragma-with-float-double_t-1.c
Normal file
@ -0,0 +1,102 @@
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -DNOERROR %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -DNOERROR %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=source -DNOERROR %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -ffp-eval-method=source \
|
||||
// RUN: -DNOERROR %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=double %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -ffp-eval-method=double %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=extended %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP \
|
||||
// RUN: -ffp-eval-method=extended %s
|
||||
|
||||
|
||||
#ifdef NOERROR
|
||||
// expected-no-diagnostics
|
||||
typedef float float_t;
|
||||
typedef double double_t;
|
||||
#else
|
||||
#ifdef CPP
|
||||
typedef float float_t; //expected-error 9 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
|
||||
typedef double double_t; //expected-error 9 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
#else
|
||||
typedef float float_t; //expected-error 7 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
|
||||
typedef double double_t; //expected-error 7 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
float foo1() {
|
||||
#pragma clang fp eval_method(source)
|
||||
float a;
|
||||
double b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
float foo2() {
|
||||
#pragma clang fp eval_method(source)
|
||||
float_t a;
|
||||
double_t b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
void foo3() {
|
||||
#pragma clang fp eval_method(source)
|
||||
char buff[sizeof(float_t)];
|
||||
char bufd[sizeof(double_t)];
|
||||
buff[1] = bufd[2];
|
||||
}
|
||||
|
||||
float foo4() {
|
||||
#pragma clang fp eval_method(source)
|
||||
typedef float_t FT;
|
||||
typedef double_t DT;
|
||||
FT a;
|
||||
DT b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int foo5() {
|
||||
#pragma clang fp eval_method(source)
|
||||
int t = _Generic( 1.0L, float_t:1, default:0);
|
||||
int v = _Generic( 1.0L, double_t:1, default:0);
|
||||
return t;
|
||||
}
|
||||
|
||||
void foo6() {
|
||||
#pragma clang fp eval_method(source)
|
||||
float f = (float_t)1;
|
||||
double d = (double_t)2;
|
||||
}
|
||||
|
||||
void foo7() {
|
||||
#pragma clang fp eval_method(source)
|
||||
float c1 = (float_t)12;
|
||||
double c2 = (double_t)13;
|
||||
}
|
||||
|
||||
float foo8() {
|
||||
#pragma clang fp eval_method(source)
|
||||
extern float_t f;
|
||||
extern double_t g;
|
||||
return f-g;
|
||||
}
|
||||
|
||||
#ifdef CPP
|
||||
void foo9() {
|
||||
#pragma clang fp eval_method(source)
|
||||
auto resf = [](float_t f) { return f; };
|
||||
auto resd = [](double_t g) { return g; };
|
||||
}
|
||||
|
||||
void foo10() {
|
||||
#pragma clang fp eval_method(source)
|
||||
using Ft = float_t;
|
||||
using Dt = double_t;
|
||||
Ft a;
|
||||
Dt b;
|
||||
}
|
||||
#endif
|
100
clang/test/Sema/fp-eval-pragma-with-float-double_t-2.c
Normal file
100
clang/test/Sema/fp-eval-pragma-with-float-double_t-2.c
Normal file
@ -0,0 +1,100 @@
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -DNOERROR %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -DNOERROR %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=double -DNOERROR %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -ffp-eval-method=double -DNOERROR %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=source %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -ffp-eval-method=source %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=extended %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -ffp-eval-method=extended %s
|
||||
|
||||
#ifdef NOERROR
|
||||
// expected-no-diagnostics
|
||||
typedef float float_t;
|
||||
typedef double double_t;
|
||||
#else
|
||||
#ifdef CPP
|
||||
typedef float float_t; //expected-error 9 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
|
||||
typedef double double_t; //expected-error 9 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
#else
|
||||
typedef float float_t; //expected-error 7 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
|
||||
typedef double double_t; //expected-error 7 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
float foo1() {
|
||||
#pragma clang fp eval_method(double)
|
||||
float a;
|
||||
double b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
float foo2() {
|
||||
#pragma clang fp eval_method(double)
|
||||
float_t a;
|
||||
double_t b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
void foo3() {
|
||||
#pragma clang fp eval_method(double)
|
||||
char buff[sizeof(float_t)];
|
||||
char bufd[sizeof(double_t)];
|
||||
buff[1] = bufd[2];
|
||||
}
|
||||
|
||||
float foo4() {
|
||||
#pragma clang fp eval_method(double)
|
||||
typedef float_t FT;
|
||||
typedef double_t DT;
|
||||
FT a;
|
||||
DT b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int foo5() {
|
||||
#pragma clang fp eval_method(double)
|
||||
int t = _Generic( 1.0L, float_t:1, default:0);
|
||||
int v = _Generic( 1.0L, double_t:1, default:0);
|
||||
return t;
|
||||
}
|
||||
|
||||
void foo6() {
|
||||
#pragma clang fp eval_method(double)
|
||||
float f = (float_t)1;
|
||||
double d = (double_t)2;
|
||||
}
|
||||
|
||||
void foo7() {
|
||||
#pragma clang fp eval_method(double)
|
||||
float c1 = (float_t)12;
|
||||
double c2 = (double_t)13;
|
||||
}
|
||||
|
||||
float foo8() {
|
||||
#pragma clang fp eval_method(double)
|
||||
extern float_t f;
|
||||
extern double_t g;
|
||||
return f-g;
|
||||
}
|
||||
|
||||
#ifdef CPP
|
||||
void foo9() {
|
||||
#pragma clang fp eval_method(double)
|
||||
auto resf = [](float_t f) { return f; };
|
||||
auto resd = [](double_t g) { return g; };
|
||||
}
|
||||
|
||||
void foo10() {
|
||||
#pragma clang fp eval_method(double)
|
||||
using Ft = float_t;
|
||||
using Dt = double_t;
|
||||
Ft a;
|
||||
Dt b;
|
||||
}
|
||||
#endif
|
||||
|
102
clang/test/Sema/fp-eval-pragma-with-float-double_t-3.c
Normal file
102
clang/test/Sema/fp-eval-pragma-with-float-double_t-3.c
Normal file
@ -0,0 +1,102 @@
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -verify -DNOERROR %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -DNOERROR %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=extended -DNOERROR %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP \
|
||||
// RUN: -ffp-eval-method=extended -DNOERROR %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=source %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -ffp-eval-method=source %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -ffp-eval-method=double %s
|
||||
// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -DCPP -ffp-eval-method=double %s
|
||||
|
||||
|
||||
#ifdef NOERROR
|
||||
// expected-no-diagnostics
|
||||
typedef float float_t;
|
||||
typedef double double_t;
|
||||
#else
|
||||
#ifdef CPP
|
||||
typedef float float_t; //expected-error 9 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
|
||||
typedef double double_t; //expected-error 9 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
#else
|
||||
typedef float float_t; //expected-error 7 {{cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
|
||||
typedef double double_t; //expected-error 7 {{cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
float foo1() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
float a;
|
||||
double b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
float foo2() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
float_t a;
|
||||
double_t b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
void foo3() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
char buff[sizeof(float_t)];
|
||||
char bufd[sizeof(double_t)];
|
||||
buff[1] = bufd[2];
|
||||
}
|
||||
|
||||
float foo4() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
typedef float_t FT;
|
||||
typedef double_t DT;
|
||||
FT a;
|
||||
DT b;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int foo5() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
int t = _Generic( 1.0L, float_t:1, default:0);
|
||||
int v = _Generic( 1.0L, double_t:1, default:0);
|
||||
return t;
|
||||
}
|
||||
|
||||
void foo6() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
float f = (float_t)1;
|
||||
double d = (double_t)2;
|
||||
}
|
||||
|
||||
void foo7() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
float c1 = (float_t)12;
|
||||
double c2 = (double_t)13;
|
||||
}
|
||||
|
||||
float foo8() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
extern float_t f;
|
||||
extern double_t g;
|
||||
return f-g;
|
||||
}
|
||||
|
||||
#ifdef CPP
|
||||
void foo9() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
auto resf = [](float_t f) { return f; };
|
||||
auto resd = [](double_t g) { return g; };
|
||||
}
|
||||
|
||||
void foo10() {
|
||||
#pragma clang fp eval_method(extended)
|
||||
using Ft = float_t;
|
||||
using Dt = double_t;
|
||||
Ft a;
|
||||
Dt b;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user