Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -4320,6 +4320,13 @@ a = b[i] * c[i] + e; } +Note: the types ``float_t`` and ``double_t`` are defined in the math header file. +Their definition changes with the eval method. If they are used inside a scope +containing a ``#pragma clang fp eval_method`` their definition end up being +different than what the user might have intended. This can potentially generate +incorrect code, leading to an ABI mismatch. This case is prevented by emitting a +diagnostic. + 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 Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -4150,3 +4150,9 @@ 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]; +} Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11499,6 +11499,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< Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -8255,6 +8255,12 @@ D->addAttr(FunctionReturnThunksAttr::Create(S.Context, Kind, AL)); } +static void handleAvailableOnlyInDefaultEvalMethod(Sema&S, Decl *D, + const ParsedAttr &AL) { + assert(isa(D) && "This attribute only applies to a typedef"); + handleSimpleAttribute(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(D); @@ -9138,6 +9144,9 @@ case ParsedAttr::AT_FunctionReturnThunks: handleFunctionReturnThunksAttr(S, D, AL); break; + case ParsedAttr::AT_AvailableOnlyInDefaultEvalMethod: + handleAvailableOnlyInDefaultEvalMethod(S, D, AL); + break; // Microsoft attributes: case ParsedAttr::AT_LayoutVersion: Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -375,6 +375,16 @@ diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); + if (D->hasAttr()) { + 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(D)) checkTypeSupport(VD->getType(), Loc, VD); Index: clang/test/Sema/Inputs/math.h =================================================================== --- /dev/null +++ clang/test/Sema/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 [[clang::available_only_in_default_eval_method]]; +using double_t [[clang::available_only_in_default_eval_method]] = double; +# elif __GLIBC_FLT_EVAL_METHOD == 1 +typedef double float_t [[clang::available_only_in_default_eval_method]]; +typedef double double_t [[clang::available_only_in_default_eval_method]]; +# elif __GLIBC_FLT_EVAL_METHOD == 2 +typedef long double float_t [[clang::available_only_in_default_eval_method]]; +typedef long double double_t [[clang::available_only_in_default_eval_method]]; +# elif __GLIBC_FLT_EVAL_METHOD == 32 +typedef _Float32 float_t [[clang::available_only_in_default_eval_method]]; +typedef double double_t [[clang::available_only_in_default_eval_method]]; +# elif __GLIBC_FLT_EVAL_METHOD == 33 +typedef _Float32x float_t [[clang::available_only_in_default_eval_method]]; +typedef _Float32x double_t [[clang::available_only_in_default_eval_method]]; +# elif __GLIBC_FLT_EVAL_METHOD == 64 +using float_t [[clang::available_only_in_default_eval_method]] = _Float64 +typedef _Float64 double_t [[clang::available_only_in_default_eval_method]]; +# elif __GLIBC_FLT_EVAL_METHOD == 65 +typedef _Float64x float_t [[clang::available_only_in_default_eval_method]]; +typedef _Float64x double_t [[clang::available_only_in_default_eval_method]]; +# elif __GLIBC_FLT_EVAL_METHOD == 128 +typedef _Float128 float_t [[clang::available_only_in_default_eval_method]]; +typedef _Float128 double_t [[clang::available_only_in_default_eval_method]]; +# elif __GLIBC_FLT_EVAL_METHOD == 129 +typedef _Float128x float_t [[clang::available_only_in_default_eval_method]]; +using double_t __attribute__((available_only_in_default_eval_method)) = _Float128x; +# else +# error "Unknown __GLIBC_FLT_EVAL_METHOD" +# endif + Index: clang/test/Sema/abi-check-1.cpp =================================================================== --- /dev/null +++ clang/test/Sema/abi-check-1.cpp @@ -0,0 +1,121 @@ +// 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 %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 %s + +#include + +float foo1() { +#pragma clang fp eval_method(source) + float a; + double b; + // CHECK: alloca float + // CHECK: alloca double + return a - b; +} + +float foo2() { +#pragma clang fp eval_method(source) + float_t a; + double_t b; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return a - b; +} + +void foo3() { +#pragma clang fp eval_method(source) + char buff[sizeof(float_t)]; + char bufd[sizeof(double_t)]; + // CHECK: alloca [4 x i8] + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + buff[1] = bufd[2]; +} + +float foo4() { +#pragma clang fp eval_method(source) + typedef float_t FT; + typedef double_t DT; + FT a; + DT b; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + 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); + // CHECK: alloca i32 + // CHECK: alloca i32 + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return t; +} + +void foo6() { +#pragma clang fp eval_method(source) + auto resf = [](float_t f) { return f; }; + auto resd = [](double_t g) { return g; }; + // CHECK: alloca %class.anon + // CHECK: alloca %class.anon + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +void foo7() { +#pragma clang fp eval_method(source) + float f = (float_t)1; + double d = (double_t)2; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +void foo8() { +#pragma clang fp eval_method(source) + using Ft = float_t; + using Dt = double_t; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + Ft a; + Dt b; +} + +void foo9() { +#pragma clang fp eval_method(source) + float c1 = (float_t)12; + double c2 = (double_t)13; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +float foo10() { +#pragma clang fp eval_method(source) + extern float_t f; + extern double_t g; + // CHECK: load float + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return f-g; +} Index: clang/test/Sema/abi-check-2.cpp =================================================================== --- /dev/null +++ clang/test/Sema/abi-check-2.cpp @@ -0,0 +1,131 @@ +// 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 %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 %s + +#include + +float foo1() { +#pragma clang fp eval_method(double) + float a; + double b; + // CHECK: alloca float + // CHECK: alloca double + return a - b; +} + +float foo2() { +#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: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return a - b; +} + +void foo3() { +#pragma clang fp eval_method(double) + char buff[sizeof(float_t)]; + char bufd[sizeof(double_t)]; + // CHECK: alloca [4 x i8] + // CHECK: alloca [8 x i8] + // CHECK-DBL: alloca [8 x i8] + // CHECK-DBL: alloca [8 x i8] + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + buff[1] = bufd[2]; +} + +float foo4() { +#pragma clang fp eval_method(double) + typedef float_t FT; + typedef double_t DT; + FT a; + DT b; + // CHECK: alloca float + // CHECK: alloca double + // CHECK-DBL: alloca double + // CHECK-DBL: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + 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); + // CHECK: alloca i32 + // CHECK: alloca i32 + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return t; +} + +void foo6() { +#pragma clang fp eval_method(double) + auto resf = [](float_t f) { return f; }; + auto resd = [](double_t g) { return g; }; + // CHECK: alloca %class.anon + // CHECK: alloca %class.anon + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +void foo7() { +#pragma clang fp eval_method(double) + float f = (float_t)1; + double d = (double_t)2; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +void foo8() { +#pragma clang fp eval_method(double) + using Ft = float_t; + using Dt = double_t; + // CHECK: alloca float + // CHECK: alloca double + // CHECK-DBL: alloca double + // CHECK-DBL: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + Ft a; + Dt b; +} + +void foo9() { +#pragma clang fp eval_method(double) + float c1 = (float_t)12; + double c2 = (double_t)13; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +float foo10() { +#pragma clang fp eval_method(double) + extern float_t f; + extern double_t g; + // CHECK: load double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return f-g; +} Index: clang/test/Sema/abi-check-3.cpp =================================================================== --- /dev/null +++ clang/test/Sema/abi-check-3.cpp @@ -0,0 +1,133 @@ +// 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 %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 %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 a; + double b; + // CHECK: alloca float + // CHECK: alloca double + return a - b; +} + +float foo2() { +#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: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return a - b; +} + +void foo3() { +#pragma clang fp eval_method(extended) + char buff[sizeof(float_t)]; + char bufd[sizeof(double_t)]; + // CHECK: alloca [4 x i8] + // CHECK: alloca [8 x i8] + // CHECK-DBL: alloca [8 x i8] + // CHECK-DBL: alloca [8 x i8] + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + buff[1] = bufd[2]; +} + +float foo4() { +#pragma clang fp eval_method(extended) + typedef float_t FT; + typedef double_t DT; + FT a; + DT b; + // CHECK: alloca float + // CHECK: alloca double + // CHECK-EXT: alloca x86_fp80 + // CHECK-EXT: alloca x86_fp80 + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + 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); + // CHECK: alloca i32 + // CHECK: alloca i32 + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return t; +} + +void foo6() { +#pragma clang fp eval_method(extended) + auto resf = [](float_t f) { return f; }; + auto resd = [](double_t g) { return g; }; + // CHECK: alloca %class.anon + // CHECK: alloca %class.anon + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +void foo7() { +#pragma clang fp eval_method(extended) + float f = (float_t)1; + double d = (double_t)2; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +void foo8() { +#pragma clang fp eval_method(extended) + using Ft = float_t; + using Dt = double_t; + // CHECK: alloca float + // CHECK: alloca double + // CHECK-EXT: alloca x86_fp80 + // CHECK-EXT: alloca x86_fp80 + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + Ft a; + Dt b; +} + +void foo9() { +#pragma clang fp eval_method(extended) + float c1 = (float_t)12; + double c2 = (double_t)13; + // CHECK: alloca float + // CHECK: alloca double + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit +} + +float foo10() { +#pragma clang fp eval_method(extended) + extern float_t f; + extern double_t g; + // CHECK: load double + // CHECK-EXT: load x86_fp80 + // CHECK-EXT: load x86_fp80 + // ERROR: error: cannot use type 'float_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + // ERROR: error: cannot use type 'double_t' within '#pragma clang fp eval_method'; type is set according to the default eval method for the translation unit + return f-g; +} Index: clang/test/Sema/attr-only-in-default-eval.cpp =================================================================== --- /dev/null +++ clang/test/Sema/attr-only-in-default-eval.cpp @@ -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)); +