summaryrefslogtreecommitdiffstats
path: root/lib
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 /lib
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
Diffstat (limited to 'lib')
-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
12 files changed, 678 insertions, 519 deletions
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>
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:
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 42221f8df4..14b24341d0 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -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
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3e368a3b10..fd54499c9e 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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()) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index e4b40e624c..af86cb2c43 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -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,
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 284c8dec1c..50230f068d 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -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 {
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 60de75b917..128dc2f7ff 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -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 *>();
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8d382d1bac..39c27fc497 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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);
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 5511fc00f5..a66378e517 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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() ||