]> granicus.if.org Git - clang/commitdiff
More improvements to checking allocation and deallocation functions.
authorAnders Carlsson <andersca@mac.com>
Sun, 13 Dec 2009 17:53:43 +0000 (17:53 +0000)
committerAnders Carlsson <andersca@mac.com>
Sun, 13 Dec 2009 17:53:43 +0000 (17:53 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91244 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/Decl.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp
test/SemaCXX/new-delete.cpp

index dbce3e912f95b4aa27be41410bf7db4ba632c03b..e33fbe96d45829cc6f0ed19a26c73beefa60b89c 100644 (file)
@@ -2250,6 +2250,8 @@ def err_operator_new_dependent_param_type : Error<
   "use size_t (%1) instead">;
 def err_operator_new_param_type : Error<
   "%0 takes type size_t (%1) as first parameter">;
+def err_operator_new_default_arg: Error<
+  "parameter of %0 cannot have a default argument">;
 def err_operator_delete_dependent_param_type : Error<
   "%0 cannot take a dependent type as first parameter; use %1 instead">;
 def err_operator_delete_param_type : Error<
index 95934747d07f12cccdf346f77292fbd9bbf216d0..4d0d4225ce73889b7556141beadc228d44d39b82 100644 (file)
@@ -95,8 +95,8 @@ SourceRange ParmVarDecl::getDefaultArgRange() const {
   if (const Expr *E = getInit())
     return E->getSourceRange();
   
-  if (const Expr *E = getUninstantiatedDefaultArg())
-    return E->getSourceRange();
+  if (hasUninstantiatedDefaultArg())
+    return getUninstantiatedDefaultArg()->getSourceRange();
     
   return SourceRange();
 }
index 070d26f00fe7792e82468b7fa8dedf237338ec14..228a716ca483b4efe3333581291c94ba2ce20a66 100644 (file)
@@ -4624,33 +4624,83 @@ CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
   return false;
 }
 
+static inline bool
+CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
+                            CanQualType ExpectedResultType,
+                            CanQualType ExpectedFirstParamType,
+                            unsigned DependentParamTypeDiag,
+                            unsigned InvalidParamTypeDiag) {
+  QualType ResultType = 
+    FnDecl->getType()->getAs<FunctionType>()->getResultType();
+
+  // Check that the result type is not dependent.
+  if (ResultType->isDependentType())
+    return SemaRef.Diag(FnDecl->getLocation(),
+                        diag::err_operator_new_delete_dependent_result_type)
+    << FnDecl->getDeclName() << ExpectedResultType;
+
+  // Check that the result type is what we expect.
+  if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType)
+    return SemaRef.Diag(FnDecl->getLocation(),
+                        diag::err_operator_new_delete_invalid_result_type) 
+    << FnDecl->getDeclName() << ExpectedResultType;
+  
+  // A function template must have at least 2 parameters.
+  if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2)
+    return SemaRef.Diag(FnDecl->getLocation(),
+                      diag::err_operator_new_delete_template_too_few_parameters)
+        << FnDecl->getDeclName();
+  
+  // The function decl must have at least 1 parameter.
+  if (FnDecl->getNumParams() == 0)
+    return SemaRef.Diag(FnDecl->getLocation(),
+                        diag::err_operator_new_delete_too_few_parameters)
+      << FnDecl->getDeclName();
+  // Check the the first parameter type is not dependent.
+  QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
+  if (FirstParamType->isDependentType())
+    return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag)
+      << FnDecl->getDeclName() << ExpectedFirstParamType;
+
+  // Check that the first parameter type is what we expect.
+  if (SemaRef.Context.getCanonicalType(FirstParamType) != 
+      ExpectedFirstParamType)
+    return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag)
+    << FnDecl->getDeclName() << ExpectedFirstParamType;
+  
+  return false;
+}
+
 static bool
-CheckOperatorNewDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
+CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
   // C++ [basic.stc.dynamic.allocation]p1:
   //   A program is ill-formed if an allocation function is declared in a
   //   namespace scope other than global scope or declared static in global 
   //   scope.
   if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
     return true;
-  
-  bool ret = false;
-  if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
-    QualType SizeTy = 
-      SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType());
-    QualType T = SemaRef.Context.getCanonicalType((*Param)->getType());
-    if (!T->isDependentType() && SizeTy != T) {
-      SemaRef.Diag(FnDecl->getLocation(),
-                   diag::err_operator_new_param_type) << FnDecl->getDeclName()
-        << SizeTy;
-      ret = true;
-    }
-  }
-  QualType ResultTy = SemaRef.Context.getCanonicalType(FnDecl->getResultType());
-  if (!ResultTy->isDependentType() && ResultTy != SemaRef.Context.VoidPtrTy)
+
+  CanQualType SizeTy = 
+    SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType());
+
+  // C++ [basic.stc.dynamic.allocation]p1:
+  //  The return type shall be void*. The first parameter shall have type 
+  //  std::size_t.
+  if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy, 
+                                  SizeTy,
+                                  diag::err_operator_new_dependent_param_type,
+                                  diag::err_operator_new_param_type))
+    return true;
+
+  // C++ [basic.stc.dynamic.allocation]p1:
+  //  The first parameter shall not have an associated default argument.
+  if (FnDecl->getParamDecl(0)->hasDefaultArg())
     return SemaRef.Diag(FnDecl->getLocation(),
-                        diag::err_operator_new_delete_invalid_result_type) 
-      << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy;
-  return ret;
+                        diag::err_operator_new_default_arg)
+      << FnDecl->getDeclName() << FnDecl->getParamDecl(0)->getDefaultArgRange();
+
+  return false;
 }
 
 static bool
