From 6a7330c20cabf1cf1cd46f5dfc183ec3a72add66 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Fri, 29 May 2009 15:01:05 +0000 Subject: [PATCH] Disallow exception specifications on multi-level indirections. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72571 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 5 +++ lib/Sema/Sema.h | 1 + lib/Sema/SemaType.cpp | 46 ++++++++++++++++++++++ test/SemaCXX/exception-spec.cpp | 25 ++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 test/SemaCXX/exception-spec.cpp diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 39feda9691..ed64f8a3d1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -268,6 +268,11 @@ def err_deleted_non_function : Error< def err_deleted_decl_not_first : Error< "deleted definition must be first declaration">; +// C++ exception specifications +def err_distant_exception_spec : Error< + "exception specifications are not allowed beyond a single level " + "of indirection">; + // C++ access checking def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 75632d560e..6559ca4f8f 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -349,6 +349,7 @@ public: QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0, TagDecl **OwnedDecl = 0); DeclarationName GetNameForDeclarator(Declarator &D); + bool CheckDistantExceptionSpec(QualType T); QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 83f9b60fd7..01b8aa4fd4 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -682,14 +682,35 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, .getQualifiedType(DeclType.Cls.TypeQuals)); break; case DeclaratorChunk::Pointer: + // Verify that we're not building a pointer to pointer to function with + // exception specification. + if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { + Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + D.setInvalidType(true); + // Build the type anyway. + } T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); break; case DeclaratorChunk::Reference: + // Verify that we're not building a reference to pointer to function with + // exception specification. + if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { + Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + D.setInvalidType(true); + // Build the type anyway. + } T = BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Ref.HasRestrict ? QualType::Restrict : 0, DeclType.Loc, Name); break; case DeclaratorChunk::Array: { + // Verify that we're not building an array of pointers to function with + // exception specification. + if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { + Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + D.setInvalidType(true); + // Build the type anyway. + } DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; Expr *ArraySize = static_cast(ATI.NumElts); ArrayType::ArraySizeModifier ASM; @@ -834,6 +855,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, break; } case DeclaratorChunk::MemberPointer: + // Verify that we're not building a pointer to pointer to function with + // exception specification. + if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { + Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + D.setInvalidType(true); + // Build the type anyway. + } // The scope spec must refer to a class, or be dependent. DeclContext *DC = computeDeclContext(DeclType.Mem.Scope()); QualType ClsType; @@ -925,6 +953,24 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, return T; } +/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer +/// to member to a function with an exception specification. This means that +/// it is invalid to add another level of indirection. +bool Sema::CheckDistantExceptionSpec(QualType T) { + if (const PointerType *PT = T->getAsPointerType()) + T = PT->getPointeeType(); + else if (const MemberPointerType *PT = T->getAsMemberPointerType()) + T = PT->getPointeeType(); + else + return false; + + const FunctionProtoType *FnT = T->getAsFunctionProtoType(); + if (!FnT) + return false; + + return FnT->hasExceptionSpec(); +} + /// ObjCGetTypeForMethodDefinition - Builds the type for a method definition /// declarator QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) { diff --git a/test/SemaCXX/exception-spec.cpp b/test/SemaCXX/exception-spec.cpp new file mode 100644 index 0000000000..d697e02355 --- /dev/null +++ b/test/SemaCXX/exception-spec.cpp @@ -0,0 +1,25 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Straight from the standard: +// Plain function with spec +void f() throw(int); +// Pointer to function with spec +void (*fp)() throw (int); +// Function taking reference to function with spec +void g(void pfa() throw(int)); +// Typedef for pointer to function with spec +typedef int (*pf)() throw(int); // xpected-error spec-on-typedef + +// Some more: +// Function returning function with spec +void (*h())() throw(int); +// Ultimate parser thrill: function with spec returning function with spec and +// taking pointer to function with spec. +// The actual function throws int, the return type double, the argument float. +void (*i() throw(int))(void (*)() throw(float)) throw(double); +// Pointer to pointer to function taking function with spec +void (**k)(void pfa() throw(int)); // no-error +// Pointer to pointer to function with spec +void (**j)() throw(int); // expected-error {{not allowed beyond a single}} +// Pointer to function returning pointer to pointer to function with spec +void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}} -- 2.40.0