//===--- 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 "clang/Sema/SemaInternal.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.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();
else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
T = MPTy->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.
///
/// \param[in,out] T The exception type. This will be decayed to a pointer type
/// when the input is an array or a function type.
bool Sema::CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range) {
// C++11 [except.spec]p2:
// A type cv T, "array of T", or "function returning T" denoted
// in an exception-specification is adjusted to type T, "pointer to T", or
// "pointer to function returning T", respectively.
//
// We also apply this rule in C++98.
if (T->isArrayType())
T = Context.getArrayDecayedType(T);
else if (T->isFunctionType())
T = Context.getPointerType(T);
int Kind = 0;
QualType PointeeT = T;
if (const PointerType *PT = T->getAs<PointerType>()) {
PointeeT = PT->getPointeeType();
Kind = 1;
// cv void* is explicitly permitted, despite being a pointer to an
// incomplete type.
if (PointeeT->isVoidType())
return false;
} else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
PointeeT = RT->getPointeeType();
Kind = 2;
if (RT->isRValueReferenceType()) {
// C++11 [except.spec]p2:
// A type denoted in an exception-specification shall not denote [...]
// an rvalue reference type.
Diag(Range.getBegin(), diag::err_rref_in_exception_spec)
<< T << Range;
return true;
}
}
// C++11 [except.spec]p2:
// A type denoted in an exception-specification shall not denote an
// incomplete type other than a class currently being defined [...].
// A type denoted in an exception-specification shall not denote a
// pointer or reference to an incomplete type, other than (cv) void* or a
// pointer or reference to a class currently being defined.
if (!(PointeeT->isRecordType() &&
PointeeT->getAs<RecordType>()->isBeingDefined()) &&
RequireCompleteType(Range.getBegin(), PointeeT,
diag::err_incomplete_in_exception_spec, Kind, Range))
return true;
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();
}
const FunctionProtoType *
Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *