From: Anders Carlsson Date: Fri, 11 Dec 2009 23:23:22 +0000 (+0000) Subject: Improve diagnostics for malformed delete operator function declarations. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9d59ecb4d2c2e8efdb214589753826b662246d82;p=clang Improve diagnostics for malformed delete operator function declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91180 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 9b1187770f..af8d23692e 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -172,6 +172,12 @@ inline bool operator!=(CanQual x, CanQual y) { /// \brief Represents a canonical, potentially-qualified type. typedef CanQual CanQualType; +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + CanQualType T) { + DB << static_cast(T); + return DB; +} + //----------------------------------------------------------------------------// // Internal proxy classes used by canonical types //----------------------------------------------------------------------------// diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1e694f2b99..4e88a3eed3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2220,10 +2220,6 @@ def err_operator_overload_needs_class_or_enum : Error< def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">; def err_operator_overload_static : Error< "overloaded %0 cannot be a static member function">; -def err_operator_new_param_type : Error< - "%0 takes type size_t (%1) as first parameter">; -def err_operator_new_result_type : Error< - "%0 must return type %1">; def err_operator_overload_default_arg : Error< "parameter of overloaded %0 cannot have a default argument">; def err_operator_overload_must_be : Error< @@ -2236,6 +2232,19 @@ def err_operator_overload_post_incdec_must_be_int : Error< "parameter of overloaded post-%select{increment|decrement}1 operator must " "have type 'int' (not %0)">; +// C++ allocation and deallocation functions. +def err_operator_new_delete_declared_in_namespace : Error< + "%0 cannot be declared inside a namespace">; +def err_operator_new_delete_declared_static : Error< + "%0 cannot be declared static in global scope">; +def err_operator_new_delete_invalid_result_type : Error< + "%0 must return type %1">; +def err_operator_new_delete_too_few_parameters : Error< + "%0 must have at least one parameter.">; +def err_operator_new_param_type : Error< + "%0 takes type size_t (%1) as first parameter">; +def err_operator_delete_param_type : Error< + "%0 takes type %1 as first parameter">; // C++ conversion functions def err_conv_function_not_member : Error< diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 5a7cba00e5..32e391d8d0 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4604,6 +4604,52 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, } } +static bool +CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { + // C++ [basic.stc.dynamic.deallocation]p1: + // A program is ill-formed if deallocation functions are declared in a + // namespace scope other than global scope or declared static in global + // scope. + const DeclContext *DC = FnDecl->getDeclContext()->getLookupContext(); + if (isa(DC)) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_declared_in_namespace) + << FnDecl->getDeclName(); + } else if (isa(DC) && + FnDecl->getStorageClass() == FunctionDecl::Static) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_declared_static) + << FnDecl->getDeclName(); + } + + // C++ [basic.stc.dynamic.deallocation]p2: + // Each deallocation function shall return void and its first parameter + // shall be void*. + QualType ResultType = FnDecl->getResultType(); + if (!ResultType->isDependentType() && !ResultType->isVoidType()) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_invalid_result_type) + << FnDecl->getDeclName() << SemaRef.Context.VoidTy; + } + + if (FnDecl->getNumParams() == 0) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_too_few_parameters) + << FnDecl->getDeclName(); + } + + QualType FirstParamType = + SemaRef.Context.getCanonicalType(FnDecl->getParamDecl(0)->getType()); + if (!FirstParamType->isDependentType() && + FirstParamType != SemaRef.Context.VoidPtrTy) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_delete_param_type) + << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy; + } + + return false; +} + /// CheckOverloadedOperatorDeclaration - Check whether the declaration /// of this overloaded operator is well-formed. If so, returns false; /// otherwise, emits appropriate diagnostics and returns true. @@ -4619,9 +4665,14 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // described completely in 3.7.3. The attributes and restrictions // found in the rest of this subclause do not apply to them unless // explicitly stated in 3.7.3. - // FIXME: Write a separate routine for checking this. For now, just allow it. - if (Op == OO_Delete || Op == OO_Array_Delete) + if (Op == OO_Delete || Op == OO_Array_Delete) { + return CheckOperatorDeleteDeclaration(*this, FnDecl); + FnDecl->setInvalidDecl(); + return true; + } + return false; + } if (Op == OO_New || Op == OO_Array_New) { bool ret = false; @@ -4638,8 +4689,8 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { QualType ResultTy = Context.getCanonicalType(FnDecl->getResultType()); if (!ResultTy->isDependentType() && ResultTy != Context.VoidPtrTy) return Diag(FnDecl->getLocation(), - diag::err_operator_new_result_type) << FnDecl->getDeclName() - << static_cast(Context.VoidPtrTy); + diag::err_operator_new_delete_invalid_result_type) + << FnDecl->getDeclName() << Context.VoidPtrTy; return ret; } diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p1.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p1.cpp new file mode 100644 index 0000000000..04af5bc82e --- /dev/null +++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p1.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct A { + void operator delete(void*); +}; + +namespace NS { + void operator delete(void *); // expected-error {{'operator delete' cannot be declared inside a namespace}} +} + +static void operator delete(void *); // expected-error {{'operator delete' cannot be declared static in global scope}} diff --git a/test/CXX/special/class.free/p6.cpp b/test/CXX/special/class.free/p6.cpp index 8334817ca2..b082b85d18 100644 --- a/test/CXX/special/class.free/p6.cpp +++ b/test/CXX/special/class.free/p6.cpp @@ -2,7 +2,7 @@ #include struct A { - void operator delete(size_t) { + void operator delete(void*) { (void)this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} } void operator delete[](void*) {