diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 40 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 9 | ||||
-rw-r--r-- | test/SemaCXX/exception-spec.cpp | 14 |
6 files changed, 64 insertions, 11 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3b4af8e9b5..f3d69c0035 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -363,6 +363,8 @@ def err_mismatched_exception_spec : Error< def err_override_exception_spec : Error< "exception specification of overriding function is more lax than " "base version">; +def err_incompatible_exception_specs : Error< + "target exception specification is not superset of source">; // C++ access checking def err_class_redeclared_with_different_access : Error< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 9d35f3dd3f..56eb24edcf 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3519,6 +3519,8 @@ public: bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); + bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); + bool PerformImplicitConversion(Expr *&From, QualType ToType, const char *Flavor, bool AllowExplicit = false, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index fb0e144036..9a90be4189 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3630,6 +3630,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, CastExpr::CastKind CK = CastExpr::CK_NoOp; if (DerivedToBase) CK = CastExpr::CK_DerivedToBase; + else if(CheckExceptionSpecCompatibility(Init, T1)) + return true; ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true); } } @@ -3703,7 +3705,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, cast<CXXMethodDecl>(Best->Function), Owned(Init)); Init = InitConversion.takeAs<Expr>(); - + + if (CheckExceptionSpecCompatibility(Init, T1)) + return true; ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion, /*isLvalue=*/true); } @@ -3792,6 +3796,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, CastExpr::CastKind CK = CastExpr::CK_NoOp; if (DerivedToBase) CK = CastExpr::CK_DerivedToBase; + else if(CheckExceptionSpecCompatibility(Init, T1)) + return true; ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false); } return false; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d746237563..eb0b6e1eff 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1197,7 +1197,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Perform the second implicit conversion switch (SCS.Second) { case ICK_Identity: - // Nothing to do. + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; + // Nothing else to do. break; case ICK_Integral_Promotion: @@ -1235,6 +1239,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, CastExpr::CastKind Kind = CastExpr::CK_Unknown; if (CheckMemberPointerConversion(From, ToType, Kind)) return true; + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; ImpCastExprToType(From, ToType, Kind); break; } @@ -1269,6 +1275,38 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return false; } +bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) +{ + // First we check for applicability. + // Target type must be a function, function pointer or function reference. + if (const PointerType *PtrTy = ToType->getAs<PointerType>()) + ToType = PtrTy->getPointeeType(); + else if (const ReferenceType *RefTy = ToType->getAs<ReferenceType>()) + ToType = RefTy->getPointeeType(); + + const FunctionProtoType *ToFunc = ToType->getAs<FunctionProtoType>(); + if (!ToFunc) + return false; + + // SourceType must be a function or function pointer. + // References are treated as functions. + QualType FromType = From->getType(); + if (const PointerType *PtrTy = FromType->getAs<PointerType>()) + FromType = PtrTy->getPointeeType(); + + const FunctionProtoType *FromFunc = FromType->getAs<FunctionProtoType>(); + if (!FromFunc) + return false; + + // Now we've got the correct types on both sides, check their compatibility. + // 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(), + FromFunc, SourceLocation()); +} + Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT, SourceLocation KWLoc, SourceLocation LParen, diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 6a5db5f2ad..5c7bbd0441 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1512,6 +1512,9 @@ bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID, // FIXME: As usual, we could be more specific in our error messages, but // that better waits until we've got types with source locations. + if (!SubLoc.isValid()) + SubLoc = SuperLoc; + // If superset contains everything, we're done. if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec()) return false; @@ -1519,7 +1522,8 @@ bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID, // It does not. If the subset contains everything, we've failed. if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) { Diag(SubLoc, DiagID); - Diag(SuperLoc, NoteID); + if (NoteID != 0) + Diag(SuperLoc, NoteID); return true; } @@ -1584,7 +1588,8 @@ bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID, } if (!Contained) { Diag(SubLoc, DiagID); - Diag(SuperLoc, NoteID); + if (NoteID != 0) + Diag(SuperLoc, NoteID); return true; } } diff --git a/test/SemaCXX/exception-spec.cpp b/test/SemaCXX/exception-spec.cpp index 9d656ad212..cb4cbf4a70 100644 --- a/test/SemaCXX/exception-spec.cpp +++ b/test/SemaCXX/exception-spec.cpp @@ -134,25 +134,25 @@ void fnptrs() { // Assignment and initialization of function pointers. void (*t1)() throw() = &s1; // valid - t1 = &s2; // invalid - t1 = &s3; // invalid - void (&t2)() throw() = s2; // invalid + t1 = &s2; // expected-error {{not superset}} expected-error {{incompatible type}} + t1 = &s3; // expected-error {{not superset}} expected-error {{incompatible type}} + void (&t2)() throw() = s2; // expected-error {{not superset}} void (*t3)() throw(int) = &s2; // valid void (*t4)() throw(A) = &s1; // valid t4 = &s3; // valid t4 = &s4; // valid - t4 = &s5; // invalid + t4 = &s5; // expected-error {{not superset}} expected-error {{incompatible type}} void (*t5)() = &s1; // valid t5 = &s2; // valid t5 = &s6; // valid t5 = &s7; // valid - t1 = t3; // invalid + t1 = t3; // expected-error {{not superset}} expected-error {{incompatible type}} t3 = t1; // valid void (*t6)() throw(B1); - t6 = t4; // invalid + t6 = t4; // expected-error {{not superset}} expected-error {{incompatible type}} t4 = t6; // valid t5 = t1; // valid - t1 = t5; // invalid + t1 = t5; // expected-error {{not superset}} expected-error {{incompatible type}} // return types and arguments must match exactly, no inheritance allowed void (*(*t7)())() throw(B1) = &s8; // valid |