Sema: Properly initialize the thrown exception object

We would create the exception object with the wrong qualifiers, ensuring
that the wrong copy constructor would get called.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@231049 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Majnemer 2015-03-03 01:50:05 +00:00
Родитель f12d91a4ba
Коммит c69762c6e8
4 изменённых файлов: 34 добавлений и 21 удалений

Просмотреть файл

@ -1936,6 +1936,8 @@ public:
/// cv-qualifiers.
QualType getSignatureParameterType(QualType T) const;
QualType getExceptionObjectType(QualType T) const;
/// \brief Return the properly qualified result of decaying the specified
/// array type to a pointer.
///

Просмотреть файл

@ -4338,6 +4338,19 @@ QualType ASTContext::getSignatureParameterType(QualType T) const {
return T.getUnqualifiedType();
}
QualType ASTContext::getExceptionObjectType(QualType T) const {
// C++ [except.throw]p3:
// A throw-expression initializes a temporary object, called the exception
// object, the type of which is determined by removing any top-level
// cv-qualifiers from the static type of the operand of throw and adjusting
// the type from "array of T" or "function returning T" to "pointer to T"
// or "pointer to function returning T", [...]
T = getVariableArrayDecayedType(T);
if (T->isArrayType() || T->isFunctionType())
T = getDecayedType(T);
return T.getUnqualifiedType();
}
/// getArrayDecayedType - Return the properly qualified result of decaying the
/// specified array type to a pointer. This operation is non-trivial when
/// handling typedefs etc. The canonical type of "T" must be an array type,

Просмотреть файл

@ -660,24 +660,10 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
/// CheckCXXThrowOperand - Validate the operand of a throw.
ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
bool IsThrownVarInScope) {
// C++ [except.throw]p3:
// A throw-expression initializes a temporary object, called the exception
// object, the type of which is determined by removing any top-level
// cv-qualifiers from the static type of the operand of throw and adjusting
// the type from "array of T" or "function returning T" to "pointer to T"
// or "pointer to function returning T", [...]
if (E->getType().hasQualifiers())
E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp,
E->getValueKind()).get();
ExprResult Res = DefaultFunctionArrayConversion(E);
if (Res.isInvalid())
return ExprError();
E = Res.get();
QualType ExceptionObjectTy = Context.getExceptionObjectType(E->getType());
// If the type of the exception would be an incomplete type or a pointer
// to an incomplete type other than (cv) void the program is ill-formed.
QualType Ty = E->getType();
QualType Ty = ExceptionObjectTy;
bool isPointer = false;
if (const PointerType* Ptr = Ty->getAs<PointerType>()) {
Ty = Ptr->getPointeeType();
@ -690,7 +676,7 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
E->getSourceRange()))
return ExprError();
if (RequireNonAbstractType(ThrowLoc, E->getType(),
if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy,
diag::err_throw_abstract_type, E))
return ExprError();
}
@ -714,11 +700,10 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
InitializedEntity Entity =
InitializedEntity::InitializeException(ThrowLoc, E->getType(),
InitializedEntity::InitializeException(ThrowLoc, ExceptionObjectTy,
/*NRVO=*/NRVOVariable != nullptr);
Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable,
QualType(), E,
IsThrownVarInScope);
ExprResult Res = PerformMoveOrCopyInitialization(
Entity, NRVOVariable, QualType(), E, IsThrownVarInScope);
if (Res.isInvalid())
return ExprError();
E = Res.get();

Просмотреть файл

@ -145,3 +145,16 @@ namespace Decay {
}
void rval_ref() throw (int &&); // expected-error {{rvalue reference type 'int &&' is not allowed in exception specification}} expected-warning {{C++11}}
namespace ConstVolatile {
struct S {
S() {} // expected-note{{candidate constructor not viable}}
S(const S &s); // expected-note{{candidate constructor not viable}}
};
typedef const volatile S CVS;
void f() {
throw CVS(); // expected-error{{no matching constructor for initialization}}
}
}