From a9e178ab754104f72d2450a35d58164ed1f8e5b6 Mon Sep 17 00:00:00 2001 From: Pekka Jaaskelainen <pekka.jaaskelainen@tut.fi> Date: Thu, 20 Feb 2014 13:52:08 +0000 Subject: [PATCH] OpenCL: fix for the restriction on pointers to functions. Patch from Anastasia Stulova! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201788 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 6 ++++ include/clang/Sema/Sema.h | 4 +++ lib/Sema/SemaDecl.cpp | 25 +++++++++++---- lib/Sema/SemaExpr.cpp | 36 ++++++++++++++++++++-- test/SemaOpenCL/func_ptr.cl | 16 ++++++++++ 5 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 test/SemaOpenCL/func_ptr.cl diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8984116ad0e..a2415f7a956 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5844,6 +5844,12 @@ def err_invalid_conversion_between_vector_and_integer : Error< "invalid conversion between vector type %0 and integer type %1 " "of different size">; +def err_opencl_function_pointer_variable : Error< + "pointers to functions are not allowed">; + +def err_opencl_taking_function_address : Error< + "taking address of function is not allowed">; + def err_invalid_conversion_between_vector_and_scalar : Error< "invalid conversion between vector type %0 and scalar type %1">; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ff21c1d284a..6ed43b2cc83 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7202,6 +7202,10 @@ public: // functions and arrays to their respective pointers (C99 6.3.2.1). ExprResult UsualUnaryConversions(Expr *E); + /// CallExprUnaryConversions - a special case of an unary conversion + /// performed on a function designator of a call expression. + ExprResult CallExprUnaryConversions(Expr *E); + // DefaultFunctionArrayConversion - converts functions and arrays // to their respective pointers (C99 6.3.2.1). ExprResult DefaultFunctionArrayConversion(Expr *E); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c147681f03f..06d4500f77e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4986,12 +4986,25 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool IsLocalExternDecl = SC == SC_Extern && adjustContextForLocalExternDecl(DC); - if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) { - // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and - // half array type (unless the cl_khr_fp16 extension is enabled). - if (Context.getBaseElementType(R)->isHalfType()) { - Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R; - D.setInvalidType(); + if (getLangOpts().OpenCL) { + // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. + QualType NR = R; + while (NR->isPointerType()) { + if (NR->isFunctionPointerType()) { + Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer_variable); + D.setInvalidType(); + break; + } + NR = NR->getPointeeType(); + } + + if (!getOpenCLOptions().cl_khr_fp16) { + // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and + // half array type (unless the cl_khr_fp16 extension is enabled). + if (Context.getBaseElementType(R)->isHalfType()) { + Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R; + D.setInvalidType(); + } } } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 44e1b8c5498..5e249711123 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -434,10 +434,16 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); - if (Ty->isFunctionType()) + if (Ty->isFunctionType()) { + // If we are here, we are not calling a function but taking + // its address (which is not allowed in OpenCL v1.0 s6.8.a.3). + if (getLangOpts().OpenCL) { + Diag(E->getExprLoc(), diag::err_opencl_taking_function_address); + return ExprError(); + } E = ImpCastExprToType(E, Context.getPointerType(Ty), CK_FunctionToPointerDecay).take(); - else if (Ty->isArrayType()) { + } else if (Ty->isArrayType()) { // In C90 mode, arrays only promote to pointers if the array expression is // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has // type 'array of type' is converted to an expression that has type 'pointer @@ -633,6 +639,24 @@ ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) { return Res; } +/// CallExprUnaryConversions - a special case of an unary conversion +/// performed on a function designator of a call expression. +ExprResult Sema::CallExprUnaryConversions(Expr *E) { + QualType Ty = E->getType(); + ExprResult Res = E; + // Only do implicit cast for a function type, but not for a pointer + // to function type. + if (Ty->isFunctionType()) { + Res = ImpCastExprToType(E, Context.getPointerType(Ty), + CK_FunctionToPointerDecay).take(); + if (Res.isInvalid()) + return ExprError(); + } + Res = DefaultLvalueConversion(Res.take()); + if (Res.isInvalid()) + return ExprError(); + return Owned(Res.take()); +} /// UsualUnaryConversions - Performs various conversions that are common to most /// operators (C99 6.3). The conversions of array and function types are @@ -4570,7 +4594,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, Result = ImpCastExprToType(Fn, Context.getPointerType(FDecl->getType()), CK_BuiltinFnToFnPtr).take(); } else { - Result = UsualUnaryConversions(Fn); + Result = CallExprUnaryConversions(Fn); } if (Result.isInvalid()) return ExprError(); @@ -8808,6 +8832,12 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { // Make sure to ignore parentheses in subsequent checks Expr *op = OrigOp.get()->IgnoreParens(); + // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. + if (LangOpts.OpenCL && op->getType()->isFunctionType()) { + Diag(op->getExprLoc(), diag::err_opencl_taking_function_address); + return QualType(); + } + if (getLangOpts().C99) { // Implement C99-only parts of addressof rules. if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) { diff --git a/test/SemaOpenCL/func_ptr.cl b/test/SemaOpenCL/func_ptr.cl new file mode 100644 index 00000000000..f21a3d3265a --- /dev/null +++ b/test/SemaOpenCL/func_ptr.cl @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only + +void foo(void*); + +void bar() +{ + // declaring a function pointer is an error + void (*fptr)(int); // expected-error{{pointers to functions are not allowed}} + + // taking the address of a function is an error + foo((void*)foo); // expected-error{{taking address of function is not allowed}} + foo(&foo); // expected-error{{taking address of function is not allowed}} + + // just calling a function is correct + foo(0); +} -- GitLab