diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-04-02 08:55:10 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-04-02 08:55:10 +0000 |
commit | 07b2cfcdb817cc0790420f159a313d61e7241cb9 (patch) | |
tree | d374cdca417e76f1bf101f139dba2db1d10ee8f7 /lib/Sema/SemaExceptionSpec.cpp | |
parent | 1e255aab650a7fa2047fd953cae65b12215280af (diff) | |
download | FreeBSD-src-07b2cfcdb817cc0790420f159a313d61e7241cb9.zip FreeBSD-src-07b2cfcdb817cc0790420f159a313d61e7241cb9.tar.gz |
Update clang to r100181.
Diffstat (limited to 'lib/Sema/SemaExceptionSpec.cpp')
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 154 |
1 files changed, 128 insertions, 26 deletions
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 4ce1ce9..53e9385 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -15,6 +15,8 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" @@ -94,19 +96,21 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { } bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { + bool MissingExceptionSpecification = false; bool MissingEmptyExceptionSpecification = false; - if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, - diag::note_previous_declaration, + if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec), + PDiag(diag::note_previous_declaration), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), New->getType()->getAs<FunctionProtoType>(), New->getLocation(), + &MissingExceptionSpecification, &MissingEmptyExceptionSpecification)) return false; // The failure was something other than an empty exception // specification; return an error. - if (!MissingEmptyExceptionSpecification) + if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) return true; // The new function declaration is only missing an empty exception @@ -117,8 +121,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // 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()) && + if (MissingEmptyExceptionSpecification && + isa<FunctionProtoType>(New->getType()) && + (Old->getLocation().isInvalid() || + Context.getSourceManager().isInSystemHeader(Old->getLocation())) && Old->isExternC()) { const FunctionProtoType *NewProto = cast<FunctionProtoType>(New->getType()); @@ -128,12 +134,91 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { NewProto->isVariadic(), NewProto->getTypeQuals(), true, false, 0, 0, - NewProto->getNoReturnAttr(), - NewProto->getCallConv()); + NewProto->getExtInfo()); New->setType(NewType); return false; } + if (MissingExceptionSpecification && isa<FunctionProtoType>(New->getType())) { + const FunctionProtoType *NewProto + = cast<FunctionProtoType>(New->getType()); + const FunctionProtoType *OldProto + = Old->getType()->getAs<FunctionProtoType>(); + + // Update the type of the function with the appropriate exception + // specification. + QualType NewType = Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + NewProto->isVariadic(), + NewProto->getTypeQuals(), + OldProto->hasExceptionSpec(), + OldProto->hasAnyExceptionSpec(), + OldProto->getNumExceptions(), + OldProto->exception_begin(), + NewProto->getExtInfo()); + New->setType(NewType); + + // If exceptions are disabled, suppress the warning about missing + // exception specifications for new and delete operators. + if (!getLangOptions().Exceptions) { + switch (New->getDeclName().getCXXOverloadedOperator()) { + case OO_New: + case OO_Array_New: + case OO_Delete: + case OO_Array_Delete: + if (New->getDeclContext()->isTranslationUnit()) + return false; + break; + + default: + break; + } + } + + // Warn about the lack of exception specification. + llvm::SmallString<128> ExceptionSpecString; + llvm::raw_svector_ostream OS(ExceptionSpecString); + OS << "throw("; + bool OnFirstException = true; + for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(), + EEnd = OldProto->exception_end(); + E != EEnd; + ++E) { + if (OnFirstException) + OnFirstException = false; + else + OS << ", "; + + OS << E->getAsString(Context.PrintingPolicy); + } + OS << ")"; + OS.flush(); + + SourceLocation AfterParenLoc; + if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { + TypeLoc TL = TSInfo->getTypeLoc(); + if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL)) + AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc()); + } + + if (AfterParenLoc.isInvalid()) + Diag(New->getLocation(), diag::warn_missing_exception_specification) + << New << OS.str(); + else { + // FIXME: This will get more complicated with C++0x + // late-specified return types. + Diag(New->getLocation(), diag::warn_missing_exception_specification) + << New << OS.str() + << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str()); + } + + if (!Old->getLocation().isInvalid()) + Diag(Old->getLocation(), diag::note_previous_declaration); + + return false; + } + Diag(New->getLocation(), diag::err_mismatched_exception_spec); Diag(Old->getLocation(), diag::note_previous_declaration); return true; @@ -146,8 +231,9 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { bool Sema::CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc) { - return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, - diag::note_previous_declaration, + return CheckEquivalentExceptionSpec( + PDiag(diag::err_mismatched_exception_spec), + PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc); } @@ -155,11 +241,17 @@ bool Sema::CheckEquivalentExceptionSpec( /// 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 PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, - const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc, - bool *MissingEmptyExceptionSpecification) { +bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, + const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, + SourceLocation OldLoc, + const FunctionProtoType *New, + SourceLocation NewLoc, + bool *MissingExceptionSpecification, + bool *MissingEmptyExceptionSpecification) { + if (MissingExceptionSpecification) + *MissingExceptionSpecification = false; + if (MissingEmptyExceptionSpecification) *MissingEmptyExceptionSpecification = false; @@ -168,13 +260,20 @@ bool Sema::CheckEquivalentExceptionSpec( if (OldAny && NewAny) return false; if (OldAny || NewAny) { - if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() && - !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 && + if (MissingExceptionSpecification && Old->hasExceptionSpec() && !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; + // The old type has an exception specification of some sort, but + // the new type does not. + *MissingExceptionSpecification = true; + + if (MissingEmptyExceptionSpecification && + !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) { + // 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; } @@ -350,7 +449,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, const FunctionProtoType *Source, SourceLocation SourceLoc) { if (CheckSpecForTypesEquivalent(*this, - PDiag(diag::err_deep_exception_specs_differ) << 0, 0, + PDiag(diag::err_deep_exception_specs_differ) << 0, + PDiag(), Target->getResultType(), TargetLoc, Source->getResultType(), SourceLoc)) return true; @@ -361,7 +461,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, "Functions have different argument counts."); for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) { if (CheckSpecForTypesEquivalent(*this, - PDiag(diag::err_deep_exception_specs_differ) << 1, 0, + PDiag(diag::err_deep_exception_specs_differ) << 1, + PDiag(), Target->getArgType(i), TargetLoc, Source->getArgType(i), SourceLoc)) return true; @@ -386,15 +487,16 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) // This means that the source of the conversion can only throw a subset of // the exceptions of the target, and any exception specs on arguments or // return types must be equivalent. - return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs, - 0, ToFunc, From->getSourceRange().getBegin(), + return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), + PDiag(), ToFunc, + From->getSourceRange().getBegin(), FromFunc, SourceLocation()); } bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - return CheckExceptionSpecSubset(diag::err_override_exception_spec, - diag::note_overridden_virtual_function, + return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec), + PDiag(diag::note_overridden_virtual_function), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), New->getType()->getAs<FunctionProtoType>(), |