forked from OSchip/llvm-project
Catch function redeclarations with incompatible exception specifications.
llvm-svn: 74787
This commit is contained in:
parent
108f89cbfa
commit
4f4d7b5d8e
|
@ -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<
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue