/// 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) {
  return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
                                      diag::note_previous_declaration,
                                      Old, OldLoc, New, NewLoc);
}
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;
}
Esempio n. 3
0
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
  bool MissingExceptionSpecification = false;
  bool MissingEmptyExceptionSpecification = false;
  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 (!MissingExceptionSpecification && !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 (MissingEmptyExceptionSpecification &&
      isa<FunctionProtoType>(New->getType()) &&
      (Old->getLocation().isInvalid() ||
       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->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;
}