[OpenCL] Support new/delete in Sema

Reject uses of the default new/delete operators with a diagnostic
instead of a crash in OpenCL C++ mode and accept user-defined forms.

Differential Revision: https://reviews.llvm.org/D46651


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@334700 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sven van Haastregt 2018-06-14 09:51:54 +00:00
parent 9c72f2596e
commit af56077940
4 changed files with 98 additions and 4 deletions

View File

@ -13007,6 +13007,13 @@ CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
return false;
}
static QualType
RemoveAddressSpaceFromPtr(Sema &SemaRef, const PointerType *PtrTy) {
QualType QTy = PtrTy->getPointeeType();
QTy = SemaRef.Context.removeAddrSpaceQualType(QTy);
return SemaRef.Context.getPointerType(QTy);
}
static inline bool
CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
CanQualType ExpectedResultType,
@ -13022,6 +13029,13 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
diag::err_operator_new_delete_dependent_result_type)
<< FnDecl->getDeclName() << ExpectedResultType;
// OpenCL C++: the operator is valid on any address space.
if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
if (auto *PtrTy = ResultType->getAs<PointerType>()) {
ResultType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy);
}
}
// Check that the result type is what we expect.
if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType)
return SemaRef.Diag(FnDecl->getLocation(),
@ -13047,6 +13061,13 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
<< FnDecl->getDeclName() << ExpectedFirstParamType;
// Check that the first parameter type is what we expect.
if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
// OpenCL C++: the operator is valid on any address space.
if (auto *PtrTy =
FnDecl->getParamDecl(0)->getType()->getAs<PointerType>()) {
FirstParamType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy);
}
}
if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() !=
ExpectedFirstParamType)
return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag)

View File

@ -2146,7 +2146,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
else if (AllocType->isVariablyModifiedType())
return Diag(Loc, diag::err_variably_modified_new_type)
<< AllocType;
else if (AllocType.getAddressSpace() != LangAS::Default)
else if (AllocType.getAddressSpace() != LangAS::Default &&
!getLangOpts().OpenCLCPlusPlus)
return Diag(Loc, diag::err_address_space_qualified_new)
<< AllocType.getUnqualifiedType()
<< AllocType.getQualifiers().getAddressSpaceAttributePrintValue();
@ -2362,6 +2363,11 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
LookupQualifiedName(R, Context.getTranslationUnitDecl());
}
if (getLangOpts().OpenCLCPlusPlus && R.empty()) {
Diag(StartLoc, diag::err_openclcxx_not_supported) << "default new";
return true;
}
assert(!R.empty() && "implicitly declared allocation functions not found");
assert(!R.isAmbiguous() && "global allocation functions are ambiguous");
@ -2597,6 +2603,11 @@ void Sema::DeclareGlobalNewDelete() {
if (GlobalNewDeleteDeclared)
return;
// OpenCL C++ 1.0 s2.9: the implicitly declared new and delete operators
// are not supported.
if (getLangOpts().OpenCLCPlusPlus)
return;
// C++ [basic.std.dynamic]p2:
// [...] The following allocation and deallocation functions (18.4) are
// implicitly declared in global scope in each translation unit of a
@ -3230,7 +3241,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
QualType PointeeElem = Context.getBaseElementType(Pointee);
if (Pointee.getAddressSpace() != LangAS::Default)
if (Pointee.getAddressSpace() != LangAS::Default &&
!getLangOpts().OpenCLCPlusPlus)
return Diag(Ex.get()->getLocStart(),
diag::err_address_space_qualified_delete)
<< Pointee.getUnqualifiedType()
@ -3305,6 +3317,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
}
if (!OperatorDelete) {
if (getLangOpts().OpenCLCPlusPlus) {
Diag(StartLoc, diag::err_openclcxx_not_supported) << "default delete";
return ExprError();
}
bool IsComplete = isCompleteType(StartLoc, Pointee);
bool CanProvideSize =
IsComplete && (!ArrayForm || UsualArrayDeleteWantsSize ||

View File

@ -7173,8 +7173,9 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
// The default address space name for arguments to a function in a
// program, or local variables of a function is __private. All function
// arguments shall be in the __private address space.
if (State.getSema().getLangOpts().OpenCLVersion <= 120) {
ImpAddr = LangAS::opencl_private;
if (State.getSema().getLangOpts().OpenCLVersion <= 120 &&
!State.getSema().getLangOpts().OpenCLCPlusPlus) {
ImpAddr = LangAS::opencl_private;
} else {
// If address space is not set, OpenCL 2.0 defines non private default
// address spaces for some cases:

View File

@ -0,0 +1,55 @@
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify -fsyntax-only
class A {
public:
A() : x(21) {}
int x;
};
typedef __SIZE_TYPE__ size_t;
class B {
public:
B() : bx(42) {}
void *operator new(size_t);
void operator delete(void *ptr);
int bx;
};
// There are no global user-defined new operators at this point. Test that clang
// rejects these gracefully.
void test_default_new_delete(void *buffer, A **pa) {
A *a = new A; // expected-error {{'default new' is not supported in OpenCL C++}}
delete a; // expected-error {{'default delete' is not supported in OpenCL C++}}
*pa = new (buffer) A; // expected-error {{'default new' is not supported in OpenCL C++}}
}
// expected-note@+1 {{candidate function not viable: requires 2 arguments, but 1 was provided}}
void *operator new(size_t _s, void *ptr) noexcept {
return ptr;
}
// expected-note@+1 {{candidate function not viable: requires 2 arguments, but 1 was provided}}
void *operator new[](size_t _s, void *ptr) noexcept {
return ptr;
}
void test_new_delete(void *buffer, A **a, B **b) {
*a = new A; // expected-error {{no matching function for call to 'operator new'}}
delete a; // expected-error {{'default delete' is not supported in OpenCL C++}}
*a = new A[20]; // expected-error {{no matching function for call to 'operator new[]'}}
delete[] *a; // expected-error {{'default delete' is not supported in OpenCL C++}}
// User-defined placement new is supported.
*a = new (buffer) A;
// User-defined placement new[] is supported.
*a = new (buffer) A[30];
// User-defined new is supported.
*b = new B;
// User-defined delete is supported.
delete *b;
}