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