Improve diagnostics for malformed delete operator function declarations.

llvm-svn: 91180
This commit is contained in:
Anders Carlsson 2009-12-11 23:23:22 +00:00
parent f5303fe492
commit 12308f41e7
5 changed files with 86 additions and 9 deletions

View File

@ -172,6 +172,12 @@ inline bool operator!=(CanQual<T> x, CanQual<U> y) {
/// \brief Represents a canonical, potentially-qualified type.
typedef CanQual<Type> CanQualType;
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
CanQualType T) {
DB << static_cast<QualType>(T);
return DB;
}
//----------------------------------------------------------------------------//
// Internal proxy classes used by canonical types
//----------------------------------------------------------------------------//

View File

@ -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<

View File

@ -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<NamespaceDecl>(DC)) {
return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_declared_in_namespace)
<< FnDecl->getDeclName();
} else if (isa<TranslationUnitDecl>(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<QualType>(Context.VoidPtrTy);
diag::err_operator_new_delete_invalid_result_type)
<< FnDecl->getDeclName() << Context.VoidPtrTy;
return ret;
}

View File

@ -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}}

View File

@ -2,7 +2,7 @@
#include <stddef.h>
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*) {