зеркало из https://github.com/microsoft/clang-1.git
Work around an annoying, non-standard optimization in the glibc
headers, where malloc (and many other libc functions) are declared with empty throw specifications, e.g., extern void *malloc (__SIZE_TYPE__ __size) throw () __attribute__ ((__malloc__)) ; The C++ standard doesn't seem to allow this, and redeclaring malloc as the standard permits (as follows) resulted in Clang (rightfully!) complaining about mis-matched exception specifications. void *malloc(size_t size); We work around this by silently propagating an empty throw specification "throw()" from a function with C linkage declared in a system header to a redeclaration that has no throw specifier. Ick. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95969 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
96058953c7
Коммит
e13ad83770
|
@ -657,13 +657,15 @@ public:
|
|||
static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0);
|
||||
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
|
||||
bool CheckDistantExceptionSpec(QualType T);
|
||||
bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
|
||||
bool CheckEquivalentExceptionSpec(
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc);
|
||||
bool CheckEquivalentExceptionSpec(
|
||||
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc);
|
||||
const FunctionProtoType *New, SourceLocation NewLoc,
|
||||
bool *MissingEmptyExceptionSpecification = 0);
|
||||
bool CheckExceptionSpecSubset(
|
||||
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
|
||||
const FunctionProtoType *Superset, SourceLocation SuperLoc,
|
||||
|
|
|
@ -356,9 +356,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
|
|||
}
|
||||
}
|
||||
|
||||
if (CheckEquivalentExceptionSpec(
|
||||
Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
|
||||
New->getType()->getAs<FunctionProtoType>(), New->getLocation()))
|
||||
if (CheckEquivalentExceptionSpec(Old, New))
|
||||
Invalid = true;
|
||||
|
||||
return Invalid;
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Sema.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
|
||||
namespace clang {
|
||||
|
@ -92,6 +93,52 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
|
|||
return FnT->hasExceptionSpec();
|
||||
}
|
||||
|
||||
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
|
||||
bool MissingEmptyExceptionSpecification = false;
|
||||
if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
|
||||
diag::note_previous_declaration,
|
||||
Old->getType()->getAs<FunctionProtoType>(),
|
||||
Old->getLocation(),
|
||||
New->getType()->getAs<FunctionProtoType>(),
|
||||
New->getLocation(),
|
||||
&MissingEmptyExceptionSpecification))
|
||||
return false;
|
||||
|
||||
// The failure was something other than an empty exception
|
||||
// specification; return an error.
|
||||
if (!MissingEmptyExceptionSpecification)
|
||||
return true;
|
||||
|
||||
// The new function declaration is only missing an empty exception
|
||||
// specification "throw()". If the throw() specification came from a
|
||||
// function in a system header that has C linkage, just add an empty
|
||||
// exception specification to the "new" declaration. This is an
|
||||
// egregious workaround for glibc, which adds throw() specifications
|
||||
// to many libc functions as an optimization. Unfortunately, that
|
||||
// optimization isn't permitted by the C++ standard, so we're forced
|
||||
// to work around it here.
|
||||
if (isa<FunctionProtoType>(New->getType()) &&
|
||||
Context.getSourceManager().isInSystemHeader(Old->getLocation()) &&
|
||||
Old->isExternC()) {
|
||||
const FunctionProtoType *NewProto
|
||||
= cast<FunctionProtoType>(New->getType());
|
||||
QualType NewType = Context.getFunctionType(NewProto->getResultType(),
|
||||
NewProto->arg_type_begin(),
|
||||
NewProto->getNumArgs(),
|
||||
NewProto->isVariadic(),
|
||||
NewProto->getTypeQuals(),
|
||||
true, false, 0, 0,
|
||||
NewProto->getNoReturnAttr(),
|
||||
NewProto->getCallConv());
|
||||
New->setType(NewType);
|
||||
return false;
|
||||
}
|
||||
|
||||
Diag(New->getLocation(), diag::err_mismatched_exception_spec);
|
||||
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
@ -111,12 +158,26 @@ bool Sema::CheckEquivalentExceptionSpec(
|
|||
bool Sema::CheckEquivalentExceptionSpec(
|
||||
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc) {
|
||||
const FunctionProtoType *New, SourceLocation NewLoc,
|
||||
bool *MissingEmptyExceptionSpecification) {
|
||||
if (MissingEmptyExceptionSpecification)
|
||||
*MissingEmptyExceptionSpecification = false;
|
||||
|
||||
bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
|
||||
bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
|
||||
if (OldAny && NewAny)
|
||||
return false;
|
||||
if (OldAny || NewAny) {
|
||||
if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() &&
|
||||
!Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 &&
|
||||
!New->hasExceptionSpec()) {
|
||||
// The old type has a throw() exception specification and the
|
||||
// new type has no exception specification, and the caller asked
|
||||
// to handle this itself.
|
||||
*MissingEmptyExceptionSpecification = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Diag(NewLoc, DiagID);
|
||||
if (NoteID.getDiagID() != 0)
|
||||
Diag(OldLoc, NoteID);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
config.suffixes = []
|
|
@ -0,0 +1,3 @@
|
|||
extern "C" {
|
||||
extern void *malloc (__SIZE_TYPE__ __size) throw () __attribute__ ((__malloc__)) ;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
|
||||
#include <malloc.h>
|
||||
|
||||
extern "C" {
|
||||
void *malloc(__SIZE_TYPE__);
|
||||
}
|
Загрузка…
Ссылка в новой задаче