From: Sebastian Redl Date: Mon, 14 Mar 2011 18:08:30 +0000 (+0000) Subject: Make deallocation functions implicitly noexcept in C++0x. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8999fe1bc367b3ecc878d135c7b31e3479da56f4;p=clang Make deallocation functions implicitly noexcept in C++0x. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127596 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 3b2a062162..7c3f726a99 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3733,7 +3733,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } bool isStatic = SC == SC_Static; - + // [class.free]p1: // Any allocation function for a class T is a static member // (even if not explicitly declared static). @@ -3746,7 +3746,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Name.getCXXOverloadedOperator() == OO_Delete || Name.getCXXOverloadedOperator() == OO_Array_Delete) isStatic = true; - + // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast(DC), D.getSourceRange().getBegin(), diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 5701835c1a..fe0d413a76 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1404,11 +1404,18 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, /// DeclareGlobalNewDelete - Declare the global forms of operator new and /// delete. These are: /// @code +/// // C++03: /// void* operator new(std::size_t) throw(std::bad_alloc); /// void* operator new[](std::size_t) throw(std::bad_alloc); /// void operator delete(void *) throw(); /// void operator delete[](void *) throw(); +/// // C++0x: +/// void* operator new(std::size_t); +/// void* operator new[](std::size_t); +/// void operator delete(void *); +/// void operator delete[](void *); /// @endcode +/// C++0x operator delete is implicitly noexcept. /// Note that the placement and nothrow forms of new are *not* implicitly /// declared. Their use requires including \. void Sema::DeclareGlobalNewDelete() { @@ -1420,10 +1427,16 @@ void Sema::DeclareGlobalNewDelete() { // implicitly declared in global scope in each translation unit of a // program // + // C++03: // void* operator new(std::size_t) throw(std::bad_alloc); // void* operator new[](std::size_t) throw(std::bad_alloc); // void operator delete(void*) throw(); // void operator delete[](void*) throw(); + // C++0x: + // void* operator new(std::size_t); + // void* operator new[](std::size_t); + // void operator delete(void*); + // void operator delete[](void*); // // These implicit declarations introduce only the function names operator // new, operator new[], operator delete, operator delete[]. @@ -1432,7 +1445,9 @@ void Sema::DeclareGlobalNewDelete() { // "std" or "bad_alloc" as necessary to form the exception specification. // However, we do not make these implicit declarations visible to name // lookup. - if (!StdBadAlloc) { + // Note that the C++0x versions of operator delete are deallocation functions, + // and thus are implicitly noexcept. + if (!StdBadAlloc && !getLangOptions().CPlusPlus0x) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, @@ -1495,18 +1510,21 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, bool HasBadAllocExceptionSpec = (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New); - if (HasBadAllocExceptionSpec) { + if (HasBadAllocExceptionSpec && !getLangOptions().CPlusPlus0x) { assert(StdBadAlloc && "Must have std::bad_alloc declared"); BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); } FunctionProtoType::ExtProtoInfo EPI; if (HasBadAllocExceptionSpec) { - EPI.ExceptionSpecType = EST_Dynamic; - EPI.NumExceptions = 1; - EPI.Exceptions = &BadAllocType; + if (!getLangOptions().CPlusPlus0x) { + EPI.ExceptionSpecType = EST_Dynamic; + EPI.NumExceptions = 1; + EPI.Exceptions = &BadAllocType; + } } else { - EPI.ExceptionSpecType = EST_DynamicNone; + EPI.ExceptionSpecType = getLangOptions().CPlusPlus0x ? + EST_BasicNoexcept : EST_DynamicNone; } QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index f49a49c28f..e766ced1b6 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1494,9 +1494,19 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, TypeProcessingState state(*this, D); + // In C++0x, deallocation functions (normal and array operator delete) + // are implicitly noexcept. + bool ImplicitlyNoexcept = false; + switch (D.getName().getKind()) { - case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: + if (getLangOptions().CPlusPlus0x) { + OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator; + if (OO == OO_Delete || OO == OO_Array_Delete) + ImplicitlyNoexcept = true; + } + // Intentional fall-through. + case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: T = ConvertDeclSpecToType(*this, state); @@ -1917,6 +1927,10 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, else EPI.NoexceptExpr = NoexceptExpr; } + } else if (FTI.getExceptionSpecType() == EST_None && + ImplicitlyNoexcept && chunkIndex == 0) { + // Only the outermost chunk is marked noexcept, of course. + EPI.ExceptionSpecType = EST_BasicNoexcept; } T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI); diff --git a/test/CXX/except/except.spec/p15.cpp b/test/CXX/except/except.spec/p15.cpp new file mode 100644 index 0000000000..2dae9623e0 --- /dev/null +++ b/test/CXX/except/except.spec/p15.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s + +// Deallocation functions are implicitly noexcept. +// Thus, explicit specs aren't allowed to conflict. + +void f() { + // Force implicit declaration of delete. + delete new int; + delete[] new int[1]; +} + +void operator delete(void*) noexcept; +void operator delete[](void*) noexcept; + +// Same goes for explicit declarations. +void operator delete(void*, float); +void operator delete(void*, float) noexcept; + +void operator delete[](void*, float); +void operator delete[](void*, float) noexcept; + +// But explicit specs stay. +void operator delete(void*, double) throw(int); // expected-note {{previous}} +void operator delete(void*, double) noexcept; // expected-error {{does not match}}