forked from OSchip/llvm-project
Test exception spec compatibility on return type and parameters.
Along the way, use RequireCompleteType when testing exception spec types. Separate all the ugly spec stuff into its own file. llvm-svn: 83764
This commit is contained in:
parent
b8edf2a4dd
commit
4915e63d3b
|
@ -365,6 +365,10 @@ def err_override_exception_spec : Error<
|
|||
"base version">;
|
||||
def err_incompatible_exception_specs : Error<
|
||||
"target exception specification is not superset of source">;
|
||||
def err_return_type_specs_differ : Error<
|
||||
"exception specifications of return types differ">;
|
||||
def err_arg_type_specs_differ : Error<
|
||||
"exception specifications of argument types differ">;
|
||||
|
||||
// C++ access checking
|
||||
def err_class_redeclared_with_different_access : Error<
|
||||
|
|
|
@ -16,6 +16,7 @@ add_clang_library(clangSema
|
|||
SemaDeclAttr.cpp
|
||||
SemaDeclCXX.cpp
|
||||
SemaDeclObjC.cpp
|
||||
SemaExceptionSpec.cpp
|
||||
SemaExpr.cpp
|
||||
SemaExprCXX.cpp
|
||||
SemaExprObjC.cpp
|
||||
|
|
|
@ -482,9 +482,15 @@ public:
|
|||
bool CheckEquivalentExceptionSpec(
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc);
|
||||
bool CheckEquivalentExceptionSpec(unsigned DiagID, unsigned NoteID,
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc);
|
||||
bool CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID,
|
||||
const FunctionProtoType *Superset, SourceLocation SuperLoc,
|
||||
const FunctionProtoType *Subset, SourceLocation SubLoc);
|
||||
bool CheckParamExceptionSpec(unsigned NoteID,
|
||||
const FunctionProtoType *Target, SourceLocation TargetLoc,
|
||||
const FunctionProtoType *Source, SourceLocation SourceLoc);
|
||||
|
||||
QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
|
||||
|
||||
|
|
|
@ -4629,16 +4629,6 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
|
||||
const CXXMethodDecl *Old) {
|
||||
return CheckExceptionSpecSubset(diag::err_override_exception_spec,
|
||||
diag::note_overridden_virtual_function,
|
||||
Old->getType()->getAs<FunctionProtoType>(),
|
||||
Old->getLocation(),
|
||||
New->getType()->getAs<FunctionProtoType>(),
|
||||
New->getLocation());
|
||||
}
|
||||
|
||||
/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an
|
||||
/// initializer for the declaration 'Dcl'.
|
||||
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides Sema routines for C++ exception specification testing.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Sema.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
static const FunctionProtoType *GetUnderlyingFunction(QualType T)
|
||||
{
|
||||
if (const PointerType *PtrTy = T->getAs<PointerType>())
|
||||
T = PtrTy->getPointeeType();
|
||||
else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
|
||||
T = RefTy->getPointeeType();
|
||||
return T->getAs<FunctionProtoType>();
|
||||
}
|
||||
|
||||
/// CheckSpecifiedExceptionType - Check if the given type is valid in an
|
||||
/// exception specification. Incomplete types, or pointers to incomplete types
|
||||
/// other than void are not allowed.
|
||||
bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
|
||||
// FIXME: This may not correctly work with the fix for core issue 437,
|
||||
// where a class's own type is considered complete within its body. But
|
||||
// perhaps RequireCompleteType itself should contain this logic?
|
||||
|
||||
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
|
||||
// an incomplete type.
|
||||
// FIXME: This isn't right. This will supress diagnostics from template
|
||||
// instantiation and then simply emit the invalid type diagnostic.
|
||||
if (RequireCompleteType(Range.getBegin(), T, 0))
|
||||
return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
|
||||
<< Range << T << /*direct*/0;
|
||||
|
||||
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
|
||||
// an incomplete type a pointer or reference to an incomplete type, other
|
||||
// than (cv) void*.
|
||||
int kind;
|
||||
if (const PointerType* IT = T->getAs<PointerType>()) {
|
||||
T = IT->getPointeeType();
|
||||
kind = 1;
|
||||
} else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
|
||||
T = IT->getPointeeType();
|
||||
kind = 2;
|
||||
} else
|
||||
return false;
|
||||
|
||||
if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T, 0))
|
||||
return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
|
||||
<< Range << T << /*indirect*/kind;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
|
||||
/// to member to a function with an exception specification. This means that
|
||||
/// it is invalid to add another level of indirection.
|
||||
bool Sema::CheckDistantExceptionSpec(QualType T) {
|
||||
if (const PointerType *PT = T->getAs<PointerType>())
|
||||
T = PT->getPointeeType();
|
||||
else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
|
||||
T = PT->getPointeeType();
|
||||
else
|
||||
return false;
|
||||
|
||||
const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
|
||||
if (!FnT)
|
||||
return false;
|
||||
|
||||
return FnT->hasExceptionSpec();
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// 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(
|
||||
unsigned DiagID, unsigned NoteID,
|
||||
const FunctionProtoType *Old, SourceLocation OldLoc,
|
||||
const FunctionProtoType *New, SourceLocation NewLoc) {
|
||||
bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
|
||||
bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
|
||||
if (OldAny && NewAny)
|
||||
return false;
|
||||
if (OldAny || NewAny) {
|
||||
Diag(NewLoc, DiagID);
|
||||
if (NoteID != 0)
|
||||
Diag(OldLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Success = true;
|
||||
// Both have a definite exception spec. Collect the first set, then compare
|
||||
// to the second.
|
||||
llvm::SmallPtrSet<const Type*, 8> Types;
|
||||
for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
|
||||
E = Old->exception_end(); I != E; ++I)
|
||||
Types.insert(Context.getCanonicalType(*I).getTypePtr());
|
||||
|
||||
for (FunctionProtoType::exception_iterator I = New->exception_begin(),
|
||||
E = New->exception_end(); I != E && Success; ++I)
|
||||
Success = Types.erase(Context.getCanonicalType(*I).getTypePtr());
|
||||
|
||||
Success = Success && Types.empty();
|
||||
|
||||
if (Success) {
|
||||
return false;
|
||||
}
|
||||
Diag(NewLoc, DiagID);
|
||||
if (NoteID != 0)
|
||||
Diag(OldLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID,
|
||||
const FunctionProtoType *Superset, SourceLocation SuperLoc,
|
||||
const FunctionProtoType *Subset, SourceLocation SubLoc) {
|
||||
// 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 CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
|
||||
|
||||
// It does not. If the subset contains everything, we've failed.
|
||||
if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
|
||||
Diag(SubLoc, DiagID);
|
||||
if (NoteID != 0)
|
||||
Diag(SuperLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Neither contains everything. Do a proper comparison.
|
||||
for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
|
||||
SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
|
||||
// Take one type from the subset.
|
||||
QualType CanonicalSubT = Context.getCanonicalType(*SubI);
|
||||
bool SubIsPointer = false;
|
||||
if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
|
||||
CanonicalSubT = RefTy->getPointeeType();
|
||||
if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
|
||||
CanonicalSubT = PtrTy->getPointeeType();
|
||||
SubIsPointer = true;
|
||||
}
|
||||
bool SubIsClass = CanonicalSubT->isRecordType();
|
||||
CanonicalSubT = CanonicalSubT.getUnqualifiedType();
|
||||
|
||||
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
|
||||
/*DetectVirtual=*/false);
|
||||
|
||||
bool Contained = false;
|
||||
// Make sure it's in the superset.
|
||||
for (FunctionProtoType::exception_iterator SuperI =
|
||||
Superset->exception_begin(), SuperE = Superset->exception_end();
|
||||
SuperI != SuperE; ++SuperI) {
|
||||
QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
|
||||
// SubT must be SuperT or derived from it, or pointer or reference to
|
||||
// such types.
|
||||
if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
|
||||
CanonicalSuperT = RefTy->getPointeeType();
|
||||
if (SubIsPointer) {
|
||||
if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
|
||||
CanonicalSuperT = PtrTy->getPointeeType();
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CanonicalSuperT = CanonicalSuperT.getUnqualifiedType();
|
||||
// If the types are the same, move on to the next type in the subset.
|
||||
if (CanonicalSubT == CanonicalSuperT) {
|
||||
Contained = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise we need to check the inheritance.
|
||||
if (!SubIsClass || !CanonicalSuperT->isRecordType())
|
||||
continue;
|
||||
|
||||
Paths.clear();
|
||||
if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
|
||||
continue;
|
||||
|
||||
if (Paths.isAmbiguous(CanonicalSuperT))
|
||||
continue;
|
||||
|
||||
if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
|
||||
continue;
|
||||
|
||||
Contained = true;
|
||||
break;
|
||||
}
|
||||
if (!Contained) {
|
||||
Diag(SubLoc, DiagID);
|
||||
if (NoteID != 0)
|
||||
Diag(SuperLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// We've run half the gauntlet.
|
||||
return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
|
||||
}
|
||||
|
||||
static bool CheckSpecForTypesEquivalent(Sema &S,
|
||||
unsigned DiagID, unsigned NoteID,
|
||||
QualType Target, SourceLocation TargetLoc,
|
||||
QualType Source, SourceLocation SourceLoc)
|
||||
{
|
||||
const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
|
||||
if (!TFunc)
|
||||
return false;
|
||||
const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
|
||||
if (!SFunc)
|
||||
return false;
|
||||
|
||||
return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
|
||||
SFunc, SourceLoc);
|
||||
}
|
||||
|
||||
/// CheckParamExceptionSpec - Check if the parameter and return types of the
|
||||
/// two functions have equivalent exception specs. This is part of the
|
||||
/// assignment and override compatibility check. We do not check the parameters
|
||||
/// of parameter function pointers recursively, as no sane programmer would
|
||||
/// even be able to write such a function type.
|
||||
bool Sema::CheckParamExceptionSpec(unsigned NoteID,
|
||||
const FunctionProtoType *Target, SourceLocation TargetLoc,
|
||||
const FunctionProtoType *Source, SourceLocation SourceLoc)
|
||||
{
|
||||
if (CheckSpecForTypesEquivalent(*this, diag::err_return_type_specs_differ, 0,
|
||||
Target->getResultType(), TargetLoc,
|
||||
Source->getResultType(), SourceLoc))
|
||||
return true;
|
||||
|
||||
// We shouldn't even testing this unless the arguments are otherwise
|
||||
// compatible.
|
||||
assert(Target->getNumArgs() == Source->getNumArgs() &&
|
||||
"Functions have different argument counts.");
|
||||
for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
|
||||
if (CheckSpecForTypesEquivalent(*this, diag::err_arg_type_specs_differ, 0,
|
||||
Target->getArgType(i), TargetLoc,
|
||||
Source->getArgType(i), SourceLoc))
|
||||
return true;
|
||||
}
|
||||
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.
|
||||
const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
|
||||
if (!ToFunc)
|
||||
return false;
|
||||
|
||||
// SourceType must be a function or function pointer.
|
||||
const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
|
||||
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());
|
||||
}
|
||||
|
||||
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
|
||||
const CXXMethodDecl *Old) {
|
||||
return CheckExceptionSpecSubset(diag::err_override_exception_spec,
|
||||
diag::note_overridden_virtual_function,
|
||||
Old->getType()->getAs<FunctionProtoType>(),
|
||||
Old->getLocation(),
|
||||
New->getType()->getAs<FunctionProtoType>(),
|
||||
New->getLocation());
|
||||
}
|
||||
|
||||
} // end namespace clang
|
|
@ -1275,38 +1275,6 @@ 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,
|
||||
|
|
|
@ -1413,190 +1413,6 @@ void LocInfoType::getAsStringInternal(std::string &Str,
|
|||
" GetTypeFromParser");
|
||||
}
|
||||
|
||||
/// CheckSpecifiedExceptionType - Check if the given type is valid in an
|
||||
/// exception specification. Incomplete types, or pointers to incomplete types
|
||||
/// other than void are not allowed.
|
||||
bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
|
||||
// FIXME: This may not correctly work with the fix for core issue 437,
|
||||
// where a class's own type is considered complete within its body.
|
||||
|
||||
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
|
||||
// an incomplete type.
|
||||
if (T->isIncompleteType())
|
||||
return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
|
||||
<< Range << T << /*direct*/0;
|
||||
|
||||
// C++ 15.4p2: A type denoted in an exception-specification shall not denote
|
||||
// an incomplete type a pointer or reference to an incomplete type, other
|
||||
// than (cv) void*.
|
||||
int kind;
|
||||
if (const PointerType* IT = T->getAs<PointerType>()) {
|
||||
T = IT->getPointeeType();
|
||||
kind = 1;
|
||||
} else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
|
||||
T = IT->getPointeeType();
|
||||
kind = 2;
|
||||
} else
|
||||
return false;
|
||||
|
||||
if (T->isIncompleteType() && !T->isVoidType())
|
||||
return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec)
|
||||
<< Range << T << /*indirect*/kind;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
|
||||
/// to member to a function with an exception specification. This means that
|
||||
/// it is invalid to add another level of indirection.
|
||||
bool Sema::CheckDistantExceptionSpec(QualType T) {
|
||||
if (const PointerType *PT = T->getAs<PointerType>())
|
||||
T = PT->getPointeeType();
|
||||
else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
|
||||
T = PT->getPointeeType();
|
||||
else
|
||||
return false;
|
||||
|
||||
const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
|
||||
if (!FnT)
|
||||
return false;
|
||||
|
||||
return FnT->hasExceptionSpec();
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
|
||||
bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
|
||||
if (OldAny && NewAny)
|
||||
return false;
|
||||
if (OldAny || NewAny) {
|
||||
Diag(NewLoc, diag::err_mismatched_exception_spec);
|
||||
Diag(OldLoc, diag::note_previous_declaration);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Success = true;
|
||||
// Both have a definite exception spec. Collect the first set, then compare
|
||||
// to the second.
|
||||
llvm::SmallPtrSet<const Type*, 8> Types;
|
||||
for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
|
||||
E = Old->exception_end(); I != E; ++I)
|
||||
Types.insert(Context.getCanonicalType(*I).getTypePtr());
|
||||
|
||||
for (FunctionProtoType::exception_iterator I = New->exception_begin(),
|
||||
E = New->exception_end(); I != E && Success; ++I)
|
||||
Success = Types.erase(Context.getCanonicalType(*I).getTypePtr());
|
||||
|
||||
Success = Success && Types.empty();
|
||||
|
||||
if (Success) {
|
||||
return false;
|
||||
}
|
||||
Diag(NewLoc, diag::err_mismatched_exception_spec);
|
||||
Diag(OldLoc, diag::note_previous_declaration);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID,
|
||||
const FunctionProtoType *Superset, SourceLocation SuperLoc,
|
||||
const FunctionProtoType *Subset, SourceLocation SubLoc) {
|
||||
// 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);
|
||||
if (NoteID != 0)
|
||||
Diag(SuperLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Neither contains everything. Do a proper comparison.
|
||||
for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
|
||||
SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
|
||||
// Take one type from the subset.
|
||||
QualType CanonicalSubT = Context.getCanonicalType(*SubI);
|
||||
bool SubIsPointer = false;
|
||||
if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
|
||||
CanonicalSubT = RefTy->getPointeeType();
|
||||
if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
|
||||
CanonicalSubT = PtrTy->getPointeeType();
|
||||
SubIsPointer = true;
|
||||
}
|
||||
bool SubIsClass = CanonicalSubT->isRecordType();
|
||||
CanonicalSubT = CanonicalSubT.getUnqualifiedType();
|
||||
|
||||
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
|
||||
/*DetectVirtual=*/false);
|
||||
|
||||
bool Contained = false;
|
||||
// Make sure it's in the superset.
|
||||
for (FunctionProtoType::exception_iterator SuperI =
|
||||
Superset->exception_begin(), SuperE = Superset->exception_end();
|
||||
SuperI != SuperE; ++SuperI) {
|
||||
QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
|
||||
// SubT must be SuperT or derived from it, or pointer or reference to
|
||||
// such types.
|
||||
if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
|
||||
CanonicalSuperT = RefTy->getPointeeType();
|
||||
if (SubIsPointer) {
|
||||
if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
|
||||
CanonicalSuperT = PtrTy->getPointeeType();
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CanonicalSuperT = CanonicalSuperT.getUnqualifiedType();
|
||||
// If the types are the same, move on to the next type in the subset.
|
||||
if (CanonicalSubT == CanonicalSuperT) {
|
||||
Contained = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise we need to check the inheritance.
|
||||
if (!SubIsClass || !CanonicalSuperT->isRecordType())
|
||||
continue;
|
||||
|
||||
Paths.clear();
|
||||
if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
|
||||
continue;
|
||||
|
||||
if (Paths.isAmbiguous(CanonicalSuperT))
|
||||
continue;
|
||||
|
||||
if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
|
||||
continue;
|
||||
|
||||
Contained = true;
|
||||
break;
|
||||
}
|
||||
if (!Contained) {
|
||||
Diag(SubLoc, DiagID);
|
||||
if (NoteID != 0)
|
||||
Diag(SuperLoc, NoteID);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// We've run the gauntlet.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
|
||||
/// declarator
|
||||
QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
|
||||
|
|
|
@ -156,9 +156,9 @@ void fnptrs()
|
|||
|
||||
// return types and arguments must match exactly, no inheritance allowed
|
||||
void (*(*t7)())() throw(B1) = &s8; // valid
|
||||
void (*(*t8)())() throw(A) = &s8; // invalid
|
||||
void (*(*t9)())() throw(D) = &s8; // invalid
|
||||
void (*(*t8)())() throw(A) = &s8; // expected-error {{return types differ}} expected-error {{incompatible type}}
|
||||
void (*(*t9)())() throw(D) = &s8; // expected-error {{return types differ}} expected-error {{incompatible type}}
|
||||
void (*t10)(void (*)() throw(B1)) = &s9; // valid expected-warning{{disambiguated}}
|
||||
void (*t11)(void (*)() throw(A)) = &s9; // invalid expected-warning{{disambiguated}}
|
||||
void (*t12)(void (*)() throw(D)) = &s9; // invalid expected-warning{{disambiguated}}
|
||||
void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} expected-error {{incompatible type}} expected-warning{{disambiguated}}
|
||||
void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} expected-error {{incompatible type}} expected-warning{{disambiguated}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue