From 89307aa3e9fce213a55b64c042a001458d3ba41c Mon Sep 17 00:00:00 2001 From: Xiuli Pan Date: Wed, 24 Feb 2016 04:29:36 +0000 Subject: [PATCH] [OpenCL] Add Sema checks for OpenCL 2.0 block Summary: Add Sema checks for opencl 2.0 new features: Block. This patch is partitioned from http://reviews.llvm.org/D16047 Reviewers: Anastasia Subscribers: pekka.jaaskelainen, cfe-commits Differential Revision: http://reviews.llvm.org/D17436 llvm-svn: 261719 --- .../clang/Basic/DiagnosticSemaKinds.td | 8 +++++ clang/lib/Sema/SemaDecl.cpp | 13 +++++++ clang/lib/Sema/SemaExpr.cpp | 35 +++++++++++++++++++ clang/lib/Sema/SemaType.cpp | 9 +++++ clang/test/SemaOpenCL/invalid-block.cl | 20 +++++++++++ 5 files changed, 85 insertions(+) create mode 100644 clang/test/SemaOpenCL/invalid-block.cl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 45d1b4acc134b..53c0a31236b3a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7712,6 +7712,14 @@ def err_atomic_init_constant : Error< " in the declaration statement in the program scope">; def err_opencl_implicit_vector_conversion : Error< "implicit conversions between vector types (%0 and %1) are not permitted">; +def err_opencl_dereferencing : Error< + "dereferencing pointer of type %0 is not allowed in OpenCL">; +def err_opencl_block_proto_variadic : Error< + "invalid block prototype, variadic arguments are not allowed in OpenCL">; +def err_opencl_invalid_type_array : Error< + "array of %0 type is invalid in OpenCL">; +def err_opencl_ternary_with_block : Error< + "block type cannot be used as expression in ternary expression in OpenCL">; // OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions def err_opencl_builtin_pipe_first_arg : Error< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0f6470bf453f1..378abe94e877c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6708,6 +6708,19 @@ 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 diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ee9e646e24ce4..0ca5555e1dafb 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6458,6 +6458,18 @@ OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond, return OpenCLConvertScalarsToVectors(S, LHS, RHS, CondTy, QuestionLoc); } +/// \brief Return true if the Expr is block type +static bool checkBlockType(Sema &S, const Expr *E) { + if (const CallExpr *CE = dyn_cast(E)) { + QualType Ty = CE->getCallee()->getType(); + if (Ty->isBlockPointerType()) { + S.Diag(E->getExprLoc(), diag::err_opencl_ternary_with_block); + return true; + } + } + return false; +} + /// Note that LHS is not null here, even if this is the gnu "x ?: y" extension. /// In that case, LHS = cond. /// C99 6.5.15 @@ -6507,6 +6519,13 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); + // OpenCL v2.0 s6.12.5 - Blocks cannot be used as expressions of the ternary + // selection operator (?:). + if (getLangOpts().OpenCL && + (checkBlockType(*this, LHS.get()) | checkBlockType(*this, RHS.get()))) { + return QualType(); + } + // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { @@ -10334,6 +10353,14 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { // If the operand has type "type", the result has type "pointer to type". if (op->getType()->isObjCObjectType()) return Context.getObjCObjectPointerType(op->getType()); + + // OpenCL v2.0 s6.12.5 - The unary operators & cannot be used with a block. + if (getLangOpts().OpenCL && OrigOp.get()->getType()->isBlockPointerType()) { + Diag(OpLoc, diag::err_typecheck_unary_expr) << OrigOp.get()->getType() + << op->getSourceRange(); + return QualType(); + } + return Context.getPointerType(op->getType()); } @@ -10375,7 +10402,15 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, } if (const PointerType *PT = OpTy->getAs()) + { Result = PT->getPointeeType(); + // OpenCL v2.0 s6.12.5 - The unary operators * cannot be used with a block. + if (S.getLangOpts().OpenCLVersion >= 200 && Result->isBlockPointerType()) { + S.Diag(OpLoc, diag::err_opencl_dereferencing) << OpTy + << Op->getSourceRange(); + return QualType(); + } + } else if (const ObjCObjectPointerType *OPT = OpTy->getAs()) Result = OPT->getPointeeType(); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index cabb5bc0e0af4..5c3b7ab3349a8 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2175,6 +2175,15 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Diag(Loc, diag::warn_vla_used); } + // OpenCL v2.0 s6.12.5 - Arrays of blocks are not supported. + if (getLangOpts().OpenCL) { + const QualType ArrType = Context.getBaseElementType(T); + if (ArrType->isBlockPointerType()) { + Diag(Loc, diag::err_opencl_invalid_type_array) << ArrType; + return QualType(); + } + } + return T; } diff --git a/clang/test/SemaOpenCL/invalid-block.cl b/clang/test/SemaOpenCL/invalid-block.cl new file mode 100644 index 0000000000000..c3989a28c83ba --- /dev/null +++ b/clang/test/SemaOpenCL/invalid-block.cl @@ -0,0 +1,20 @@ +// 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}} + 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}} +} + +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}} +}