@@ -4665,25 +4715,11 @@ CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
   // 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())
-    return SemaRef.Diag(FnDecl->getLocation(),
-                        diag::err_operator_new_delete_dependent_result_type)
-      << FnDecl->getDeclName() << SemaRef.Context.VoidTy;
-    
-  if (!ResultType->isVoidType())
-    return SemaRef.Diag(FnDecl->getLocation(),
-                        diag::err_operator_new_delete_invalid_result_type) 
-      << FnDecl->getDeclName() << SemaRef.Context.VoidTy;
-
-  if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2)
-    return SemaRef.Diag(FnDecl->getLocation(),
-                      diag::err_operator_new_delete_template_too_few_parameters)
-        << FnDecl->getDeclName();
-  else if (FnDecl->getNumParams() == 0)
-    return SemaRef.Diag(FnDecl->getLocation(),
-                        diag::err_operator_new_delete_too_few_parameters)
-      << FnDecl->getDeclName();
+  if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy, 
+                                  SemaRef.Context.VoidPtrTy,
+                                 diag::err_operator_delete_dependent_param_type,
+                                 diag::err_operator_delete_param_type))
+    return true;
 
   QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
   if (FirstParamType->isDependentType())
@@ -4758,14 +4794,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
   if (Op != OO_Call) {
     for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
          Param != FnDecl->param_end(); ++Param) {
-      if ((*Param)->hasUnparsedDefaultArg())
-        return Diag((*Param)->getLocation(),
-                    diag::err_operator_overload_default_arg)
-          << FnDecl->getDeclName();
-      else if (Expr *DefArg = (*Param)->getDefaultArg())
+      if ((*Param)->hasDefaultArg())
         return Diag((*Param)->getLocation(),
                     diag::err_operator_overload_default_arg)
-          << FnDecl->getDeclName() << DefArg->getSourceRange();
+          << FnDecl->getDeclName() << (*Param)->getDefaultArgRange();
     }
   }
 
index f8fd9f2dd505e74571a64c53218daa24e0432b30..dac994393a61e9f3aa93331df0aa6fcebc94185f 100644 (file)
@@ -10,3 +10,35 @@ namespace NS {
 }
 
 static void *operator new(size_t); // expected-error {{'operator new' cannot be declared static in global scope}}
+
+struct B {
+  void operator new(size_t);  // expected-error {{'operator new' must return type 'void *'}}
+};
+
+struct C {
+  void *operator new(); // expected-error {{'operator new' must have at least one parameter}}
+};
+
+struct D {
+  void *operator new(bool); // expected-error {{'operator new' takes type size_t ('unsigned long') as first parameter}}
+};
+
+struct E {
+  void *operator new(size_t = 0); // expected-error {{parameter of 'operator new' cannot have a default argument}}
+};
+
+struct F {
+  template<typename T> void *operator new(size_t, int);
+};
+
+struct G {
+  template<typename T> T operator new(size_t, int); // expected-error {{'operator new' cannot have a dependent return type; use 'void *' instead}}
+};
+
+struct H {
+  template<typename T> void *operator new(T, int); // expected-error {{'operator new' cannot take a dependent type as first parameter; use size_t}}
+};
+
+struct I {
+  template<typename T> void *operator new(size_t); // expected-error {{'operator new' template must have at least two parameters}}
+};
index dd28413855bd27b7dd4d65440e9f75fccc53d6fe..8a3ec8b16a2625f713a212b91678edb130aee04c 100644 (file)
@@ -140,10 +140,8 @@ public:
 
 class Base {
 public:
-  static int operator new(signed char) throw(); // expected-error {{'operator new' takes type size_t}} \
-                                                 // expected-error {{operator new' must return type 'void *'}}
-  static int operator new[] (signed char) throw(); // expected-error {{'operator new[]' takes type size_t}} \
-                                                    // expected-error {{operator new[]' must return type 'void *'}}
+  static void *operator new(signed char) throw(); // expected-error {{'operator new' takes type size_t}}
+  static int operator new[] (size_t) throw(); // expected-error {{operator new[]' must return type 'void *'}}
 };
 
 class Tier {};
@@ -160,9 +158,11 @@ void loadEngineFor() {
 }
 
 template <class T> struct TBase {
-  void* operator new(T size, int); // expected-error {{'operator new' takes type size_t}}
+  void* operator new(T size, int); // expected-error {{'operator new' cannot take a dependent type as first parameter; use size_t}}\
+                                   // expected-error {{'operator new' takes type size_t}}
 };
 
+// FIXME: We should not try to instantiate operator new, since it is invalid.
 TBase<int> t1; // expected-note {{in instantiation of template class 'struct TBase<int>' requested here}}
 
 class X6 {