aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaDeclCXX.cpp8
-rw-r--r--lib/Sema/SemaExprCXX.cpp40
-rw-r--r--lib/Sema/SemaType.cpp9
-rw-r--r--test/SemaCXX/exception-spec.cpp14
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