From 1f95cc097c2b5290ab050cdf64f2ac0dd78ef015 Mon Sep 17 00:00:00 2001 From: Anastasia Stulova Date: Thu, 3 Mar 2016 13:33:19 +0000 Subject: [PATCH] [OpenCL] Apply missing restrictions for Blocks in OpenCL v2.0 Applying the following restrictions for block types in OpenCL (v2.0 s6.12.5): - __block storage class is disallowed - every block declaration must be const qualified and initialized - a block can't be used as a return type of a function - a blocks can't be used to declare a structure or union field - extern speficier is disallowed Corrected image and sampler types diagnostics with struct and unions. Review: http://reviews.llvm.org/D16928 llvm-svn: 262616 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 16 +++-- clang/lib/Sema/SemaDecl.cpp | 78 +++++++++++++++------- clang/lib/Sema/SemaType.cpp | 11 ++- clang/test/CodeGen/blocks-opencl.cl | 7 +- clang/test/SemaOpenCL/event_t.cl | 2 +- clang/test/SemaOpenCL/invalid-block.cl | 54 +++++++++++---- clang/test/SemaOpenCL/invalid-kernel-parameters.cl | 5 +- clang/test/SemaOpenCL/sampler_t.cl | 6 +- 8 files changed, 133 insertions(+), 46 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e259e0d..b870c52 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -623,8 +623,8 @@ def err_opencl_half_declaration : Error< "declaring variable of type %0 is not allowed">; def err_opencl_half_param : Error< "declaring function parameter of type %0 is not allowed; did you forget * ?">; -def err_opencl_half_return : Error< - "declaring function return value of type %0 is not allowed; did you forget * ?">; +def err_opencl_invalid_return : Error< + "declaring function return value of type %0 is not allowed %select{; did you forget * ?|}1">; def warn_enum_value_overflow : Warning<"overflow in enumeration value">; def warn_pragma_options_align_reset_failed : Warning< "#pragma options align=reset failed: %0">, @@ -7701,8 +7701,8 @@ def note_illegal_field_declared_here : Note< "field of illegal %select{type|pointer type}0 %1 declared here">; def err_event_t_global_var : Error< "the event_t type cannot be used to declare a program scope variable">; -def err_event_t_struct_field : Error< - "the event_t type cannot be used to declare a structure or union field">; +def err_opencl_type_struct_or_union_field : Error< + "the %0 type cannot be used to declare a structure or union field">; def err_event_t_addr_space_qual : Error< "the event_t type can only be used with __private address space qualifier">; def err_expected_kernel_void_return_type : Error< @@ -7764,6 +7764,14 @@ def err_opencl_multiple_access_qualifiers : Error< def err_opencl_unknown_type_specifier : Error< "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">; +// OpenCL v2.0 s6.12.5 Blocks restrictions +def err_opencl_block_storage_type : Error< + "the __block storage type is not permitted">; +def err_opencl_invalid_block_declaration : Error< + "invalid block variable declaration - must be %select{const qualified|initialized}0">; +def err_opencl_extern_block_declaration : Error< + "invalid block variable declaration - using 'extern' storage class is disallowed">; + } // end of sema category let CategoryName = "OpenMP Issue" in { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f20b4d0..74d6f91 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6585,7 +6585,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } - // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program + // OpenCL v1.2 s6.8 - The static qualifier is valid only in program // scope. if (getLangOpts().OpenCLVersion == 120 && !getOpenCLOptions().cl_clang_storage_class_specifiers && @@ -6595,12 +6595,44 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } - // OpenCL v1.2 s6.5 - All program scope variables must be declared in the - // __constant address space. - // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static - // variables inside a function can also be declared in the global - // address space. if (getLangOpts().OpenCL) { + // OpenCL v2.0 s6.12.5 - The __block storage type is not supported. + if (NewVD->hasAttr()) { + Diag(NewVD->getLocation(), diag::err_opencl_block_storage_type); + return; + } + + if (T->isBlockPointerType()) { + // OpenCL v2.0 s6.12.5 - Any block declaration must be const qualified and + // can't use 'extern' storage class. + if (!T.isConstQualified()) { + Diag(NewVD->getLocation(), diag::err_opencl_invalid_block_declaration) + << 0 /*const*/; + NewVD->setInvalidDecl(); + return; + } + if (NewVD->hasExternalStorage()) { + Diag(NewVD->getLocation(), diag::err_opencl_extern_block_declaration); + NewVD->setInvalidDecl(); + return; + } + // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not supported. + // TODO: this check is not enough as it doesn't diagnose the typedef + const BlockPointerType *BlkTy = T->getAs(); + const FunctionProtoType *FTy = + BlkTy->getPointeeType()->getAs(); + if (FTy && FTy->isVariadic()) { + Diag(NewVD->getLocation(), diag::err_opencl_block_proto_variadic) + << T << NewVD->getSourceRange(); + NewVD->setInvalidDecl(); + return; + } + } + // OpenCL v1.2 s6.5 - All program scope variables must be declared in the + // __constant address space. + // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static + // variables inside a function can also be declared in the global + // address space. if (NewVD->isFileVarDecl()) { if (!T->isSamplerT() && !(T.getAddressSpace() == LangAS::opencl_constant || @@ -6735,19 +6767,6 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { NewVD->setInvalidDecl(); return; } - - // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not supported. - if (LangOpts.OpenCL && T->isBlockPointerType()) { - const BlockPointerType *BlkTy = T->getAs(); - const FunctionProtoType *FTy = - BlkTy->getPointeeType()->getAs(); - if (FTy->isVariadic()) { - Diag(NewVD->getLocation(), diag::err_opencl_block_proto_variadic) - << T << NewVD->getSourceRange(); - NewVD->setInvalidDecl(); - return; - } - } } /// \brief Perform semantic checking on a newly-created variable @@ -10058,6 +10077,18 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; + if (getLangOpts().OpenCL) { + // OpenCL v2.0 s6.12.5 - Every block variable declaration must have an + // initialiser + if (var->getTypeSourceInfo()->getType()->isBlockPointerType() && + !var->hasInit()) { + Diag(var->getLocation(), diag::err_opencl_invalid_block_declaration) + << 1 /*Init*/; + var->setInvalidDecl(); + return; + } + } + // In Objective-C, don't allow jumps past the implicit initialization of a // local retaining variable. if (getLangOpts().ObjC1 && @@ -13110,10 +13141,11 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, D.setInvalidType(); } - // OpenCL 1.2 spec, s6.9 r: - // The event type cannot be used to declare a structure or union field. - if (LangOpts.OpenCL && T->isEventT()) { - Diag(Loc, diag::err_event_t_struct_field); + // OpenCL v1.2 s6.9b,r & OpenCL v2.0 s6.12.5 - The following types cannot be + // used as structure or union field: image, sampler, event or block types. + if (LangOpts.OpenCL && (T->isEventT() || T->isImageType() || + T->isSamplerT() || T->isBlockPointerType())) { + Diag(Loc, diag::err_opencl_type_struct_or_union_field) << T; D.setInvalidType(); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 135b78a..73c5bcc 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3921,7 +3921,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (T->isHalfType()) { if (S.getLangOpts().OpenCL) { if (!S.getOpenCLOptions().cl_khr_fp16) { - S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T; + S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return) + << T << 0 /*pointer hint*/; D.setInvalidType(true); } } else if (!S.getLangOpts().HalfArgsAndReturns) { @@ -3931,6 +3932,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + // OpenCL v2.0 s6.12.5 - A block cannot be the return value of a + // function. + if (LangOpts.OpenCL && T->isBlockPointerType()) { + S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return) + << T << 1 /*hint off*/; + D.setInvalidType(true); + } + // Methods cannot return interface types. All ObjC objects are // passed by reference. if (T->isObjCObjectType()) { diff --git a/clang/test/CodeGen/blocks-opencl.cl b/clang/test/CodeGen/blocks-opencl.cl index d356298..61c479b 100644 --- a/clang/test/CodeGen/blocks-opencl.cl +++ b/clang/test/CodeGen/blocks-opencl.cl @@ -2,15 +2,16 @@ // This used to crash due to trying to generate a bitcase from a cstring // in the constant address space to i8* in AS0. -void dummy(float (^op)(float)) -{ +void dummy(float (^const op)(float)) { } // CHECK: i8 addrspace(3)* getelementptr inbounds ([9 x i8], [9 x i8] addrspace(3)* @.str, i32 0, i32 0) kernel void test_block() { - float (^X)(float) = ^(float x) { return x + 42.0f; }; + float (^const X)(float) = ^(float x) { + return x + 42.0f; + }; dummy(X); } diff --git a/clang/test/SemaOpenCL/event_t.cl b/clang/test/SemaOpenCL/event_t.cl index e098839..3c4b45b 100644 --- a/clang/test/SemaOpenCL/event_t.cl +++ b/clang/test/SemaOpenCL/event_t.cl @@ -3,7 +3,7 @@ event_t glb_evt; // expected-error {{the event_t type cannot be used to declare a program scope variable}} constant struct evt_s { - event_t evt; // expected-error {{the event_t type cannot be used to declare a structure or union field}} + event_t evt; // expected-error {{the 'event_t' type cannot be used to declare a structure or union field}} } evt_str = {0}; void foo(event_t evt); // expected-note {{passing argument to parameter 'evt' here}} diff --git a/clang/test/SemaOpenCL/invalid-block.cl b/clang/test/SemaOpenCL/invalid-block.cl index c3989a2..c8c8821 100644 --- a/clang/test/SemaOpenCL/invalid-block.cl +++ b/clang/test/SemaOpenCL/invalid-block.cl @@ -1,20 +1,50 @@ // RUN: %clang_cc1 -verify -fblocks -cl-std=CL2.0 %s -int (^BlkVariadic)(int, ...) = ^int(int I, ...) { // expected-error {{invalid block prototype, variadic arguments are not allowed in OpenCL}} +// OpenCL v2.0 s6.12.5 + +// All blocks declarations must be const qualified and initialized. +void f1() { + int (^bl1)() = ^() {}; // expected-error{{invalid block variable declaration - must be const qualified}} + int (^const bl2)(); // expected-error{{invalid block variable declaration - must be initialized}} + int (^const bl3)() = ^const(){ + }; +} + +// A block with extern storage class is not allowed. +extern int (^const bl)() = ^const(){}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}} +void f2() { + extern int (^const bl)() = ^const(){}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}} +} + +// A block cannot be the return value of a function. +typedef int (^const bl_t)(void); +bl_t f3(bl_t bl); // expected-error{{declaring function return value of type 'bl_t' (aka 'int (^const)(void)') is not allowed}} + +struct bl_s { + int (^const bl)(void); // expected-error {{the 'int (^const)(void)' type cannot be used to declare a structure or union field}} +}; + +void f4() { + __block int a = 10; // expected-error {{the __block storage type is not permitted}} +} + +// A block with variadic argument is not allowed. +int (^const bl)(int, ...) = ^const int(int I, ...) { // expected-error {{invalid block prototype, variadic arguments are not allowed in OpenCL}} return 0; }; -typedef int (^BlkInt)(int); -void f1(int i) { - BlkInt B1 = ^int(int I) {return 1;}; - BlkInt B2 = ^int(int I) {return 2;}; - BlkInt Arr[] = {B1, B2}; // expected-error {{array of 'BlkInt' (aka 'int (^)(int)') type is invalid in OpenCL}} - int tmp = i ? B1(i) // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} - : B2(i); // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} +// A block can't be used to declare an array +typedef int (^const bl1_t)(int); +void f5(int i) { + bl1_t bl1 = ^const(int i) {return 1;}; + bl1_t bl2 = ^const(int i) {return 2;}; + bl1_t arr[] = {bl1, bl2}; // expected-error {{array of 'bl1_t' (aka 'int (^const)(int)') type is invalid in OpenCL}} + int tmp = i ? bl1(i) // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} + : bl2(i); // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} } -void f2(BlkInt *BlockPtr) { - BlkInt B = ^int(int I) {return 1;}; - BlkInt *P = &B; // expected-error {{invalid argument type 'BlkInt' (aka 'int (^)(int)') to unary expression}} - B = *BlockPtr; // expected-error {{dereferencing pointer of type '__generic BlkInt *' (aka 'int (^__generic *)(int)') is not allowed in OpenCL}} +void f6(bl1_t * bl_ptr) { + bl1_t bl = ^const(int i) {return 1;}; + bl1_t *p = &bl; // expected-error {{invalid argument type 'bl1_t' (aka 'int (^const)(int)') to unary expression}} + bl = *bl_ptr; // expected-error {{dereferencing pointer of type '__generic bl1_t *' (aka 'int (^const __generic *)(int)') is not allowed in OpenCL}} } diff --git a/clang/test/SemaOpenCL/invalid-kernel-parameters.cl b/clang/test/SemaOpenCL/invalid-kernel-parameters.cl index de32eae..95a56e2 100644 --- a/clang/test/SemaOpenCL/invalid-kernel-parameters.cl +++ b/clang/test/SemaOpenCL/invalid-kernel-parameters.cl @@ -24,7 +24,10 @@ kernel void bool_in_struct_arg(ContainsBool x) { } // expected-error{{'ContainsB typedef struct FooImage2D // expected-note{{within field of type 'FooImage2D' declared here}} { - image2d_t imageField; // expected-note{{field of illegal type 'image2d_t' declared here}} + // TODO: Clean up needed - we don't really need to check for image, event, etc + // as a note here any longer. + // They are diagnosed as an error for all struct fields (OpenCL v1.2 s6.9b,r). + image2d_t imageField; // expected-note{{field of illegal type 'image2d_t' declared here}} expected-error{{the 'image2d_t' type cannot be used to declare a structure or union field}} } FooImage2D; kernel void image_in_struct_arg(FooImage2D arg) { } // expected-error{{struct kernel parameters may not contain pointers}} diff --git a/clang/test/SemaOpenCL/sampler_t.cl b/clang/test/SemaOpenCL/sampler_t.cl index 82fb347..711cdea 100644 --- a/clang/test/SemaOpenCL/sampler_t.cl +++ b/clang/test/SemaOpenCL/sampler_t.cl @@ -2,7 +2,11 @@ constant sampler_t glb_smp = 5; -void foo(sampler_t); +void foo(sampler_t); + +constant struct sampler_s { + sampler_t smp; // expected-error {{the 'sampler_t' type cannot be used to declare a structure or union field}} +} sampler_str = {0}; void kernel ker(sampler_t argsmp) { local sampler_t smp; // expected-error {{sampler type cannot be used with the __local and __global address space qualifiers}} -- 2.7.4