diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 120 | ||||
-rw-r--r-- | clang/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp | 32 | ||||
-rw-r--r-- | clang/test/SemaCXX/new-delete.cpp | 10 |
5 files changed, 117 insertions, 51 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index dbce3e912f9..e33fbe96d45 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 95934747d07..4d0d4225ce7 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -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(); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 070d26f00fe..228a716ca48 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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(); } } diff --git a/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp b/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp index f8fd9f2dd50..dac994393a6 100644 --- a/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp +++ b/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/basic.stc.dynamic.allocation/p1.cpp @@ -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}} +}; diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp index dd28413855b..8a3ec8b16a2 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -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 { |