// 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 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 struct ValueDependent { void nb_method() [[clang::nonblocking(V)]]; }; void t3() [[clang::nonblocking]] { ValueDependent x1; x1.nb_method(); // CHECK: ClassTemplateSpecializationDecl {{.*}} ValueDependent // CHECK: TemplateArgument integral 'false' // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((blocking))' ValueDependent x2; x2.nb_method(); // CHECK: ClassTemplateSpecializationDecl {{.*}} ValueDependent // CHECK: TemplateArgument integral 'true' // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((nonblocking))' } template 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 x1; x1.td_method(); // CHECK: ClassTemplateSpecializationDecl {{.*}} TypeDependent // CHECK: TemplateArgument type 'NBPolicyFalse' // CHECK: CXXMethodDecl {{.*}} td_method 'void () __attribute__((blocking))' TypeDependent x2; x2.td_method(); // CHECK: ClassTemplateSpecializationDecl {{.*}} TypeDependent // CHECK: TemplateArgument type 'NBPolicyTrue' // CHECK: CXXMethodDecl {{.*}} td_method 'void () __attribute__((nonblocking))' }