Catch function redeclarations with incompatible exception specifications.

llvm-svn: 74787
This commit is contained in:
Sebastian Redl 2009-07-04 11:39:00 +00:00
parent 108f89cbfa
commit 4f4d7b5d8e
5 changed files with 88 additions and 1 deletions

View File

@ -287,6 +287,8 @@ def err_distant_exception_spec : Error<
def err_incomplete_in_exception_spec : Error<
"%select{|pointer to |reference to }1incomplete type %0 is not allowed "
"in exception specification">;
def err_mismatched_exception_spec : Error<
"exception specification in declaration does not match previous declaration">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<

View File

@ -86,6 +86,7 @@ namespace clang {
class ObjCMethodDecl;
class ObjCPropertyDecl;
class ObjCContainerDecl;
class FunctionProtoType;
class BasePaths;
struct MemberLookupCriteria;
class CXXTemporary;
@ -394,6 +395,9 @@ public:
DeclarationName GetNameForDeclarator(Declarator &D);
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
bool CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc);
QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);

View File

@ -258,6 +258,12 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
}
}
if (CheckEquivalentExceptionSpec(
Old->getType()->getAsFunctionProtoType(), Old->getLocation(),
New->getType()->getAsFunctionProtoType(), New->getLocation())) {
Invalid = true;
}
return Invalid;
}

View File

@ -17,6 +17,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace clang;
/// \brief Perform adjustment on the parameter type of a function.
@ -1063,6 +1064,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.
QualType ClsType;
if (isDependentScopeSpecifier(DeclType.Mem.Scope())) {
@ -1187,6 +1195,45 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
return FnT->hasExceptionSpec();
}
/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
/// exception specifications. Exception specifications are equivalent if
/// they allow exactly the same set of exception types. It does not matter how
/// that is achieved. See C++ [except.spec]p2.
bool Sema::CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc) {
bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
if (OldAny && NewAny)
return false;
if (OldAny || NewAny) {
Diag(NewLoc, diag::err_mismatched_exception_spec);
Diag(OldLoc, diag::note_previous_declaration);
return true;
}
bool Success = true;
// Both have a definite exception spec. Collect the first set, then compare
// to the second.
llvm::SmallPtrSet<const Type*, 8> Types;
for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
E = Old->exception_end(); I != E; ++I)
Types.insert(Context.getCanonicalType(*I).getTypePtr());
for (FunctionProtoType::exception_iterator I = New->exception_begin(),
E = New->exception_end(); I != E && Success; ++I)
Success = Types.erase(Context.getCanonicalType(*I).getTypePtr());
Success = Success && Types.empty();
if (Success) {
return false;
}
Diag(NewLoc, diag::err_mismatched_exception_spec);
Diag(OldLoc, diag::note_previous_declaration);
return true;
}
/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
/// declarator
QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {

View File

@ -1,4 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
// RUN: clang-cc -fsyntax-only -verify -fms-extensions %s
// Straight from the standard:
// Plain function with spec
@ -33,3 +33,31 @@ void ic2() throw(Incomplete); // expected-error {{incomplete type 'struct Incomp
void ic3() throw(void*);
void ic4() throw(Incomplete*); // expected-error {{pointer to incomplete type 'struct Incomplete' is not allowed in exception specification}}
void ic5() throw(Incomplete&); // expected-error {{reference to incomplete type 'struct Incomplete' is not allowed in exception specification}}
// Redeclarations
typedef int INT;
void r1() throw(int);
void r1() throw(int);
void r2() throw(int);
void r2() throw(INT);
// throw-any spec and no spec at all are semantically equivalent
void r3();
void r3() throw(...);
void r4() throw(int, float);
void r4() throw(float, int);
void r5() throw(int); // expected-note {{previous declaration}}
void r5(); // expected-error {{exception specification in declaration does not match}}
void r6() throw(...); // expected-note {{previous declaration}}
void r6() throw(int); // expected-error {{exception specification in declaration does not match}}
void r7() throw(int); // expected-note {{previous declaration}}
void r7() throw(float); // expected-error {{exception specification in declaration does not match}}
// Top-level const doesn't matter.
void r8() throw(int);
void r8() throw(const int);