/// 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; }
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; }