aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-04-17 00:58:00 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-04-17 00:58:00 +0000
commite6975e9b0985ad7f7ff9187e38d95bfe9ac4181b (patch)
treec68d347ef93340e9e17ee01fc56755561260b697
parent7fea7c81c0970cdb150c1fadb2776dec9fd09780 (diff)
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
-rw-r--r--include/clang/AST/Expr.h10
-rw-r--r--include/clang/AST/Type.h18
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Basic/ExceptionSpecificationType.h18
-rw-r--r--include/clang/Sema/Sema.h29
-rw-r--r--lib/AST/ASTContext.cpp2
-rw-r--r--lib/AST/Expr.cpp325
-rw-r--r--lib/AST/Type.cpp9
-rw-r--r--lib/Analysis/CFG.cpp3
-rw-r--r--lib/Sema/SemaDeclCXX.cpp76
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp359
-rw-r--r--lib/Sema/SemaExpr.cpp7
-rw-r--r--lib/Sema/SemaExprCXX.cpp13
-rw-r--r--lib/Sema/SemaOverload.cpp2
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp32
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp362
-rw-r--r--lib/Sema/TreeTransform.h7
-rw-r--r--test/CXX/except/except.spec/p1.cpp4
-rw-r--r--test/CodeGenCXX/cxx11-exception-spec.cpp18
-rw-r--r--test/SemaTemplate/instantiate-declref.cpp10
-rw-r--r--test/SemaTemplate/instantiate-exception-spec-cxx11.cpp107
21 files changed, 872 insertions, 541 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index a7822fab1c..b0b9b0fd6f 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -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;
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 7bd367c054..9fd4901672 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -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)
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index baaddcfeb2..779af403a6 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h
index 98cfd297ad..e911bde191 100644
--- a/include/clang/Basic/ExceptionSpecificationType.h
+++ b/include/clang/Basic/ExceptionSpecificationType.h
@@ -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
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 7de59e0f5d..c845ee5549 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.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,
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 887beac4b0..65ddc059fa 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -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);
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 9556b1acb9..fcde5429b3 100644
--- a/lib/AST/Expr.cpp
+++ b/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) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index c82aeaadd4..10c1adc875 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -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)
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index f4d9a354a5..2f1f1cb4e4 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -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;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 8fe28e9555..f0f52c7546 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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>