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<
bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
+ bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType);
+
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const char *Flavor,
bool AllowExplicit = false,
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);
}
}
cast<CXXMethodDecl>(Best->Function),
Owned(Init));
Init = InitConversion.takeAs<Expr>();
-
+
+ if (CheckExceptionSpecCompatibility(Init, T1))
+ return true;
ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion,
/*isLvalue=*/true);
}
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;
// 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:
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
if (CheckMemberPointerConversion(From, ToType, Kind))
return true;
+ if (CheckExceptionSpecCompatibility(From, ToType))
+ return true;
ImpCastExprToType(From, ToType, Kind);
break;
}
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,
// 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;
// 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;
}
}
if (!Contained) {
Diag(SubLoc, DiagID);
- Diag(SuperLoc, NoteID);
+ if (NoteID != 0)
+ Diag(SuperLoc, NoteID);
return true;
}
}
{
// 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