]> granicus.if.org Git - clang/commitdiff
Improve diagnostics for malformed delete operator function declarations.
authorAnders Carlsson <andersca@mac.com>
Fri, 11 Dec 2009 23:23:22 +0000 (23:23 +0000)
committerAnders Carlsson <andersca@mac.com>
Fri, 11 Dec 2009 23:23:22 +0000 (23:23 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91180 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/CanonicalType.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.deallocation/p1.cpp [new file with mode: 0644]
test/CXX/special/class.free/p6.cpp

index 9b1187770f6ac78a102f9a38232e423152956e8c..af8d23692e196fa27902a8914ef10ae613f60280 100644 (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
 //----------------------------------------------------------------------------//
index 1e694f2b998c97bafe9b080c789979ffcfb08e9e..4e88a3eed3561ae06733bc8621e66fdebb470c72 100644 (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<
index 5a7cba00e5fbbcb696ee4fde4f4521ab3d0d9d3e..32e391d8d0305c3524e5161bdd830150df7b94fa 100644 (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;
   }
 
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 (file)
index 0000000..04af5bc
--- /dev/null
@@ -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}}
index 8334817ca2b5f2918df21fb0618152c3929dd463..b082b85d18c4b014fee9a878a1f57d5a60cad160 100644 (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*) {