mirror of https://github.com/microsoft/clang.git
Implement DR1330 in C++11 mode, to support libstdc++4.7 which uses it.
We have a new flavor of exception specification, EST_Uninstantiated. A function type with this exception specification carries a pointer to a FunctionDecl, and the exception specification for that FunctionDecl is instantiated (if needed) and used in the place of the function type's exception specification. When a function template declaration with a non-trivial exception specification is instantiated, the specialization's exception specification is set to this new 'uninstantiated' kind rather than being instantiated immediately. Expr::CanThrow has migrated onto Sema, so it can instantiate exception specs on-demand. Also, any odr-use of a function triggers the instantiation of its exception specification (the exception specification could be needed by IRGen). In passing, fix two places where a DeclRefExpr was created but the corresponding function was not actually marked odr-used. We used to get away with this, but don't any more. Also fix a bug where instantiating an exception specification which refers to function parameters resulted in a crash. We still have the same bug in default arguments, which I'll be looking into next. This, plus a tiny patch to fix libstdc++'s common_type, is enough for clang to parse (and, in very limited testing, support) all of libstdc++4.7's standard headers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154886 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7fea7c81c0
commit
e6975e9b09
|
@ -581,16 +581,6 @@ public:
|
|||
/// member expression.
|
||||
static QualType findBoundMemberType(const Expr *expr);
|
||||
|
||||
/// \brief Result type of CanThrow().
|
||||
enum CanThrowResult {
|
||||
CT_Cannot,
|
||||
CT_Dependent,
|
||||
CT_Can
|
||||
};
|
||||
/// \brief Test if this expression, if evaluated, might throw, according to
|
||||
/// the rules of C++ [expr.unary.noexcept].
|
||||
CanThrowResult CanThrow(ASTContext &C) const;
|
||||
|
||||
/// IgnoreImpCasts - Skip past any implicit casts which might
|
||||
/// surround this expression. Only skips ImplicitCastExprs.
|
||||
Expr *IgnoreImpCasts() LLVM_READONLY;
|
||||
|
|
|
@ -79,6 +79,7 @@ namespace clang {
|
|||
class CXXRecordDecl;
|
||||
class EnumDecl;
|
||||
class FieldDecl;
|
||||
class FunctionDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCProtocolDecl;
|
||||
class ObjCMethodDecl;
|
||||
|
@ -2700,7 +2701,8 @@ public:
|
|||
ExtProtoInfo() :
|
||||
Variadic(false), HasTrailingReturn(false), TypeQuals(0),
|
||||
ExceptionSpecType(EST_None), RefQualifier(RQ_None),
|
||||
NumExceptions(0), Exceptions(0), NoexceptExpr(0), ConsumedArguments(0) {}
|
||||
NumExceptions(0), Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0),
|
||||
ConsumedArguments(0) {}
|
||||
|
||||
FunctionType::ExtInfo ExtInfo;
|
||||
bool Variadic : 1;
|
||||
|
@ -2711,6 +2713,7 @@ public:
|
|||
unsigned NumExceptions;
|
||||
const QualType *Exceptions;
|
||||
Expr *NoexceptExpr;
|
||||
FunctionDecl *ExceptionSpecDecl;
|
||||
const bool *ConsumedArguments;
|
||||
};
|
||||
|
||||
|
@ -2756,6 +2759,10 @@ private:
|
|||
// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
|
||||
// to the expression in the noexcept() specifier.
|
||||
|
||||
// ExceptionSpecDecl - Instead of Exceptions, there may be a single
|
||||
// FunctionDecl* pointing to the function which should be used to resolve
|
||||
// this function type's exception specification.
|
||||
|
||||
// ConsumedArgs - A variable size array, following Exceptions
|
||||
// and of length NumArgs, holding flags indicating which arguments
|
||||
// are consumed. This only appears if HasAnyConsumedArgs is true.
|
||||
|
@ -2795,6 +2802,8 @@ public:
|
|||
EPI.Exceptions = exception_begin();
|
||||
} else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
|
||||
EPI.NoexceptExpr = getNoexceptExpr();
|
||||
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
||||
EPI.ExceptionSpecDecl = getExceptionSpecDecl();
|
||||
}
|
||||
if (hasAnyConsumedArgs())
|
||||
EPI.ConsumedArguments = getConsumedArgsBuffer();
|
||||
|
@ -2838,9 +2847,14 @@ public:
|
|||
// NoexceptExpr sits where the arguments end.
|
||||
return *reinterpret_cast<Expr *const *>(arg_type_end());
|
||||
}
|
||||
FunctionDecl *getExceptionSpecDecl() const {
|
||||
if (getExceptionSpecType() != EST_Uninstantiated)
|
||||
return 0;
|
||||
return *reinterpret_cast<FunctionDecl * const *>(arg_type_end());
|
||||
}
|
||||
bool isNothrow(ASTContext &Ctx) const {
|
||||
ExceptionSpecificationType EST = getExceptionSpecType();
|
||||
assert(EST != EST_Delayed);
|
||||
assert(EST != EST_Delayed && EST != EST_Uninstantiated);
|
||||
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
|
||||
return true;
|
||||
if (EST != EST_ComputedNoexcept)
|
||||
|
|
|
@ -2583,6 +2583,8 @@ def note_template_enum_def_here : Note<
|
|||
"in instantiation of enumeration %q0 requested here">;
|
||||
def note_template_type_alias_instantiation_here : Note<
|
||||
"in instantiation of template type alias %0 requested here">;
|
||||
def note_template_exception_spec_instantiation_here : Note<
|
||||
"in instantiation of exception specification for %0 requested here">;
|
||||
|
||||
def note_default_arg_instantiation_here : Note<
|
||||
"in instantiation of default argument for '%0' required here">;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
/// \brief The various types of exception specifications that exist in C++0x.
|
||||
/// \brief The various types of exception specifications that exist in C++11.
|
||||
enum ExceptionSpecificationType {
|
||||
EST_None, ///< no exception specification
|
||||
EST_DynamicNone, ///< throw()
|
||||
|
@ -24,7 +24,8 @@ enum ExceptionSpecificationType {
|
|||
EST_MSAny, ///< Microsoft throw(...) extension
|
||||
EST_BasicNoexcept, ///< noexcept
|
||||
EST_ComputedNoexcept, ///< noexcept(expression)
|
||||
EST_Delayed ///< not known yet
|
||||
EST_Delayed, ///< not known yet
|
||||
EST_Uninstantiated ///< not instantiated yet
|
||||
};
|
||||
|
||||
inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
|
||||
|
@ -35,6 +36,19 @@ inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) {
|
|||
return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept;
|
||||
}
|
||||
|
||||
/// \brief Possible results from evaluation of a noexcept expression.
|
||||
enum CanThrowResult {
|
||||
CT_Cannot,
|
||||
CT_Dependent,
|
||||
CT_Can
|
||||
};
|
||||
|
||||
inline CanThrowResult mergeCanThrow(CanThrowResult CT1, CanThrowResult CT2) {
|
||||
// CanThrowResult constants are ordered so that the maximum is the correct
|
||||
// merge result.
|
||||
return CT1 > CT2 ? CT1 : CT2;
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H
|
||||
|
|
|
@ -907,6 +907,9 @@ public:
|
|||
DeclarationNameInfo GetNameForDeclarator(Declarator &D);
|
||||
DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name);
|
||||
static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = 0);
|
||||
CanThrowResult canThrow(const Expr *E);
|
||||
const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
|
||||
const FunctionProtoType *FPT);
|
||||
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
|
||||
bool CheckDistantExceptionSpec(QualType T);
|
||||
bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
|
||||
|
@ -3050,7 +3053,7 @@ public:
|
|||
/// implicitly-declared special member functions.
|
||||
class ImplicitExceptionSpecification {
|
||||
// Pointer to allow copying
|
||||
ASTContext *Context;
|
||||
Sema *Self;
|
||||
// We order exception specifications thus:
|
||||
// noexcept is the most restrictive, but is only used in C++0x.
|
||||
// throw() comes next.
|
||||
|
@ -3074,9 +3077,9 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
explicit ImplicitExceptionSpecification(ASTContext &Context)
|
||||
: Context(&Context), ComputedEST(EST_BasicNoexcept) {
|
||||
if (!Context.getLangOpts().CPlusPlus0x)
|
||||
explicit ImplicitExceptionSpecification(Sema &Self)
|
||||
: Self(&Self), ComputedEST(EST_BasicNoexcept) {
|
||||
if (!Self.Context.getLangOpts().CPlusPlus0x)
|
||||
ComputedEST = EST_DynamicNone;
|
||||
}
|
||||
|
||||
|
@ -3094,7 +3097,7 @@ public:
|
|||
const QualType *data() const { return Exceptions.data(); }
|
||||
|
||||
/// \brief Integrate another called method into the collected data.
|
||||
void CalledDecl(CXXMethodDecl *Method);
|
||||
void CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method);
|
||||
|
||||
/// \brief Integrate an invoked expression into the collected data.
|
||||
void CalledExpr(Expr *E);
|
||||
|
@ -5194,7 +5197,11 @@ public:
|
|||
|
||||
/// We are checking the validity of a default template argument that
|
||||
/// has been used when naming a template-id.
|
||||
DefaultTemplateArgumentChecking
|
||||
DefaultTemplateArgumentChecking,
|
||||
|
||||
/// We are instantiating the exception specification for a function
|
||||
/// template which was deferred until it was needed.
|
||||
ExceptionSpecInstantiation
|
||||
} Kind;
|
||||
|
||||
/// \brief The point of instantiation within the source code.
|
||||
|
@ -5242,6 +5249,7 @@ public:
|
|||
|
||||
switch (X.Kind) {
|
||||
case TemplateInstantiation:
|
||||
case ExceptionSpecInstantiation:
|
||||
return true;
|
||||
|
||||
case PriorTemplateArgumentSubstitution:
|
||||
|
@ -5359,6 +5367,13 @@ public:
|
|||
Decl *Entity,
|
||||
SourceRange InstantiationRange = SourceRange());
|
||||
|
||||
struct ExceptionSpecification {};
|
||||
/// \brief Note that we are instantiating an exception specification
|
||||
/// of a function template.
|
||||
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Entity, ExceptionSpecification,
|
||||
SourceRange InstantiationRange = SourceRange());
|
||||
|
||||
/// \brief Note that we are instantiating a default argument in a
|
||||
/// template-id.
|
||||
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
|
@ -5658,6 +5673,8 @@ public:
|
|||
TemplateArgumentListInfo &Result,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
||||
|
||||
void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Function);
|
||||
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Function,
|
||||
bool Recursive = false,
|
||||
|
|
|
@ -2194,6 +2194,8 @@ ASTContext::getFunctionType(QualType ResultTy,
|
|||
Size += EPI.NumExceptions * sizeof(QualType);
|
||||
else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
|
||||
Size += sizeof(Expr*);
|
||||
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
||||
Size += sizeof(FunctionDecl*);
|
||||
}
|
||||
if (EPI.ConsumedArguments)
|
||||
Size += NumArgs * sizeof(bool);
|
||||
|
|
325
lib/AST/Expr.cpp
325
lib/AST/Expr.cpp
|
@ -1996,331 +1996,6 @@ QualType Expr::findBoundMemberType(const Expr *expr) {
|
|||
return QualType();
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,
|
||||
Expr::CanThrowResult CT2) {
|
||||
// CanThrowResult constants are ordered so that the maximum is the correct
|
||||
// merge result.
|
||||
return CT1 > CT2 ? CT1 : CT2;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {
|
||||
Expr *E = const_cast<Expr*>(CE);
|
||||
Expr::CanThrowResult R = Expr::CT_Cannot;
|
||||
for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) {
|
||||
R = MergeCanThrow(R, cast<Expr>(*I)->CanThrow(C));
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,
|
||||
const Decl *D,
|
||||
bool NullThrows = true) {
|
||||
if (!D)
|
||||
return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
|
||||
|
||||
// See if we can get a function type from the decl somehow.
|
||||
const ValueDecl *VD = dyn_cast<ValueDecl>(D);
|
||||
if (!VD) // If we have no clue what we're calling, assume the worst.
|
||||
return Expr::CT_Can;
|
||||
|
||||
// As an extension, we assume that __attribute__((nothrow)) functions don't
|
||||
// throw.
|
||||
if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
QualType T = VD->getType();
|
||||
const FunctionProtoType *FT;
|
||||
if ((FT = T->getAs<FunctionProtoType>())) {
|
||||
} else if (const PointerType *PT = T->getAs<PointerType>())
|
||||
FT = PT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const ReferenceType *RT = T->getAs<ReferenceType>())
|
||||
FT = RT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
|
||||
FT = MT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
|
||||
FT = BT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
|
||||
if (!FT)
|
||||
return Expr::CT_Can;
|
||||
|
||||
if (FT->getExceptionSpecType() == EST_Delayed) {
|
||||
assert(isa<CXXConstructorDecl>(D) &&
|
||||
"only constructor exception specs can be unknown");
|
||||
Ctx.getDiagnostics().Report(E->getLocStart(),
|
||||
diag::err_exception_spec_unknown)
|
||||
<< E->getSourceRange();
|
||||
return Expr::CT_Can;
|
||||
}
|
||||
|
||||
return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
|
||||
if (DC->isTypeDependent())
|
||||
return Expr::CT_Dependent;
|
||||
|
||||
if (!DC->getTypeAsWritten()->isReferenceType())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
if (DC->getSubExpr()->isTypeDependent())
|
||||
return Expr::CT_Dependent;
|
||||
|
||||
return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanTypeidThrow(ASTContext &C,
|
||||
const CXXTypeidExpr *DC) {
|
||||
if (DC->isTypeOperand())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
Expr *Op = DC->getExprOperand();
|
||||
if (Op->isTypeDependent())
|
||||
return Expr::CT_Dependent;
|
||||
|
||||
const RecordType *RT = Op->getType()->getAs<RecordType>();
|
||||
if (!RT)
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
if (Op->Classify(C).isPRValue())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
return Expr::CT_Can;
|
||||
}
|
||||
|
||||
Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
|
||||
// C++ [expr.unary.noexcept]p3:
|
||||
// [Can throw] if in a potentially-evaluated context the expression would
|
||||
// contain:
|
||||
switch (getStmtClass()) {
|
||||
case CXXThrowExprClass:
|
||||
// - a potentially evaluated throw-expression
|
||||
return CT_Can;
|
||||
|
||||
case CXXDynamicCastExprClass: {
|
||||
// - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
|
||||
// where T is a reference type, that requires a run-time check
|
||||
CanThrowResult CT = CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this));
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case CXXTypeidExprClass:
|
||||
// - a potentially evaluated typeid expression applied to a glvalue
|
||||
// expression whose type is a polymorphic class type
|
||||
return CanTypeidThrow(C, cast<CXXTypeidExpr>(this));
|
||||
|
||||
// - a potentially evaluated call to a function, member function, function
|
||||
// pointer, or member function pointer that does not have a non-throwing
|
||||
// exception-specification
|
||||
case CallExprClass:
|
||||
case CXXMemberCallExprClass:
|
||||
case CXXOperatorCallExprClass:
|
||||
case UserDefinedLiteralClass: {
|
||||
const CallExpr *CE = cast<CallExpr>(this);
|
||||
CanThrowResult CT;
|
||||
if (isTypeDependent())
|
||||
CT = CT_Dependent;
|
||||
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
|
||||
CT = CT_Cannot;
|
||||
else
|
||||
CT = CanCalleeThrow(C, this, CE->getCalleeDecl());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case CXXConstructExprClass:
|
||||
case CXXTemporaryObjectExprClass: {
|
||||
CanThrowResult CT = CanCalleeThrow(C, this,
|
||||
cast<CXXConstructExpr>(this)->getConstructor());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case LambdaExprClass: {
|
||||
const LambdaExpr *Lambda = cast<LambdaExpr>(this);
|
||||
CanThrowResult CT = Expr::CT_Cannot;
|
||||
for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(),
|
||||
CapEnd = Lambda->capture_init_end();
|
||||
Cap != CapEnd; ++Cap)
|
||||
CT = MergeCanThrow(CT, (*Cap)->CanThrow(C));
|
||||
return CT;
|
||||
}
|
||||
|
||||
case CXXNewExprClass: {
|
||||
CanThrowResult CT;
|
||||
if (isTypeDependent())
|
||||
CT = CT_Dependent;
|
||||
else
|
||||
CT = CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case CXXDeleteExprClass: {
|
||||
CanThrowResult CT;
|
||||
QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();
|
||||
if (DTy.isNull() || DTy->isDependentType()) {
|
||||
CT = CT_Dependent;
|
||||
} else {
|
||||
CT = CanCalleeThrow(C, this,
|
||||
cast<CXXDeleteExpr>(this)->getOperatorDelete());
|
||||
if (const RecordType *RT = DTy->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor()));
|
||||
}
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
}
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case CXXBindTemporaryExprClass: {
|
||||
// The bound temporary has to be destroyed again, which might throw.
|
||||
CanThrowResult CT = CanCalleeThrow(C, this,
|
||||
cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
// ObjC message sends are like function calls, but never have exception
|
||||
// specs.
|
||||
case ObjCMessageExprClass:
|
||||
case ObjCPropertyRefExprClass:
|
||||
case ObjCSubscriptRefExprClass:
|
||||
return CT_Can;
|
||||
|
||||
// All the ObjC literals that are implemented as calls are
|
||||
// potentially throwing unless we decide to close off that
|
||||
// possibility.
|
||||
case ObjCArrayLiteralClass:
|
||||
case ObjCDictionaryLiteralClass:
|
||||
case ObjCNumericLiteralClass:
|
||||
return CT_Can;
|
||||
|
||||
// Many other things have subexpressions, so we have to test those.
|
||||
// Some are simple:
|
||||
case ConditionalOperatorClass:
|
||||
case CompoundLiteralExprClass:
|
||||
case CXXConstCastExprClass:
|
||||
case CXXDefaultArgExprClass:
|
||||
case CXXReinterpretCastExprClass:
|
||||
case DesignatedInitExprClass:
|
||||
case ExprWithCleanupsClass:
|
||||
case ExtVectorElementExprClass:
|
||||
case InitListExprClass:
|
||||
case MemberExprClass:
|
||||
case ObjCIsaExprClass:
|
||||
case ObjCIvarRefExprClass:
|
||||
case ParenExprClass:
|
||||
case ParenListExprClass:
|
||||
case ShuffleVectorExprClass:
|
||||
case VAArgExprClass:
|
||||
return CanSubExprsThrow(C, this);
|
||||
|
||||
// Some might be dependent for other reasons.
|
||||
case ArraySubscriptExprClass:
|
||||
case BinaryOperatorClass:
|
||||
case CompoundAssignOperatorClass:
|
||||
case CStyleCastExprClass:
|
||||
case CXXStaticCastExprClass:
|
||||
case CXXFunctionalCastExprClass:
|
||||
case ImplicitCastExprClass:
|
||||
case MaterializeTemporaryExprClass:
|
||||
case UnaryOperatorClass: {
|
||||
CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
// FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
|
||||
case StmtExprClass:
|
||||
return CT_Can;
|
||||
|
||||
case ChooseExprClass:
|
||||
if (isTypeDependent() || isValueDependent())
|
||||
return CT_Dependent;
|
||||
return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
|
||||
|
||||
case GenericSelectionExprClass:
|
||||
if (cast<GenericSelectionExpr>(this)->isResultDependent())
|
||||
return CT_Dependent;
|
||||
return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
|
||||
|
||||
// Some expressions are always dependent.
|
||||
case CXXDependentScopeMemberExprClass:
|
||||
case CXXUnresolvedConstructExprClass:
|
||||
case DependentScopeDeclRefExprClass:
|
||||
return CT_Dependent;
|
||||
|
||||
case AtomicExprClass:
|
||||
case AsTypeExprClass:
|
||||
case BinaryConditionalOperatorClass:
|
||||
case BlockExprClass:
|
||||
case CUDAKernelCallExprClass:
|
||||
case DeclRefExprClass:
|
||||
case ObjCBridgedCastExprClass:
|
||||
case ObjCIndirectCopyRestoreExprClass:
|
||||
case ObjCProtocolExprClass:
|
||||
case ObjCSelectorExprClass:
|
||||
case OffsetOfExprClass:
|
||||
case PackExpansionExprClass:
|
||||
case PseudoObjectExprClass:
|
||||
case SubstNonTypeTemplateParmExprClass:
|
||||
case SubstNonTypeTemplateParmPackExprClass:
|
||||
case UnaryExprOrTypeTraitExprClass:
|
||||
case UnresolvedLookupExprClass:
|
||||
case UnresolvedMemberExprClass:
|
||||
// FIXME: Can any of the above throw? If so, when?
|
||||
return CT_Cannot;
|
||||
|
||||
case AddrLabelExprClass:
|
||||
case ArrayTypeTraitExprClass:
|
||||
case BinaryTypeTraitExprClass:
|
||||
case TypeTraitExprClass:
|
||||
case CXXBoolLiteralExprClass:
|
||||
case CXXNoexceptExprClass:
|
||||
case CXXNullPtrLiteralExprClass:
|
||||
case CXXPseudoDestructorExprClass:
|
||||
case CXXScalarValueInitExprClass:
|
||||
case CXXThisExprClass:
|
||||
case CXXUuidofExprClass:
|
||||
case CharacterLiteralClass:
|
||||
case ExpressionTraitExprClass:
|
||||
case FloatingLiteralClass:
|
||||
case GNUNullExprClass:
|
||||
case ImaginaryLiteralClass:
|
||||
case ImplicitValueInitExprClass:
|
||||
case IntegerLiteralClass:
|
||||
case ObjCEncodeExprClass:
|
||||
case ObjCStringLiteralClass:
|
||||
case ObjCBoolLiteralExprClass:
|
||||
case OpaqueValueExprClass:
|
||||
case PredefinedExprClass:
|
||||
case SizeOfPackExprClass:
|
||||
case StringLiteralClass:
|
||||
case UnaryTypeTraitExprClass:
|
||||
// These expressions can never throw.
|
||||
return CT_Cannot;
|
||||
|
||||
#define STMT(CLASS, PARENT) case CLASS##Class:
|
||||
#define STMT_RANGE(Base, First, Last)
|
||||
#define LAST_STMT_RANGE(BASE, FIRST, LAST)
|
||||
#define EXPR(CLASS, PARENT)
|
||||
#define ABSTRACT_STMT(STMT)
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
case NoStmtClass:
|
||||
llvm_unreachable("Invalid class for expression");
|
||||
}
|
||||
llvm_unreachable("Bogus StmtClass");
|
||||
}
|
||||
|
||||
Expr* Expr::IgnoreParens() {
|
||||
Expr* E = this;
|
||||
while (true) {
|
||||
|
|
|
@ -1546,6 +1546,13 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
|
|||
else if (epi.NoexceptExpr->isInstantiationDependent())
|
||||
setInstantiationDependent();
|
||||
}
|
||||
} else if (getExceptionSpecType() == EST_Uninstantiated) {
|
||||
// Store the function decl from which we will resolve our
|
||||
// exception specification.
|
||||
FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
|
||||
*slot = epi.ExceptionSpecDecl;
|
||||
// This exception specification doesn't make the type dependent, because
|
||||
// it's not instantiated as part of instantiating the type.
|
||||
}
|
||||
|
||||
if (epi.ConsumedArguments) {
|
||||
|
@ -1629,6 +1636,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
|||
ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
|
||||
} else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
|
||||
epi.NoexceptExpr->Profile(ID, Context, false);
|
||||
} else if (epi.ExceptionSpecType == EST_Uninstantiated) {
|
||||
ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl());
|
||||
}
|
||||
if (epi.ConsumedArguments) {
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
|
|
|
@ -1284,7 +1284,8 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) {
|
|||
const FunctionType *FT = Ty->getAs<FunctionType>();
|
||||
if (FT) {
|
||||
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
|
||||
if (Proto->isNothrow(Ctx))
|
||||
if (Proto->getExceptionSpecType() != EST_Uninstantiated &&
|
||||
Proto->isNothrow(Ctx))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -125,14 +125,17 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
|
||||
assert(Context && "ImplicitExceptionSpecification without an ASTContext");
|
||||
void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
|
||||
CXXMethodDecl *Method) {
|
||||
// If we have an MSAny or unknown spec already, don't bother.
|
||||
if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
|
||||
return;
|
||||
|
||||
const FunctionProtoType *Proto
|
||||
= Method->getType()->getAs<FunctionProtoType>();
|
||||
Proto = Self->ResolveExceptionSpec(CallLoc, Proto);
|
||||
if (!Proto)
|
||||
return;
|
||||
|
||||
ExceptionSpecificationType EST = Proto->getExceptionSpecType();
|
||||
|
||||
|
@ -164,7 +167,8 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
|
|||
|
||||
// Check out noexcept specs.
|
||||
if (EST == EST_ComputedNoexcept) {
|
||||
FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(*Context);
|
||||
FunctionProtoType::NoexceptResult NR =
|
||||
Proto->getNoexceptSpec(Self->Context);
|
||||
assert(NR != FunctionProtoType::NR_NoNoexcept &&
|
||||
"Must have noexcept result for EST_ComputedNoexcept.");
|
||||
assert(NR != FunctionProtoType::NR_Dependent &&
|
||||
|
@ -188,7 +192,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
|
|||
for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
|
||||
EEnd = Proto->exception_end();
|
||||
E != EEnd; ++E)
|
||||
if (ExceptionsSeen.insert(Context->getCanonicalType(*E)))
|
||||
if (ExceptionsSeen.insert(Self->Context.getCanonicalType(*E)))
|
||||
Exceptions.push_back(*E);
|
||||
}
|
||||
|
||||
|
@ -217,7 +221,7 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
|
|||
// implicit definition. For now, we assume that any non-nothrow expression can
|
||||
// throw any exception.
|
||||
|
||||
if (E->CanThrow(*Context))
|
||||
if (Self->canThrow(E))
|
||||
ComputedEST = EST_None;
|
||||
}
|
||||
|
||||
|
@ -3922,7 +3926,7 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
|
|||
HadError = true;
|
||||
}
|
||||
|
||||
ImplicitExceptionSpecification Spec(Context);
|
||||
ImplicitExceptionSpecification Spec(*this);
|
||||
bool Const;
|
||||
llvm::tie(Spec, Const) =
|
||||
ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent());
|
||||
|
@ -4031,7 +4035,7 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
|
|||
HadError = true;
|
||||
}
|
||||
|
||||
ImplicitExceptionSpecification Spec(Context);
|
||||
ImplicitExceptionSpecification Spec(*this);
|
||||
bool Const;
|
||||
llvm::tie(Spec, Const) =
|
||||
ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());
|
||||
|
@ -6814,7 +6818,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// C++ [except.spec]p14:
|
||||
// An implicitly declared special member function (Clause 12) shall have an
|
||||
// exception-specification. [...]
|
||||
ImplicitExceptionSpecification ExceptSpec(Context);
|
||||
ImplicitExceptionSpecification ExceptSpec(*this);
|
||||
if (ClassDecl->isInvalidDecl())
|
||||
return ExceptSpec;
|
||||
|
||||
|
@ -6831,7 +6835,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// If this is a deleted function, add it anyway. This might be conformant
|
||||
// with the standard. This might not. I'm not sure. It might not matter.
|
||||
if (Constructor)
|
||||
ExceptSpec.CalledDecl(Constructor);
|
||||
ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6845,7 +6849,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// If this is a deleted function, add it anyway. This might be conformant
|
||||
// with the standard. This might not. I'm not sure. It might not matter.
|
||||
if (Constructor)
|
||||
ExceptSpec.CalledDecl(Constructor);
|
||||
ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6868,7 +6872,7 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// might just be ill-formed because this function attempts to refer to
|
||||
// a deleted function here.
|
||||
if (Constructor)
|
||||
ExceptSpec.CalledDecl(Constructor);
|
||||
ExceptSpec.CalledDecl(F->getLocation(), Constructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6990,6 +6994,7 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
|
|||
const FunctionProtoType *CtorTy =
|
||||
CtorDecl->getType()->castAs<FunctionProtoType>();
|
||||
if (CtorTy->getExceptionSpecType() == EST_Delayed) {
|
||||
// FIXME: Don't do this unless the exception spec is needed.
|
||||
ImplicitExceptionSpecification Spec =
|
||||
ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
|
||||
FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
|
||||
|
@ -7190,7 +7195,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// C++ [except.spec]p14:
|
||||
// An implicitly declared special member function (Clause 12) shall have
|
||||
// an exception-specification.
|
||||
ImplicitExceptionSpecification ExceptSpec(Context);
|
||||
ImplicitExceptionSpecification ExceptSpec(*this);
|
||||
if (ClassDecl->isInvalidDecl())
|
||||
return ExceptSpec;
|
||||
|
||||
|
@ -7202,7 +7207,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
continue;
|
||||
|
||||
if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
|
||||
ExceptSpec.CalledDecl(
|
||||
ExceptSpec.CalledDecl(B->getLocStart(),
|
||||
LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
|
||||
}
|
||||
|
||||
|
@ -7211,7 +7216,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
BEnd = ClassDecl->vbases_end();
|
||||
B != BEnd; ++B) {
|
||||
if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
|
||||
ExceptSpec.CalledDecl(
|
||||
ExceptSpec.CalledDecl(B->getLocStart(),
|
||||
LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
|
||||
}
|
||||
|
||||
|
@ -7221,7 +7226,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
F != FEnd; ++F) {
|
||||
if (const RecordType *RecordTy
|
||||
= Context.getBaseElementType(F->getType())->getAs<RecordType>())
|
||||
ExceptSpec.CalledDecl(
|
||||
ExceptSpec.CalledDecl(F->getLocation(),
|
||||
LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
|
||||
}
|
||||
|
||||
|
@ -7546,7 +7551,7 @@ std::pair<Sema::ImplicitExceptionSpecification, bool>
|
|||
Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
|
||||
CXXRecordDecl *ClassDecl) {
|
||||
if (ClassDecl->isInvalidDecl())
|
||||
return std::make_pair(ImplicitExceptionSpecification(Context), false);
|
||||
return std::make_pair(ImplicitExceptionSpecification(*this), false);
|
||||
|
||||
// C++ [class.copy]p10:
|
||||
// If the class definition does not explicitly declare a copy
|
||||
|
@ -7619,7 +7624,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
|
|||
// Based on a similar decision made for constness in C++0x, we're erring on
|
||||
// the side of assuming such calls to be made regardless of whether they
|
||||
// actually happen.
|
||||
ImplicitExceptionSpecification ExceptSpec(Context);
|
||||
ImplicitExceptionSpecification ExceptSpec(*this);
|
||||
unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;
|
||||
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
|
||||
BaseEnd = ClassDecl->bases_end();
|
||||
|
@ -7631,7 +7636,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
|
|||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
|
||||
ArgQuals, false, 0))
|
||||
ExceptSpec.CalledDecl(CopyAssign);
|
||||
ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
|
||||
|
@ -7641,7 +7646,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
|
|||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
|
||||
ArgQuals, false, 0))
|
||||
ExceptSpec.CalledDecl(CopyAssign);
|
||||
ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
|
@ -7652,7 +7657,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
|
|||
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
|
||||
if (CXXMethodDecl *CopyAssign =
|
||||
LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0))
|
||||
ExceptSpec.CalledDecl(CopyAssign);
|
||||
ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7665,7 +7670,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
|
|||
// for determining the argument type of the operator. Note also that
|
||||
// operators taking an object instead of a reference are allowed.
|
||||
|
||||
ImplicitExceptionSpecification Spec(Context);
|
||||
ImplicitExceptionSpecification Spec(*this);
|
||||
bool Const;
|
||||
llvm::tie(Spec, Const) =
|
||||
ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);
|
||||
|
@ -8032,7 +8037,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
|
|||
|
||||
Sema::ImplicitExceptionSpecification
|
||||
Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
|
||||
ImplicitExceptionSpecification ExceptSpec(Context);
|
||||
ImplicitExceptionSpecification ExceptSpec(*this);
|
||||
|
||||
if (ClassDecl->isInvalidDecl())
|
||||
return ExceptSpec;
|
||||
|
@ -8059,7 +8064,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
|
||||
false, 0))
|
||||
ExceptSpec.CalledDecl(MoveAssign);
|
||||
ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
|
||||
|
@ -8069,7 +8074,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
|
||||
false, 0))
|
||||
ExceptSpec.CalledDecl(MoveAssign);
|
||||
ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
|
||||
}
|
||||
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
|
@ -8080,7 +8085,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
|
||||
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl,
|
||||
false, 0))
|
||||
ExceptSpec.CalledDecl(MoveAssign);
|
||||
ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8578,7 +8583,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
|
|||
std::pair<Sema::ImplicitExceptionSpecification, bool>
|
||||
Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
|
||||
if (ClassDecl->isInvalidDecl())
|
||||
return std::make_pair(ImplicitExceptionSpecification(Context), false);
|
||||
return std::make_pair(ImplicitExceptionSpecification(*this), false);
|
||||
|
||||
// C++ [class.copy]p5:
|
||||
// The implicitly-declared copy constructor for a class X will
|
||||
|
@ -8639,7 +8644,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
|
|||
// C++ [except.spec]p14:
|
||||
// An implicitly declared special member function (Clause 12) shall have an
|
||||
// exception-specification. [...]
|
||||
ImplicitExceptionSpecification ExceptSpec(Context);
|
||||
ImplicitExceptionSpecification ExceptSpec(*this);
|
||||
unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0;
|
||||
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
|
||||
BaseEnd = ClassDecl->bases_end();
|
||||
|
@ -8653,7 +8658,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
|
|||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
if (CXXConstructorDecl *CopyConstructor =
|
||||
LookupCopyingConstructor(BaseClassDecl, Quals))
|
||||
ExceptSpec.CalledDecl(CopyConstructor);
|
||||
ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);
|
||||
}
|
||||
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
|
||||
BaseEnd = ClassDecl->vbases_end();
|
||||
|
@ -8663,7 +8668,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
|
|||
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
if (CXXConstructorDecl *CopyConstructor =
|
||||
LookupCopyingConstructor(BaseClassDecl, Quals))
|
||||
ExceptSpec.CalledDecl(CopyConstructor);
|
||||
ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);
|
||||
}
|
||||
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
||||
FieldEnd = ClassDecl->field_end();
|
||||
|
@ -8673,7 +8678,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
|
|||
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
|
||||
if (CXXConstructorDecl *CopyConstructor =
|
||||
LookupCopyingConstructor(FieldClassDecl, Quals))
|
||||
ExceptSpec.CalledDecl(CopyConstructor);
|
||||
ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8686,7 +8691,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
|
|||
// If the class definition does not explicitly declare a copy
|
||||
// constructor, one is declared implicitly.
|
||||
|
||||
ImplicitExceptionSpecification Spec(Context);
|
||||
ImplicitExceptionSpecification Spec(*this);
|
||||
bool Const;
|
||||
llvm::tie(Spec, Const) =
|
||||
ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);
|
||||
|
@ -8784,7 +8789,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// C++ [except.spec]p14:
|
||||
// An implicitly declared special member function (Clause 12) shall have an
|
||||
// exception-specification. [...]
|
||||
ImplicitExceptionSpecification ExceptSpec(Context);
|
||||
ImplicitExceptionSpecification ExceptSpec(*this);
|
||||
if (ClassDecl->isInvalidDecl())
|
||||
return ExceptSpec;
|
||||
|
||||
|
@ -8801,7 +8806,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// If this is a deleted function, add it anyway. This might be conformant
|
||||
// with the standard. This might not. I'm not sure. It might not matter.
|
||||
if (Constructor)
|
||||
ExceptSpec.CalledDecl(Constructor);
|
||||
ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8815,7 +8820,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// If this is a deleted function, add it anyway. This might be conformant
|
||||
// with the standard. This might not. I'm not sure. It might not matter.
|
||||
if (Constructor)
|
||||
ExceptSpec.CalledDecl(Constructor);
|
||||
ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8833,7 +8838,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
// might just be ill-formed because this function attempts to refer to
|
||||
// a deleted function here.
|
||||
if (Constructor)
|
||||
ExceptSpec.CalledDecl(Constructor);
|
||||
ExceptSpec.CalledDecl(F->getLocation(), Constructor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11116,6 +11121,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
|
|||
FindCXXThisExpr Finder(*this);
|
||||
|
||||
switch (Proto->getExceptionSpecType()) {
|
||||
case EST_Uninstantiated:
|
||||
case EST_BasicNoexcept:
|
||||
case EST_Delayed:
|
||||
case EST_DynamicNone:
|
||||
|
|
|
@ -96,6 +96,26 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
|
|||
return FnT->hasExceptionSpec();
|
||||
}
|
||||
|
||||
const FunctionProtoType *
|
||||
Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
|
||||
// FIXME: If FD is a special member, we should delay computing its exception
|
||||
// specification until this point.
|
||||
if (FPT->getExceptionSpecType() != EST_Uninstantiated)
|
||||
return FPT;
|
||||
|
||||
FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
|
||||
const FunctionProtoType *SourceFPT =
|
||||
SourceDecl->getType()->castAs<FunctionProtoType>();
|
||||
|
||||
if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated)
|
||||
return SourceFPT;
|
||||
|
||||
// Instantiate the exception specification now.
|
||||
InstantiateExceptionSpec(Loc, SourceDecl);
|
||||
|
||||
return SourceDecl->getType()->castAs<FunctionProtoType>();
|
||||
}
|
||||
|
||||
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
|
||||
OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
|
||||
bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
|
||||
|
@ -104,7 +124,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
|
|||
unsigned DiagID = diag::err_mismatched_exception_spec;
|
||||
if (getLangOpts().MicrosoftExt)
|
||||
DiagID = diag::warn_mismatched_exception_spec;
|
||||
|
||||
|
||||
if (!CheckEquivalentExceptionSpec(PDiag(DiagID),
|
||||
PDiag(diag::note_previous_declaration),
|
||||
Old->getType()->getAs<FunctionProtoType>(),
|
||||
|
@ -295,6 +315,13 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
|||
if (MissingEmptyExceptionSpecification)
|
||||
*MissingEmptyExceptionSpecification = false;
|
||||
|
||||
Old = ResolveExceptionSpec(NewLoc, Old);
|
||||
if (!Old)
|
||||
return false;
|
||||
New = ResolveExceptionSpec(NewLoc, New);
|
||||
if (!New)
|
||||
return false;
|
||||
|
||||
// C++0x [except.spec]p3: Two exception-specifications are compatible if:
|
||||
// - both are non-throwing, regardless of their form,
|
||||
// - both have the form noexcept(constant-expression) and the constant-
|
||||
|
@ -318,6 +345,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
|||
ExceptionSpecificationType NewEST = New->getExceptionSpecType();
|
||||
|
||||
assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
|
||||
OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated &&
|
||||
"Shouldn't see unknown exception specifications here");
|
||||
|
||||
// Shortcut the case where both have no spec.
|
||||
|
@ -483,6 +511,14 @@ bool Sema::CheckExceptionSpecSubset(
|
|||
if (!SubLoc.isValid())
|
||||
SubLoc = SuperLoc;
|
||||
|
||||
// Resolve the exception specifications, if needed.
|
||||
Superset = ResolveExceptionSpec(SuperLoc, Superset);
|
||||
if (!Superset)
|
||||
return false;
|
||||
Subset = ResolveExceptionSpec(SubLoc, Subset);
|
||||
if (!Subset)
|
||||
return false;
|
||||
|
||||
ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
|
||||
|
||||
// If superset contains everything, we're done.
|
||||
|
@ -507,6 +543,7 @@ bool Sema::CheckExceptionSpecSubset(
|
|||
ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
|
||||
|
||||
assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
|
||||
SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated &&
|
||||
"Shouldn't see unknown exception specifications here");
|
||||
|
||||
// It does not. If the subset contains everything, we've failed.
|
||||
|
@ -726,4 +763,324 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
|
|||
New->getLocation());
|
||||
}
|
||||
|
||||
static CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) {
|
||||
Expr *E = const_cast<Expr*>(CE);
|
||||
CanThrowResult R = CT_Cannot;
|
||||
for (Expr::child_range I = E->children(); I && R != CT_Can; ++I)
|
||||
R = mergeCanThrow(R, S.canThrow(cast<Expr>(*I)));
|
||||
return R;
|
||||
}
|
||||
|
||||
static CanThrowResult canCalleeThrow(Sema &S, const Expr *E,
|
||||
const Decl *D,
|
||||
bool NullThrows = true) {
|
||||
if (!D)
|
||||
return NullThrows ? CT_Can : CT_Cannot;
|
||||
|
||||
// See if we can get a function type from the decl somehow.
|
||||
const ValueDecl *VD = dyn_cast<ValueDecl>(D);
|
||||
if (!VD) // If we have no clue what we're calling, assume the worst.
|
||||
return CT_Can;
|
||||
|
||||
// As an extension, we assume that __attribute__((nothrow)) functions don't
|
||||
// throw.
|
||||
if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
|
||||
return CT_Cannot;
|
||||
|
||||
QualType T = VD->getType();
|
||||
const FunctionProtoType *FT;
|
||||
if ((FT = T->getAs<FunctionProtoType>())) {
|
||||
} else if (const PointerType *PT = T->getAs<PointerType>())
|
||||
FT = PT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const ReferenceType *RT = T->getAs<ReferenceType>())
|
||||
FT = RT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
|
||||
FT = MT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
|
||||
FT = BT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
|
||||
if (!FT)
|
||||
return CT_Can;
|
||||
|
||||
FT = S.ResolveExceptionSpec(E->getLocStart(), FT);
|
||||
if (!FT)
|
||||
return CT_Can;
|
||||
|
||||
if (FT->getExceptionSpecType() == EST_Delayed) {
|
||||
// FIXME: Try to resolve a delayed exception spec in ResolveExceptionSpec.
|
||||
assert(isa<CXXConstructorDecl>(D) &&
|
||||
"only constructor exception specs can be unknown");
|
||||
S.Diag(E->getLocStart(), diag::err_exception_spec_unknown)
|
||||
<< E->getSourceRange();
|
||||
return CT_Can;
|
||||
}
|
||||
|
||||
return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
|
||||
}
|
||||
|
||||
static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
|
||||
if (DC->isTypeDependent())
|
||||
return CT_Dependent;
|
||||
|
||||
if (!DC->getTypeAsWritten()->isReferenceType())
|
||||
return CT_Cannot;
|
||||
|
||||
if (DC->getSubExpr()->isTypeDependent())
|
||||
return CT_Dependent;
|
||||
|
||||
return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;
|
||||
}
|
||||
|
||||
static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
|
||||
if (DC->isTypeOperand())
|
||||
return CT_Cannot;
|
||||
|
||||
Expr *Op = DC->getExprOperand();
|
||||
if (Op->isTypeDependent())
|
||||
return CT_Dependent;
|
||||
|
||||
const RecordType *RT = Op->getType()->getAs<RecordType>();
|
||||
if (!RT)
|
||||
return CT_Cannot;
|
||||
|
||||
if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
|
||||
return CT_Cannot;
|
||||
|
||||
if (Op->Classify(S.Context).isPRValue())
|
||||
return CT_Cannot;
|
||||
|
||||
return CT_Can;
|
||||
}
|
||||
|
||||
CanThrowResult Sema::canThrow(const Expr *E) {
|
||||
// C++ [expr.unary.noexcept]p3:
|
||||
// [Can throw] if in a potentially-evaluated context the expression would
|
||||
// contain:
|
||||
switch (E->getStmtClass()) {
|
||||
case Expr::CXXThrowExprClass:
|
||||
// - a potentially evaluated throw-expression
|
||||
return CT_Can;
|
||||
|
||||
case Expr::CXXDynamicCastExprClass: {
|
||||
// - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
|
||||
// where T is a reference type, that requires a run-time check
|
||||
CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
|
||||
}
|
||||
|
||||
case Expr::CXXTypeidExprClass:
|
||||
// - a potentially evaluated typeid expression applied to a glvalue
|
||||
// expression whose type is a polymorphic class type
|
||||
return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
|
||||
|
||||
// - a potentially evaluated call to a function, member function, function
|
||||
// pointer, or member function pointer that does not have a non-throwing
|
||||
// exception-specification
|
||||
case Expr::CallExprClass:
|
||||
case Expr::CXXMemberCallExprClass:
|
||||
case Expr::CXXOperatorCallExprClass:
|
||||
case Expr::UserDefinedLiteralClass: {
|
||||
const CallExpr *CE = cast<CallExpr>(E);
|
||||
CanThrowResult CT;
|
||||
if (E->isTypeDependent())
|
||||
CT = CT_Dependent;
|
||||
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
|
||||
CT = CT_Cannot;
|
||||
else
|
||||
CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
|
||||
}
|
||||
|
||||
case Expr::CXXConstructExprClass:
|
||||
case Expr::CXXTemporaryObjectExprClass: {
|
||||
CanThrowResult CT = canCalleeThrow(*this, E,
|
||||
cast<CXXConstructExpr>(E)->getConstructor());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
|
||||
}
|
||||
|
||||
case Expr::LambdaExprClass: {
|
||||
const LambdaExpr *Lambda = cast<LambdaExpr>(E);
|
||||
CanThrowResult CT = CT_Cannot;
|
||||
for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(),
|
||||
CapEnd = Lambda->capture_init_end();
|
||||
Cap != CapEnd; ++Cap)
|
||||
CT = mergeCanThrow(CT, canThrow(*Cap));
|
||||
return CT;
|
||||
}
|
||||
|
||||
case Expr::CXXNewExprClass: {
|
||||
CanThrowResult CT;
|
||||
if (E->isTypeDependent())
|
||||
CT = CT_Dependent;
|
||||
else
|
||||
CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
|
||||
}
|
||||
|
||||
case Expr::CXXDeleteExprClass: {
|
||||
CanThrowResult CT;
|
||||
QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
|
||||
if (DTy.isNull() || DTy->isDependentType()) {
|
||||
CT = CT_Dependent;
|
||||
} else {
|
||||
CT = canCalleeThrow(*this, E,
|
||||
cast<CXXDeleteExpr>(E)->getOperatorDelete());
|
||||
if (const RecordType *RT = DTy->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
CT = mergeCanThrow(CT, canCalleeThrow(*this, E, RD->getDestructor()));
|
||||
}
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
}
|
||||
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
|
||||
}
|
||||
|
||||
case Expr::CXXBindTemporaryExprClass: {
|
||||
// The bound temporary has to be destroyed again, which might throw.
|
||||
CanThrowResult CT = canCalleeThrow(*this, E,
|
||||
cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
|
||||
}
|
||||
|
||||
// ObjC message sends are like function calls, but never have exception
|
||||
// specs.
|
||||
case Expr::ObjCMessageExprClass:
|
||||
case Expr::ObjCPropertyRefExprClass:
|
||||
case Expr::ObjCSubscriptRefExprClass:
|
||||
return CT_Can;
|
||||
|
||||
// All the ObjC literals that are implemented as calls are
|
||||
// potentially throwing unless we decide to close off that
|
||||
// possibility.
|
||||
case Expr::ObjCArrayLiteralClass:
|
||||
case Expr::ObjCDictionaryLiteralClass:
|
||||
case Expr::ObjCNumericLiteralClass:
|
||||
return CT_Can;
|
||||
|
||||
// Many other things have subexpressions, so we have to test those.
|
||||
// Some are simple:
|
||||
case Expr::ConditionalOperatorClass:
|
||||
case Expr::CompoundLiteralExprClass:
|
||||
case Expr::CXXConstCastExprClass:
|
||||
case Expr::CXXDefaultArgExprClass:
|
||||
case Expr::CXXReinterpretCastExprClass:
|
||||
case Expr::DesignatedInitExprClass:
|
||||
case Expr::ExprWithCleanupsClass:
|
||||
case Expr::ExtVectorElementExprClass:
|
||||
case Expr::InitListExprClass:
|
||||
case Expr::MemberExprClass:
|
||||
case Expr::ObjCIsaExprClass:
|
||||
case Expr::ObjCIvarRefExprClass:
|
||||
case Expr::ParenExprClass:
|
||||
case Expr::ParenListExprClass:
|
||||
case Expr::ShuffleVectorExprClass:
|
||||
case Expr::VAArgExprClass:
|
||||
return canSubExprsThrow(*this, E);
|
||||
|
||||
// Some might be dependent for other reasons.
|
||||
case Expr::ArraySubscriptExprClass:
|
||||
case Expr::BinaryOperatorClass:
|
||||
case Expr::CompoundAssignOperatorClass:
|
||||
case Expr::CStyleCastExprClass:
|
||||
case Expr::CXXStaticCastExprClass:
|
||||
case Expr::CXXFunctionalCastExprClass:
|
||||
case Expr::ImplicitCastExprClass:
|
||||
case Expr::MaterializeTemporaryExprClass:
|
||||
case Expr::UnaryOperatorClass: {
|
||||
CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
|
||||
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
|
||||
}
|
||||
|
||||
// FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
|
||||
case Expr::StmtExprClass:
|
||||
return CT_Can;
|
||||
|
||||
case Expr::ChooseExprClass:
|
||||
if (E->isTypeDependent() || E->isValueDependent())
|
||||
return CT_Dependent;
|
||||
return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context));
|
||||
|
||||
case Expr::GenericSelectionExprClass:
|
||||
if (cast<GenericSelectionExpr>(E)->isResultDependent())
|
||||
return CT_Dependent;
|
||||
return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
|
||||
|
||||
// Some expressions are always dependent.
|
||||
case Expr::CXXDependentScopeMemberExprClass:
|
||||
case Expr::CXXUnresolvedConstructExprClass:
|
||||
case Expr::DependentScopeDeclRefExprClass:
|
||||
return CT_Dependent;
|
||||
|
||||
case Expr::AsTypeExprClass:
|
||||
case Expr::BinaryConditionalOperatorClass:
|
||||
case Expr::BlockExprClass:
|
||||
case Expr::CUDAKernelCallExprClass:
|
||||
case Expr::DeclRefExprClass:
|
||||
case Expr::ObjCBridgedCastExprClass:
|
||||
case Expr::ObjCIndirectCopyRestoreExprClass:
|
||||
case Expr::ObjCProtocolExprClass:
|
||||
case Expr::ObjCSelectorExprClass:
|
||||
case Expr::OffsetOfExprClass:
|
||||
case Expr::PackExpansionExprClass:
|
||||
case Expr::PseudoObjectExprClass:
|
||||
case Expr::SubstNonTypeTemplateParmExprClass:
|
||||
case Expr::SubstNonTypeTemplateParmPackExprClass:
|
||||
case Expr::UnaryExprOrTypeTraitExprClass:
|
||||
case Expr::UnresolvedLookupExprClass:
|
||||
case Expr::UnresolvedMemberExprClass:
|
||||
// FIXME: Can any of the above throw? If so, when?
|
||||
return CT_Cannot;
|
||||
|
||||
case Expr::AddrLabelExprClass:
|
||||
case Expr::ArrayTypeTraitExprClass:
|
||||
case Expr::AtomicExprClass:
|
||||
case Expr::BinaryTypeTraitExprClass:
|
||||
case Expr::TypeTraitExprClass:
|
||||
case Expr::CXXBoolLiteralExprClass:
|
||||
case Expr::CXXNoexceptExprClass:
|
||||
case Expr::CXXNullPtrLiteralExprClass:
|
||||
case Expr::CXXPseudoDestructorExprClass:
|
||||
case Expr::CXXScalarValueInitExprClass:
|
||||
case Expr::CXXThisExprClass:
|
||||
case Expr::CXXUuidofExprClass:
|
||||
case Expr::CharacterLiteralClass:
|
||||
case Expr::ExpressionTraitExprClass:
|
||||
case Expr::FloatingLiteralClass:
|
||||
case Expr::GNUNullExprClass:
|
||||
case Expr::ImaginaryLiteralClass:
|
||||
case Expr::ImplicitValueInitExprClass:
|
||||
case Expr::IntegerLiteralClass:
|
||||
case Expr::ObjCEncodeExprClass:
|
||||
case Expr::ObjCStringLiteralClass:
|
||||
case Expr::ObjCBoolLiteralExprClass:
|
||||
case Expr::OpaqueValueExprClass:
|
||||
case Expr::PredefinedExprClass:
|
||||
case Expr::SizeOfPackExprClass:
|
||||
case Expr::StringLiteralClass:
|
||||
case Expr::UnaryTypeTraitExprClass:
|
||||
// These expressions can never throw.
|
||||
return CT_Cannot;
|
||||
|
||||
#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
|
||||
#define STMT_RANGE(Base, First, Last)
|
||||
#define LAST_STMT_RANGE(BASE, FIRST, LAST)
|
||||
#define EXPR(CLASS, PARENT)
|
||||
#define ABSTRACT_STMT(STMT)
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
case Expr::NoStmtClass:
|
||||
llvm_unreachable("Invalid class for expression");
|
||||
}
|
||||
llvm_unreachable("Bogus StmtClass");
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -9773,6 +9773,13 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
|
|||
// FIXME: Is this really right?
|
||||
if (CurContext == Func) return;
|
||||
|
||||
// Instantiate the exception specification for any function which is
|
||||
// used: CodeGen will need it.
|
||||
if (Func->getTemplateInstantiationPattern() &&
|
||||
Func->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
|
||||
== EST_Uninstantiated)
|
||||
InstantiateExceptionSpec(Loc, Func);
|
||||
|
||||
// Implicit instantiation of function templates and member functions of
|
||||
// class templates.
|
||||
if (Func->isImplicitlyInstantiable()) {
|
||||
|
|
|
@ -3135,6 +3135,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
FoundAssign = true;
|
||||
const FunctionProtoType *CPT
|
||||
= Operator->getType()->getAs<FunctionProtoType>();
|
||||
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
|
||||
if (!CPT)
|
||||
return false;
|
||||
if (CPT->getExceptionSpecType() == EST_Delayed)
|
||||
return false;
|
||||
if (!CPT->isNothrow(Self.Context))
|
||||
|
@ -3174,6 +3177,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
FoundConstructor = true;
|
||||
const FunctionProtoType *CPT
|
||||
= Constructor->getType()->getAs<FunctionProtoType>();
|
||||
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
|
||||
if (!CPT)
|
||||
return false;
|
||||
if (CPT->getExceptionSpecType() == EST_Delayed)
|
||||
return false;
|
||||
// FIXME: check whether evaluating default arguments can throw.
|
||||
|
@ -3209,6 +3215,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
|||
if (Constructor->isDefaultConstructor()) {
|
||||
const FunctionProtoType *CPT
|
||||
= Constructor->getType()->getAs<FunctionProtoType>();
|
||||
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
|
||||
if (!CPT)
|
||||
return false;
|
||||
if (CPT->getExceptionSpecType() == EST_Delayed)
|
||||
return false;
|
||||
// TODO: check whether evaluating default arguments can throw.
|
||||
|
@ -5203,9 +5212,9 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
|
|||
|
||||
ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,
|
||||
SourceLocation RParen) {
|
||||
CanThrowResult CanThrow = canThrow(Operand);
|
||||
return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand,
|
||||
Operand->CanThrow(Context),
|
||||
KeyLoc, RParen));
|
||||
CanThrow, KeyLoc, RParen));
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
|
||||
|
|
|
@ -11150,6 +11150,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
|
|||
VK_LValue,
|
||||
Found.getDecl(),
|
||||
TemplateArgs);
|
||||
MarkDeclRefReferenced(DRE);
|
||||
DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
|
||||
return DRE;
|
||||
}
|
||||
|
@ -11178,6 +11179,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
|
|||
VK_LValue,
|
||||
Found.getDecl(),
|
||||
TemplateArgs);
|
||||
MarkDeclRefReferenced(DRE);
|
||||
DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);
|
||||
return DRE;
|
||||
} else {
|
||||
|
|
|
@ -153,6 +153,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
|
|||
bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
|
||||
switch (Kind) {
|
||||
case TemplateInstantiation:
|
||||
case ExceptionSpecInstantiation:
|
||||
case DefaultTemplateArgumentInstantiation:
|
||||
case DefaultFunctionArgumentInstantiation:
|
||||
return true;
|
||||
|
@ -190,6 +191,29 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
|
|||
}
|
||||
}
|
||||
|
||||
Sema::InstantiatingTemplate::
|
||||
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Entity, ExceptionSpecification,
|
||||
SourceRange InstantiationRange)
|
||||
: SemaRef(SemaRef),
|
||||
SavedInNonInstantiationSFINAEContext(
|
||||
SemaRef.InNonInstantiationSFINAEContext)
|
||||
{
|
||||
Invalid = CheckInstantiationDepth(PointOfInstantiation,
|
||||
InstantiationRange);
|
||||
if (!Invalid) {
|
||||
ActiveTemplateInstantiation Inst;
|
||||
Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation;
|
||||
Inst.PointOfInstantiation = PointOfInstantiation;
|
||||
Inst.Entity = reinterpret_cast<uintptr_t>(Entity);
|
||||
Inst.TemplateArgs = 0;
|
||||
Inst.NumTemplateArgs = 0;
|
||||
Inst.InstantiationRange = InstantiationRange;
|
||||
SemaRef.InNonInstantiationSFINAEContext = false;
|
||||
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
|
||||
}
|
||||
}
|
||||
|
||||
Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
|
||||
SourceLocation PointOfInstantiation,
|
||||
TemplateDecl *Template,
|
||||
|
@ -592,6 +616,13 @@ void Sema::PrintInstantiationStack() {
|
|||
<< Active->InstantiationRange;
|
||||
break;
|
||||
}
|
||||
|
||||
case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
|
||||
Diags.Report(Active->PointOfInstantiation,
|
||||
diag::note_template_exception_spec_instantiation_here)
|
||||
<< cast<FunctionDecl>((Decl *)Active->Entity)
|
||||
<< Active->InstantiationRange;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -609,6 +640,7 @@ llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
|
|||
switch(Active->Kind) {
|
||||
case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
|
||||
case ActiveTemplateInstantiation::TemplateInstantiation:
|
||||
case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
|
||||
// This is a template instantiation, so there is no SFINAE.
|
||||
return llvm::Optional<TemplateDeductionInfo *>();
|
||||
|
||||
|
|
|
@ -2215,6 +2215,194 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
|
|||
return NewTInfo;
|
||||
}
|
||||
|
||||
/// Introduce the instantiated function parameters into the local
|
||||
/// instantiation scope, and set the parameter names to those used
|
||||
/// in the template.
|
||||
static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
|
||||
const FunctionDecl *PatternDecl,
|
||||
LocalInstantiationScope &Scope,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||
unsigned FParamIdx = 0;
|
||||
for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
|
||||
const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
|
||||
if (!PatternParam->isParameterPack()) {
|
||||
// Simple case: not a parameter pack.
|
||||
assert(FParamIdx < Function->getNumParams());
|
||||
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||
Scope.InstantiatedLocal(PatternParam, FunctionParam);
|
||||
++FParamIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Expand the parameter pack.
|
||||
Scope.MakeInstantiatedLocalArgPack(PatternParam);
|
||||
unsigned NumArgumentsInExpansion
|
||||
= S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
|
||||
for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {
|
||||
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||
Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
|
||||
++FParamIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
|
||||
const FunctionProtoType *Proto,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||
// C++11 [expr.prim.general]p3:
|
||||
// If a declaration declares a member function or member function
|
||||
// template of a class X, the expression this is a prvalue of type
|
||||
// "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
|
||||
// and the end of the function-definition, member-declarator, or
|
||||
// declarator.
|
||||
CXXRecordDecl *ThisContext = 0;
|
||||
unsigned ThisTypeQuals = 0;
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
|
||||
ThisContext = Method->getParent();
|
||||
ThisTypeQuals = Method->getTypeQualifiers();
|
||||
}
|
||||
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
|
||||
SemaRef.getLangOpts().CPlusPlus0x);
|
||||
|
||||
// The function has an exception specification or a "noreturn"
|
||||
// attribute. Substitute into each of the exception types.
|
||||
SmallVector<QualType, 4> Exceptions;
|
||||
for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
|
||||
// FIXME: Poor location information!
|
||||
if (const PackExpansionType *PackExpansion
|
||||
= Proto->getExceptionType(I)->getAs<PackExpansionType>()) {
|
||||
// We have a pack expansion. Instantiate it.
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
|
||||
Unexpanded);
|
||||
assert(!Unexpanded.empty() &&
|
||||
"Pack expansion without parameter packs?");
|
||||
|
||||
bool Expand = false;
|
||||
bool RetainExpansion = false;
|
||||
llvm::Optional<unsigned> NumExpansions
|
||||
= PackExpansion->getNumExpansions();
|
||||
if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
|
||||
SourceRange(),
|
||||
Unexpanded,
|
||||
TemplateArgs,
|
||||
Expand,
|
||||
RetainExpansion,
|
||||
NumExpansions))
|
||||
break;
|
||||
|
||||
if (!Expand) {
|
||||
// We can't expand this pack expansion into separate arguments yet;
|
||||
// just substitute into the pattern and create a new pack expansion
|
||||
// type.
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
|
||||
QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
|
||||
TemplateArgs,
|
||||
New->getLocation(), New->getDeclName());
|
||||
if (T.isNull())
|
||||
break;
|
||||
|
||||
T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
|
||||
Exceptions.push_back(T);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Substitute into the pack expansion pattern for each template
|
||||
bool Invalid = false;
|
||||
for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx);
|
||||
|
||||
QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
|
||||
TemplateArgs,
|
||||
New->getLocation(), New->getDeclName());
|
||||
if (T.isNull()) {
|
||||
Invalid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Exceptions.push_back(T);
|
||||
}
|
||||
|
||||
if (Invalid)
|
||||
break;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
QualType T
|
||||
= SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
|
||||
New->getLocation(), New->getDeclName());
|
||||
if (T.isNull() ||
|
||||
SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
|
||||
continue;
|
||||
|
||||
Exceptions.push_back(T);
|
||||
}
|
||||
Expr *NoexceptExpr = 0;
|
||||
if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef,
|
||||
Sema::ConstantEvaluated);
|
||||
ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
|
||||
if (E.isUsable())
|
||||
E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());
|
||||
|
||||
if (E.isUsable()) {
|
||||
NoexceptExpr = E.take();
|
||||
if (!NoexceptExpr->isTypeDependent() &&
|
||||
!NoexceptExpr->isValueDependent())
|
||||
NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
|
||||
0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),
|
||||
/*AllowFold*/ false).take();
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild the function type
|
||||
const FunctionProtoType *NewProto
|
||||
= New->getType()->getAs<FunctionProtoType>();
|
||||
assert(NewProto && "Template instantiation without function prototype?");
|
||||
|
||||
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
|
||||
EPI.ExceptionSpecType = Proto->getExceptionSpecType();
|
||||
EPI.NumExceptions = Exceptions.size();
|
||||
EPI.Exceptions = Exceptions.data();
|
||||
EPI.NoexceptExpr = NoexceptExpr;
|
||||
|
||||
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
|
||||
NewProto->arg_type_begin(),
|
||||
NewProto->getNumArgs(),
|
||||
EPI));
|
||||
}
|
||||
|
||||
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Decl) {
|
||||
FunctionDecl *Tmpl = Decl->getTemplateInstantiationPattern();
|
||||
assert(Tmpl && "can't instantiate non-template");
|
||||
|
||||
if (Decl->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
|
||||
!= EST_Uninstantiated)
|
||||
return;
|
||||
|
||||
InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
|
||||
InstantiatingTemplate::ExceptionSpecification());
|
||||
if (Inst)
|
||||
return;
|
||||
|
||||
// Enter the scope of this instantiation. We don't use
|
||||
// PushDeclContext because we don't have a scope.
|
||||
Sema::ContextRAII savedContext(*this, Decl);
|
||||
LocalInstantiationScope Scope(*this);
|
||||
|
||||
MultiLevelTemplateArgumentList TemplateArgs =
|
||||
getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);
|
||||
|
||||
addInstantiatedParametersToScope(*this, Decl, Tmpl, Scope, TemplateArgs);
|
||||
|
||||
const FunctionProtoType *Proto = Tmpl->getType()->castAs<FunctionProtoType>();
|
||||
::InstantiateExceptionSpec(*this, Decl, Proto, TemplateArgs);
|
||||
}
|
||||
|
||||
/// \brief Initializes the common fields of an instantiation function
|
||||
/// declaration (New) from the corresponding fields of its template (Tmpl).
|
||||
///
|
||||
|
@ -2252,135 +2440,32 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
|
|||
assert(Proto && "Function template without prototype?");
|
||||
|
||||
if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {
|
||||
// C++11 [expr.prim.general]p3:
|
||||
// If a declaration declares a member function or member function
|
||||
// template of a class X, the expression this is a prvalue of type
|
||||
// "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
|
||||
// and the end of the function-definition, member-declarator, or
|
||||
// declarator.
|
||||
CXXRecordDecl *ThisContext = 0;
|
||||
unsigned ThisTypeQuals = 0;
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
|
||||
ThisContext = Method->getParent();
|
||||
ThisTypeQuals = Method->getTypeQualifiers();
|
||||
}
|
||||
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
|
||||
SemaRef.getLangOpts().CPlusPlus0x);
|
||||
|
||||
|
||||
// The function has an exception specification or a "noreturn"
|
||||
// attribute. Substitute into each of the exception types.
|
||||
SmallVector<QualType, 4> Exceptions;
|
||||
for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
|
||||
// FIXME: Poor location information!
|
||||
if (const PackExpansionType *PackExpansion
|
||||
= Proto->getExceptionType(I)->getAs<PackExpansionType>()) {
|
||||
// We have a pack expansion. Instantiate it.
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
|
||||
Unexpanded);
|
||||
assert(!Unexpanded.empty() &&
|
||||
"Pack expansion without parameter packs?");
|
||||
|
||||
bool Expand = false;
|
||||
bool RetainExpansion = false;
|
||||
llvm::Optional<unsigned> NumExpansions
|
||||
= PackExpansion->getNumExpansions();
|
||||
if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
|
||||
SourceRange(),
|
||||
Unexpanded,
|
||||
TemplateArgs,
|
||||
Expand,
|
||||
RetainExpansion,
|
||||
NumExpansions))
|
||||
break;
|
||||
|
||||
if (!Expand) {
|
||||
// We can't expand this pack expansion into separate arguments yet;
|
||||
// just substitute into the pattern and create a new pack expansion
|
||||
// type.
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
|
||||
QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
|
||||
TemplateArgs,
|
||||
New->getLocation(), New->getDeclName());
|
||||
if (T.isNull())
|
||||
break;
|
||||
|
||||
T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
|
||||
Exceptions.push_back(T);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Substitute into the pack expansion pattern for each template
|
||||
bool Invalid = false;
|
||||
for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx);
|
||||
|
||||
QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
|
||||
TemplateArgs,
|
||||
New->getLocation(), New->getDeclName());
|
||||
if (T.isNull()) {
|
||||
Invalid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Exceptions.push_back(T);
|
||||
}
|
||||
|
||||
if (Invalid)
|
||||
break;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
QualType T
|
||||
= SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
|
||||
New->getLocation(), New->getDeclName());
|
||||
if (T.isNull() ||
|
||||
SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
|
||||
continue;
|
||||
|
||||
Exceptions.push_back(T);
|
||||
}
|
||||
Expr *NoexceptExpr = 0;
|
||||
if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
|
||||
EnterExpressionEvaluationContext Unevaluated(SemaRef,
|
||||
Sema::ConstantEvaluated);
|
||||
ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
|
||||
if (E.isUsable())
|
||||
E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());
|
||||
|
||||
if (E.isUsable()) {
|
||||
NoexceptExpr = E.take();
|
||||
if (!NoexceptExpr->isTypeDependent() &&
|
||||
!NoexceptExpr->isValueDependent())
|
||||
NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
|
||||
0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),
|
||||
/*AllowFold*/ false).take();
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild the function type
|
||||
|
||||
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
|
||||
EPI.ExceptionSpecType = Proto->getExceptionSpecType();
|
||||
EPI.NumExceptions = Exceptions.size();
|
||||
EPI.Exceptions = Exceptions.data();
|
||||
EPI.NoexceptExpr = NoexceptExpr;
|
||||
EPI.ExtInfo = Proto->getExtInfo();
|
||||
|
||||
const FunctionProtoType *NewProto
|
||||
= New->getType()->getAs<FunctionProtoType>();
|
||||
assert(NewProto && "Template instantiation without function prototype?");
|
||||
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
|
||||
NewProto->arg_type_begin(),
|
||||
NewProto->getNumArgs(),
|
||||
EPI));
|
||||
// DR1330: In C++11, defer instantiation of a non-trivial
|
||||
// exception specification.
|
||||
if (SemaRef.getLangOpts().CPlusPlus0x &&
|
||||
EPI.ExceptionSpecType != EST_None &&
|
||||
EPI.ExceptionSpecType != EST_DynamicNone &&
|
||||
EPI.ExceptionSpecType != EST_BasicNoexcept) {
|
||||
// Mark the function has having an uninstantiated exception specification.
|
||||
const FunctionProtoType *NewProto
|
||||
= New->getType()->getAs<FunctionProtoType>();
|
||||
assert(NewProto && "Template instantiation without function prototype?");
|
||||
EPI = NewProto->getExtProtoInfo();
|
||||
EPI.ExceptionSpecType = EST_Uninstantiated;
|
||||
EPI.ExceptionSpecDecl = New;
|
||||
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
|
||||
NewProto->arg_type_begin(),
|
||||
NewProto->getNumArgs(),
|
||||
EPI));
|
||||
} else {
|
||||
::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
|
||||
}
|
||||
}
|
||||
|
||||
const FunctionDecl* Definition = Tmpl;
|
||||
|
||||
// Get the definition. Leaves the variable unchanged if undefined.
|
||||
const FunctionDecl *Definition = Tmpl;
|
||||
Tmpl->isDefined(Definition);
|
||||
|
||||
SemaRef.InstantiateAttrs(TemplateArgs, Definition, New,
|
||||
|
@ -2538,33 +2623,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
MultiLevelTemplateArgumentList TemplateArgs =
|
||||
getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
|
||||
|
||||
// Introduce the instantiated function parameters into the local
|
||||
// instantiation scope, and set the parameter names to those used
|
||||
// in the template.
|
||||
unsigned FParamIdx = 0;
|
||||
for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
|
||||
const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
|
||||
if (!PatternParam->isParameterPack()) {
|
||||
// Simple case: not a parameter pack.
|
||||
assert(FParamIdx < Function->getNumParams());
|
||||
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||
Scope.InstantiatedLocal(PatternParam, FunctionParam);
|
||||
++FParamIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Expand the parameter pack.
|
||||
Scope.MakeInstantiatedLocalArgPack(PatternParam);
|
||||
unsigned NumArgumentsInExpansion
|
||||
= getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
|
||||
for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {
|
||||
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||
Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
|
||||
++FParamIdx;
|
||||
}
|
||||
}
|
||||
addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
|
||||
TemplateArgs);
|
||||
|
||||
if (PatternDecl->isDefaulted()) {
|
||||
ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
|
||||
|
|
|
@ -4181,10 +4181,7 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
|||
unsigned ThisTypeQuals) {
|
||||
// Transform the parameters and return type.
|
||||
//
|
||||
// We instantiate in source order, with the return type first followed by
|
||||
// the parameters, because users tend to expect this (even if they shouldn't
|
||||
// rely on it!).
|
||||
//
|
||||
// We are required to instantiate the params and return type in source order.
|
||||
// When the function has a trailing return type, we instantiate the
|
||||
// parameters before the return type, since the return type can then refer
|
||||
// to the parameters themselves (via decltype, sizeof, etc.).
|
||||
|
@ -4230,6 +4227,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
|||
return QualType();
|
||||
}
|
||||
|
||||
// FIXME: Need to transform the exception-specification too.
|
||||
|
||||
QualType Result = TL.getType();
|
||||
if (getDerived().AlwaysRebuild() ||
|
||||
ResultType != T->getResultType() ||
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace noexcept_unevaluated {
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void g(T x) noexcept((sizeof(T) == sizeof(int)) || f(x)) { }
|
||||
void g(T x) noexcept((sizeof(T) == sizeof(int)) || noexcept(f(x))) { }
|
||||
|
||||
void h() {
|
||||
g(1);
|
||||
|
@ -77,5 +77,5 @@ namespace PR11084 {
|
|||
static int f() noexcept(1/X) { return 10; } // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}}
|
||||
};
|
||||
|
||||
void g() { A<0>::f(); } // expected-note{{in instantiation of template class 'PR11084::A<0>' requested here}}
|
||||
void g() { A<0>::f(); } // expected-note{{in instantiation of exception specification for 'f' requested here}}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -verify -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
template<typename T> void f() noexcept(sizeof(T) == 4);
|
||||
|
||||
void g() {
|
||||
// CHECK: declare void @_Z1fIiEvv() nounwind
|
||||
f<int>();
|
||||
// CHECK: declare void @_Z1fIA2_iEvv()
|
||||
f<int[2]>();
|
||||
// CHECK: declare void @_Z1fIfEvv() nounwind
|
||||
void (*f1)() = &f<float>;
|
||||
// CHECK: declare void @_Z1fIdEvv()
|
||||
void (*f2)() = &f<double>;
|
||||
// CHECK: declare void @_Z1fIA4_cEvv() nounwind
|
||||
(void)&f<char[4]>;
|
||||
// CHECK: declare void @_Z1fIcEvv()
|
||||
(void)&f<char>;
|
||||
}
|
|
@ -105,3 +105,13 @@ namespace test1 {
|
|||
}
|
||||
template void f(int const &); // expected-note {{requested here}}
|
||||
}
|
||||
|
||||
namespace test2 {
|
||||
template<typename T> void f() {
|
||||
T::error; // expected-error {{no member}}
|
||||
}
|
||||
void g() {
|
||||
// This counts as an odr-use, so should trigger the instantiation of f<int>.
|
||||
(void)&f<int>; // expected-note {{here}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 %s
|
||||
|
||||
// DR1330: an exception specification for a function template is only
|
||||
// instantiated when it is needed.
|
||||
|
||||
template<typename T> void f1(T*) throw(T); // expected-error{{incomplete type 'Incomplete' is not allowed in exception specification}}
|
||||
struct Incomplete; // expected-note{{forward}}
|
||||
|
||||
void test_f1(Incomplete *incomplete_p, int *int_p) {
|
||||
f1(int_p);
|
||||
f1(incomplete_p); // expected-note{{instantiation of exception spec}}
|
||||
}
|
||||
|
||||
template<typename T> struct A {
|
||||
template<typename U> struct B {
|
||||
static void f() noexcept(A<U>().n);
|
||||
};
|
||||
|
||||
constexpr A() : n(true) {}
|
||||
bool n;
|
||||
};
|
||||
|
||||
static_assert(noexcept(A<int>::B<char>::f()), "");
|
||||
|
||||
template<unsigned N> struct S {
|
||||
static void recurse() noexcept(noexcept(S<N+1>::recurse())); // \
|
||||
// expected-error {{no member named 'recurse'}} \
|
||||
// expected-note 9{{instantiation of exception spec}}
|
||||
};
|
||||
decltype(S<0>::recurse()) *pVoid1 = 0; // ok, exception spec not needed
|
||||
decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed
|
||||
|
||||
template<> struct S<10> {};
|
||||
void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}}
|
||||
|
||||
|
||||
template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
|
||||
// expected-error 16{{call to function 'go' that is neither visible}} \
|
||||
// expected-note 16{{'go' should be declared prior to the call site}} \
|
||||
// expected-error {{recursive template instantiation exceeded maximum depth of 16}} \
|
||||
// expected-error {{use of undeclared identifier 'go'}} \
|
||||
|
||||
void f() {
|
||||
int k = go(0); // \
|
||||
// expected-note {{in instantiation of exception specification for 'go<int>' requested here}}
|
||||
}
|
||||
|
||||
|
||||
namespace dr1330_example {
|
||||
template <class T> struct A {
|
||||
void f(...) throw (typename T::X); // expected-error {{'int'}}
|
||||
void f(int);
|
||||
};
|
||||
|
||||
int main() {
|
||||
A<int>().f(42);
|
||||
}
|
||||
|
||||
int test2() {
|
||||
struct S {
|
||||
template<typename T>
|
||||
static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } // \
|
||||
// expected-note {{instantiation of exception spec}}
|
||||
typedef decltype(f<S>()) X;
|
||||
};
|
||||
S().f<S>(); // ok
|
||||
S().f<int>(); // expected-note {{instantiation of exception spec}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace core_19754_example {
|
||||
template<typename T> T declval() noexcept;
|
||||
|
||||
template<typename T, typename = decltype(T(declval<T&&>()))>
|
||||
struct is_movable { static const bool value = true; };
|
||||
|
||||
template<typename T>
|
||||
struct wrap {
|
||||
T val;
|
||||
void irrelevant(wrap &p) noexcept(is_movable<T>::value);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct base {
|
||||
base() {}
|
||||
base(const typename T::type1 &);
|
||||
base(const typename T::type2 &);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct type1 {
|
||||
wrap<typename T::base> base;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct type2 {
|
||||
wrap<typename T::base> base;
|
||||
};
|
||||
|
||||
struct types {
|
||||
typedef base<types> base;
|
||||
typedef type1<types> type1;
|
||||
typedef type2<types> type2;
|
||||
};
|
||||
|
||||
base<types> val = base<types>();
|
||||
}
|
Loading…
Reference in New Issue