forked from OSchip/llvm-project
Implement a hack to work around the changing exception specification of operator new in C++0x.
llvm-svn: 127688
This commit is contained in:
parent
cdb2ae587a
commit
cb5dd00796
|
@ -758,7 +758,8 @@ public:
|
|||
const FunctionProtoType *New, SourceLocation NewLoc,
|
||||
bool *MissingExceptionSpecification = 0,
|
||||
bool *MissingEmptyExceptionSpecification = 0,
|
||||
bool AllowNoexceptAllMatchWithNoSpec = false);
|
||||
bool AllowNoexceptAllMatchWithNoSpec = false,
|
||||
bool IsOperatorNew = false);
|
||||
bool CheckExceptionSpecSubset(
|
||||
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
|
||||
const FunctionProtoType *Superset, SourceLocation SuperLoc,
|
||||
|
|
|
@ -96,6 +96,8 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
|
|||
}
|
||||
|
||||
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
|
||||
OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
|
||||
bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
|
||||
bool MissingExceptionSpecification = false;
|
||||
bool MissingEmptyExceptionSpecification = false;
|
||||
if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec),
|
||||
|
@ -106,7 +108,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
|
|||
New->getLocation(),
|
||||
&MissingExceptionSpecification,
|
||||
&MissingEmptyExceptionSpecification,
|
||||
/*AllowNoexceptAllMatchWithNoSpec=*/true))
|
||||
/*AllowNoexceptAllMatchWithNoSpec=*/true,
|
||||
IsOperatorNew))
|
||||
return false;
|
||||
|
||||
// The failure was something other than an empty exception
|
||||
|
@ -272,7 +275,8 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
|||
SourceLocation NewLoc,
|
||||
bool *MissingExceptionSpecification,
|
||||
bool*MissingEmptyExceptionSpecification,
|
||||
bool AllowNoexceptAllMatchWithNoSpec) {
|
||||
bool AllowNoexceptAllMatchWithNoSpec,
|
||||
bool IsOperatorNew) {
|
||||
// Just completely ignore this under -fno-exceptions.
|
||||
if (!getLangOptions().CXXExceptions)
|
||||
return false;
|
||||
|
@ -374,6 +378,38 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
|||
if (OldNonThrowing && NewNonThrowing)
|
||||
return false;
|
||||
|
||||
// As a special compatibility feature, under C++0x we accept no spec and
|
||||
// throw(std::bad_alloc) as equivalent for operator new and operator new[].
|
||||
// This is because the implicit declaration changed, but old code would break.
|
||||
if (getLangOptions().CPlusPlus0x && IsOperatorNew) {
|
||||
const FunctionProtoType *WithExceptions = 0;
|
||||
if (OldEST == EST_None && NewEST == EST_Dynamic)
|
||||
WithExceptions = New;
|
||||
else if (OldEST == EST_Dynamic && NewEST == EST_None)
|
||||
WithExceptions = Old;
|
||||
if (WithExceptions && WithExceptions->getNumExceptions() == 1) {
|
||||
// One has no spec, the other throw(something). If that something is
|
||||
// std::bad_alloc, all conditions are met.
|
||||
QualType Exception = *WithExceptions->exception_begin();
|
||||
if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) {
|
||||
IdentifierInfo* Name = ExRecord->getIdentifier();
|
||||
if (Name && Name->getName() == "bad_alloc") {
|
||||
// It's called bad_alloc, but is it in std?
|
||||
DeclContext* DC = ExRecord->getDeclContext();
|
||||
while (DC && !isa<NamespaceDecl>(DC))
|
||||
DC = DC->getParent();
|
||||
if (DC) {
|
||||
NamespaceDecl* NS = cast<NamespaceDecl>(DC);
|
||||
IdentifierInfo* NSName = NS->getIdentifier();
|
||||
if (NSName && NSName->getName() == "std" &&
|
||||
isa<TranslationUnitDecl>(NS->getParent()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, the only remaining valid case is two matching dynamic
|
||||
// specifications. We return here unless both specifications are dynamic.
|
||||
if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) {
|
||||
|
|
|
@ -92,3 +92,14 @@ extern void (*r20)() noexcept(false); // expected-error {{does not match}}
|
|||
|
||||
extern void (*r21)() throw(int); // expected-note {{previous declaration}}
|
||||
extern void (*r21)() noexcept(true); // expected-error {{does not match}}
|
||||
|
||||
|
||||
// As a very special workaround, we allow operator new to match no spec
|
||||
// with a throw(bad_alloc) spec, because C++0x makes an incompatible change
|
||||
// here.
|
||||
namespace std { class bad_alloc {}; }
|
||||
void* operator new(unsigned long) throw(std::bad_alloc);
|
||||
void* operator new(unsigned long);
|
||||
void* operator new[](unsigned long) throw(std::bad_alloc);
|
||||
void* operator new[](unsigned long);
|
||||
|
||||
|
|
Loading…
Reference in New Issue