| // RUN: %clang_cc1 %s -ast-dump -fblocks | FileCheck %s |
| |
| // Make sure that the attribute gets parsed and attached to the correct AST elements. |
| |
| #pragma clang diagnostic ignored "-Wunused-variable" |
| #pragma clang diagnostic ignored "-Wperf-constraint-implies-noexcept" |
| |
| // ========================================================================================= |
| // Square brackets, true |
| |
| namespace square_brackets { |
| |
| // 1. On the type of the FunctionDecl |
| void nl_function() [[clang::nonblocking]]; |
| // CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' |
| |
| // 2. On the type of the VarDecl holding a function pointer |
| void (*nl_func_a)() [[clang::nonblocking]]; |
| // CHECK: VarDecl {{.*}} nl_func_a 'void (*)() __attribute__((nonblocking))' |
| |
| // 3. On the type of the ParmVarDecl of a function parameter |
| static void nlReceiver(void (*nl_func)() [[clang::nonblocking]]); |
| // CHECK: ParmVarDecl {{.*}} nl_func 'void (*)() __attribute__((nonblocking))' |
| |
| // 4. As an AttributedType within the nested types of a typedef |
| typedef void (*nl_fp_type)() [[clang::nonblocking]]; |
| // CHECK: TypedefDecl {{.*}} nl_fp_type 'void (*)() __attribute__((nonblocking))' |
| using nl_fp_talias = void (*)() [[clang::nonblocking]]; |
| // CHECK: TypeAliasDecl {{.*}} nl_fp_talias 'void (*)() __attribute__((nonblocking))' |
| |
| // 5. From a typedef or typealias, on a VarDecl |
| nl_fp_type nl_fp_var1; |
| // CHECK: VarDecl {{.*}} nl_fp_var1 'nl_fp_type':'void (*)() __attribute__((nonblocking))' |
| nl_fp_talias nl_fp_var2; |
| // CHECK: VarDecl {{.*}} nl_fp_var2 'nl_fp_talias':'void (*)() __attribute__((nonblocking))' |
| |
| // 6. On type of a FieldDecl |
| struct Struct { |
| void (*nl_func_field)() [[clang::nonblocking]]; |
| // CHECK: FieldDecl {{.*}} nl_func_field 'void (*)() __attribute__((nonblocking))' |
| }; |
| |
| // nonallocating should NOT be subsumed into nonblocking |
| void nl1() [[clang::nonblocking]] [[clang::nonallocating]]; |
| // CHECK: FunctionDecl {{.*}} nl1 'void () __attribute__((nonblocking)) __attribute__((nonallocating))' |
| |
| void nl2() [[clang::nonallocating]] [[clang::nonblocking]]; |
| // CHECK: FunctionDecl {{.*}} nl2 'void () __attribute__((nonblocking)) __attribute__((nonallocating))' |
| |
| decltype(nl1) nl3; |
| // CHECK: FunctionDecl {{.*}} nl3 'decltype(nl1)':'void () __attribute__((nonblocking)) __attribute__((nonallocating))' |
| |
| // Attribute propagates from base class virtual method to overrides. |
| struct Base { |
| virtual void nb_method() [[clang::nonblocking]]; |
| }; |
| struct Derived : public Base { |
| void nb_method() override; |
| // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((nonblocking))' |
| }; |
| |
| // Dependent expression |
| template <bool V> |
| struct Dependent { |
| void nb_method2() [[clang::nonblocking(V)]]; |
| // CHECK: CXXMethodDecl {{.*}} nb_method2 'void () __attribute__((nonblocking(V)))' |
| }; |
| |
| // --- Blocks --- |
| |
| // On the type of the VarDecl holding a BlockDecl |
| void (^nl_block1)() [[clang::nonblocking]] = ^() [[clang::nonblocking]] {}; |
| // CHECK: VarDecl {{.*}} nl_block1 'void (^)() __attribute__((nonblocking))' |
| |
| int (^nl_block2)() [[clang::nonblocking]] = ^() [[clang::nonblocking]] { return 0; }; |
| // CHECK: VarDecl {{.*}} nl_block2 'int (^)() __attribute__((nonblocking))' |
| |
| // The operand of the CallExpr is an ImplicitCastExpr of a DeclRefExpr -> nl_block which hold the attribute |
| static void blockCaller() { nl_block1(); } |
| // CHECK: DeclRefExpr {{.*}} 'nl_block1' 'void (^)() __attribute__((nonblocking))' |
| |
| // --- Lambdas --- |
| |
| // On the operator() of a lambda's CXXMethodDecl |
| auto nl_lambda = []() [[clang::nonblocking]] {}; |
| // CHECK: CXXMethodDecl {{.*}} operator() 'void () const __attribute__((nonblocking))' inline |
| |
| // ========================================================================================= |
| // Square brackets, false |
| |
| void nl_func_false() [[clang::blocking]]; |
| // CHECK: FunctionDecl {{.*}} nl_func_false 'void () __attribute__((blocking))' |
| |
| auto nl_lambda_false = []() [[clang::blocking]] {}; |
| // CHECK: CXXMethodDecl {{.*}} operator() 'void () const __attribute__((blocking))' |
| |
| } // namespace square_brackets |
| |
| // ========================================================================================= |
| // GNU-style attribute, true |
| |
| namespace gnu_style { |
| |
| // 1. On the type of the FunctionDecl |
| void nl_function() __attribute__((nonblocking)); |
| // CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' |
| |
| // 1a. Alternate placement on the FunctionDecl |
| __attribute__((nonblocking)) void nl_function(); |
| // CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' |
| |
| // 2. On the type of the VarDecl holding a function pointer |
| void (*nl_func_a)() __attribute__((nonblocking)); |
| // CHECK: VarDecl {{.*}} nl_func_a 'void (*)() __attribute__((nonblocking))' |
| |
| // 2a. Alternate attribute placement on VarDecl |
| __attribute__((nonblocking)) void (*nl_func_b)(); |
| // CHECK: VarDecl {{.*}} nl_func_b 'void (*)() __attribute__((nonblocking))' |
| |
| // 3. On the type of the ParmVarDecl of a function parameter |
| static void nlReceiver(void (*nl_func)() __attribute__((nonblocking))); |
| // CHECK: ParmVarDecl {{.*}} nl_func 'void (*)() __attribute__((nonblocking))' |
| |
| // 4. As an AttributedType within the nested types of a typedef |
| // Note different placement from square brackets for the typealias. |
| typedef void (*nl_fp_type)() __attribute__((nonblocking)); |
| // CHECK: TypedefDecl {{.*}} nl_fp_type 'void (*)() __attribute__((nonblocking))' |
| using nl_fp_talias = __attribute__((nonblocking)) void (*)(); |
| // CHECK: TypeAliasDecl {{.*}} nl_fp_talias 'void (*)() __attribute__((nonblocking))' |
| |
| // 5. From a typedef or typealias, on a VarDecl |
| nl_fp_type nl_fp_var1; |
| // CHECK: VarDecl {{.*}} nl_fp_var1 'nl_fp_type':'void (*)() __attribute__((nonblocking))' |
| nl_fp_talias nl_fp_var2; |
| // CHECK: VarDecl {{.*}} nl_fp_var2 'nl_fp_talias':'void (*)() __attribute__((nonblocking))' |
| |
| // 6. On type of a FieldDecl |
| struct Struct { |
| void (*nl_func_field)() __attribute__((nonblocking)); |
| // CHECK: FieldDecl {{.*}} nl_func_field 'void (*)() __attribute__((nonblocking))' |
| }; |
| |
| } // namespace gnu_style |
| |
| // ========================================================================================= |
| // nonallocating and allocating - quick checks because the code paths are generally |
| // identical after parsing. |
| |
| void na_function() [[clang::nonallocating]]; |
| // CHECK: FunctionDecl {{.*}} na_function 'void () __attribute__((nonallocating))' |
| |
| void na_true_function() [[clang::nonallocating(true)]]; |
| // CHECK: FunctionDecl {{.*}} na_true_function 'void () __attribute__((nonallocating))' |
| |
| void na_false_function() [[clang::nonallocating(false)]]; |
| // CHECK: FunctionDecl {{.*}} na_false_function 'void () __attribute__((allocating))' |
| |
| void alloc_function() [[clang::allocating]]; |
| // CHECK: FunctionDecl {{.*}} alloc_function 'void () __attribute__((allocating))' |
| |
| |
| // ========================================================================================= |
| // Non-blocking with an expression parameter |
| |
| void t0() [[clang::nonblocking(1 - 1)]]; |
| // CHECK: FunctionDecl {{.*}} t0 'void () __attribute__((blocking))' |
| void t1() [[clang::nonblocking(1 + 1)]]; |
| // CHECK: FunctionDecl {{.*}} t1 'void () __attribute__((nonblocking))' |
| |
| template <bool V> |
| struct ValueDependent { |
| void nb_method() [[clang::nonblocking(V)]]; |
| }; |
| |
| void t3() [[clang::nonblocking]] |
| { |
| ValueDependent<false> x1; |
| x1.nb_method(); |
| // CHECK: ClassTemplateSpecializationDecl {{.*}} ValueDependent |
| // CHECK: TemplateArgument integral 'false' |
| // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((blocking))' |
| |
| ValueDependent<true> x2; |
| x2.nb_method(); |
| // CHECK: ClassTemplateSpecializationDecl {{.*}} ValueDependent |
| // CHECK: TemplateArgument integral 'true' |
| // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((nonblocking))' |
| } |
| |
| template <typename X> |
| struct TypeDependent { |
| void td_method() [[clang::nonblocking(X::is_nb)]]; |
| }; |
| |
| struct NBPolicyTrue { |
| static constexpr bool is_nb = true; |
| }; |
| |
| struct NBPolicyFalse { |
| static constexpr bool is_nb = false; |
| }; |
| |
| void t4() |
| { |
| TypeDependent<NBPolicyFalse> x1; |
| x1.td_method(); |
| // CHECK: ClassTemplateSpecializationDecl {{.*}} TypeDependent |
| // CHECK: TemplateArgument type 'NBPolicyFalse' |
| // CHECK: CXXMethodDecl {{.*}} td_method 'void () __attribute__((blocking))' |
| |
| TypeDependent<NBPolicyTrue> x2; |
| x2.td_method(); |
| // CHECK: ClassTemplateSpecializationDecl {{.*}} TypeDependent |
| // CHECK: TemplateArgument type 'NBPolicyTrue' |
| // CHECK: CXXMethodDecl {{.*}} td_method 'void () __attribute__((nonblocking))' |
| } |
| |