mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-14 14:56:47 +00:00
[c++1z] Improve support for -fno-exceptions: we can't just ignore exception
specifications in this mode in C++17, since they're part of the function type, so check and diagnose them like we would if exceptions were enabled. Better ideas welcome. llvm-svn: 288220
This commit is contained in:
parent
f9b191f135
commit
13b40bcc03
@ -1306,6 +1306,8 @@ def err_mismatched_exception_spec : Error<
|
||||
"exception specification in declaration does not match previous declaration">;
|
||||
def ext_mismatched_exception_spec : ExtWarn<err_mismatched_exception_spec.Text>,
|
||||
InGroup<MicrosoftExceptionSpec>;
|
||||
def warn_mismatched_exception_spec_no_exceptions : ExtWarn<err_mismatched_exception_spec.Text>,
|
||||
InGroup<DiagGroup<"exception-spec-no-exceptions">>;
|
||||
def err_override_exception_spec : Error<
|
||||
"exception specification of overriding function is more lax than "
|
||||
"base version">;
|
||||
|
@ -1330,11 +1330,7 @@ public:
|
||||
bool CheckEquivalentExceptionSpec(
|
||||
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc,
|
||||
bool *MissingExceptionSpecification = nullptr,
|
||||
bool *MissingEmptyExceptionSpecification = nullptr,
|
||||
bool AllowNoexceptAllMatchWithNoSpec = false,
|
||||
bool IsOperatorNew = false);
|
||||
const FunctionProtoType *New, SourceLocation NewLoc);
|
||||
bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
|
||||
const PartialDiagnostic &NestedDiagID,
|
||||
const PartialDiagnostic &NoteID,
|
||||
|
@ -2949,15 +2949,6 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
|
||||
// but do not necessarily update the type of New.
|
||||
if (CheckEquivalentExceptionSpec(Old, New))
|
||||
return true;
|
||||
// If exceptions are disabled, we might not have resolved the exception spec
|
||||
// of one or both declarations. Do so now in C++1z, so that we can properly
|
||||
// compare the types.
|
||||
if (getLangOpts().CPlusPlus1z) {
|
||||
for (QualType T : {Old->getType(), New->getType()})
|
||||
if (auto *FPT = T->getAs<FunctionProtoType>())
|
||||
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
|
||||
ResolveExceptionSpec(New->getLocation(), FPT);
|
||||
}
|
||||
OldQType = Context.getCanonicalType(Old->getType());
|
||||
NewQType = Context.getCanonicalType(New->getType());
|
||||
|
||||
|
@ -207,6 +207,14 @@ Sema::UpdateExceptionSpec(FunctionDecl *FD,
|
||||
Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
|
||||
}
|
||||
|
||||
static bool CheckEquivalentExceptionSpecImpl(
|
||||
Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc,
|
||||
bool *MissingExceptionSpecification = nullptr,
|
||||
bool *MissingEmptyExceptionSpecification = nullptr,
|
||||
bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false);
|
||||
|
||||
/// Determine whether a function has an implicitly-generated exception
|
||||
/// specification.
|
||||
static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
|
||||
@ -229,6 +237,12 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
|
||||
}
|
||||
|
||||
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
|
||||
// Just completely ignore this under -fno-exceptions prior to C++1z.
|
||||
// In C++1z onwards, the exception specification is part of the type and
|
||||
// we will diagnose mismatches anyway, so it's better to check for them here.
|
||||
if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus1z)
|
||||
return false;
|
||||
|
||||
OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
|
||||
bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
|
||||
bool MissingExceptionSpecification = false;
|
||||
@ -243,8 +257,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
|
||||
|
||||
// Check the types as written: they must match before any exception
|
||||
// specification adjustment is applied.
|
||||
if (!CheckEquivalentExceptionSpec(
|
||||
PDiag(DiagID), PDiag(diag::note_previous_declaration),
|
||||
if (!CheckEquivalentExceptionSpecImpl(
|
||||
*this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
|
||||
Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
|
||||
New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
|
||||
&MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
|
||||
@ -395,11 +409,15 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
|
||||
bool Sema::CheckEquivalentExceptionSpec(
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc) {
|
||||
if (!getLangOpts().CXXExceptions)
|
||||
return false;
|
||||
|
||||
unsigned DiagID = diag::err_mismatched_exception_spec;
|
||||
if (getLangOpts().MicrosoftExt)
|
||||
DiagID = diag::ext_mismatched_exception_spec;
|
||||
bool Result = CheckEquivalentExceptionSpec(PDiag(DiagID),
|
||||
PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc);
|
||||
bool Result = CheckEquivalentExceptionSpecImpl(
|
||||
*this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
|
||||
Old, OldLoc, New, NewLoc);
|
||||
|
||||
// In Microsoft mode, mismatching exception specifications just cause a warning.
|
||||
if (getLangOpts().MicrosoftExt)
|
||||
@ -413,30 +431,23 @@ bool Sema::CheckEquivalentExceptionSpec(
|
||||
/// \return \c false if the exception specifications match, \c true if there is
|
||||
/// a problem. If \c true is returned, either a diagnostic has already been
|
||||
/// produced or \c *MissingExceptionSpecification is set to \c true.
|
||||
bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
const PartialDiagnostic &NoteID,
|
||||
const FunctionProtoType *Old,
|
||||
SourceLocation OldLoc,
|
||||
const FunctionProtoType *New,
|
||||
SourceLocation NewLoc,
|
||||
bool *MissingExceptionSpecification,
|
||||
bool*MissingEmptyExceptionSpecification,
|
||||
bool AllowNoexceptAllMatchWithNoSpec,
|
||||
bool IsOperatorNew) {
|
||||
// Just completely ignore this under -fno-exceptions.
|
||||
if (!getLangOpts().CXXExceptions)
|
||||
return false;
|
||||
|
||||
static bool CheckEquivalentExceptionSpecImpl(
|
||||
Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc,
|
||||
bool *MissingExceptionSpecification,
|
||||
bool *MissingEmptyExceptionSpecification,
|
||||
bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) {
|
||||
if (MissingExceptionSpecification)
|
||||
*MissingExceptionSpecification = false;
|
||||
|
||||
if (MissingEmptyExceptionSpecification)
|
||||
*MissingEmptyExceptionSpecification = false;
|
||||
|
||||
Old = ResolveExceptionSpec(NewLoc, Old);
|
||||
Old = S.ResolveExceptionSpec(NewLoc, Old);
|
||||
if (!Old)
|
||||
return false;
|
||||
New = ResolveExceptionSpec(NewLoc, New);
|
||||
New = S.ResolveExceptionSpec(NewLoc, New);
|
||||
if (!New)
|
||||
return false;
|
||||
|
||||
@ -470,8 +481,8 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
if (OldEST == EST_None && NewEST == EST_None)
|
||||
return false;
|
||||
|
||||
FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context);
|
||||
FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context);
|
||||
FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(S.Context);
|
||||
FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(S.Context);
|
||||
if (OldNR == FunctionProtoType::NR_BadNoexcept ||
|
||||
NewNR == FunctionProtoType::NR_BadNoexcept)
|
||||
return false;
|
||||
@ -486,9 +497,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
if (OldNR != NewNR &&
|
||||
OldNR != FunctionProtoType::NR_NoNoexcept &&
|
||||
NewNR != FunctionProtoType::NR_NoNoexcept) {
|
||||
Diag(NewLoc, DiagID);
|
||||
S.Diag(NewLoc, DiagID);
|
||||
if (NoteID.getDiagID() != 0 && OldLoc.isValid())
|
||||
Diag(OldLoc, NoteID);
|
||||
S.Diag(OldLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -526,7 +537,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
// As a special compatibility feature, under C++0x we accept no spec and
|
||||
// throw(std::bad_alloc) as equivalent for operator new and operator new[].
|
||||
// This is because the implicit declaration changed, but old code would break.
|
||||
if (getLangOpts().CPlusPlus11 && IsOperatorNew) {
|
||||
if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) {
|
||||
const FunctionProtoType *WithExceptions = nullptr;
|
||||
if (OldEST == EST_None && NewEST == EST_Dynamic)
|
||||
WithExceptions = New;
|
||||
@ -567,9 +578,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
return true;
|
||||
}
|
||||
|
||||
Diag(NewLoc, DiagID);
|
||||
S.Diag(NewLoc, DiagID);
|
||||
if (NoteID.getDiagID() != 0 && OldLoc.isValid())
|
||||
Diag(OldLoc, NoteID);
|
||||
S.Diag(OldLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -581,11 +592,11 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
// to the second.
|
||||
llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
|
||||
for (const auto &I : Old->exceptions())
|
||||
OldTypes.insert(Context.getCanonicalType(I).getUnqualifiedType());
|
||||
OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType());
|
||||
|
||||
for (const auto &I : New->exceptions()) {
|
||||
CanQualType TypePtr = Context.getCanonicalType(I).getUnqualifiedType();
|
||||
if(OldTypes.count(TypePtr))
|
||||
CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType();
|
||||
if (OldTypes.count(TypePtr))
|
||||
NewTypes.insert(TypePtr);
|
||||
else
|
||||
Success = false;
|
||||
@ -596,12 +607,24 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
if (Success) {
|
||||
return false;
|
||||
}
|
||||
Diag(NewLoc, DiagID);
|
||||
S.Diag(NewLoc, DiagID);
|
||||
if (NoteID.getDiagID() != 0 && OldLoc.isValid())
|
||||
Diag(OldLoc, NoteID);
|
||||
S.Diag(OldLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
const PartialDiagnostic &NoteID,
|
||||
const FunctionProtoType *Old,
|
||||
SourceLocation OldLoc,
|
||||
const FunctionProtoType *New,
|
||||
SourceLocation NewLoc) {
|
||||
if (!getLangOpts().CXXExceptions)
|
||||
return false;
|
||||
return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc,
|
||||
New, NewLoc);
|
||||
}
|
||||
|
||||
/// CheckExceptionSpecSubset - Check whether the second function type's
|
||||
/// exception specification is a subset (or equivalent) of the first function
|
||||
/// type. This is used by override and pointer assignment checks.
|
||||
|
@ -1,4 +1,5 @@
|
||||
// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify -std=c++1z %s
|
||||
// expected-no-diagnostics
|
||||
#include <malloc.h>
|
||||
|
||||
|
@ -10,10 +10,9 @@ template<typename T> void redecl1() noexcept(noexcept(T())) {} // expected-error
|
||||
template<bool A, bool B> void redecl2() noexcept(A); // expected-note {{previous}}
|
||||
template<bool A, bool B> void redecl2() noexcept(B); // expected-error {{conflicting types}}
|
||||
|
||||
// These have the same canonical type.
|
||||
// FIXME: It's not clear whether this is supposed to be valid.
|
||||
template<typename A, typename B> void redecl3() throw(A);
|
||||
template<typename A, typename B> void redecl3() throw(B);
|
||||
// These have the same canonical type, but are still different.
|
||||
template<typename A, typename B> void redecl3() throw(A); // expected-note {{previous}}
|
||||
template<typename A, typename B> void redecl3() throw(B); // expected-error {{does not match previous}}
|
||||
|
||||
typedef int I;
|
||||
template<bool B> void redecl4(I) noexcept(B);
|
||||
|
Loading…
x
Reference in New Issue
Block a user