forked from OSchip/llvm-project
Improve diagnostics for malformed delete operator function declarations.
llvm-svn: 91180
This commit is contained in:
parent
f5303fe492
commit
12308f41e7
|
@ -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
|
||||
//----------------------------------------------------------------------------//
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
|
@ -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*) {
|
||||
|
|
Loading…
Reference in New Issue