diff options
| author | Roman Divacky <rdivacky@FreeBSD.org> | 2010-04-02 08:55:10 +0000 | 
|---|---|---|
| committer | Roman Divacky <rdivacky@FreeBSD.org> | 2010-04-02 08:55:10 +0000 | 
| commit | 11d2b2d2bb706fca0656f2760839721bb7f6cb6f (patch) | |
| tree | d374cdca417e76f1bf101f139dba2db1d10ee8f7 /lib/Sema/SemaExceptionSpec.cpp | |
| parent | c0c7bca4e5b8d12699dc93a0da49e9e4bb79671b (diff) | |
Notes
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 4ce1ce9b019fc..53e9385749fb8 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>(), | 
