Implement the last part of C++ [class.mem]p2, delaying the parsing of
exception specifications on member functions until after the closing
'}' for the containing class. This allows, for example, a member
function to throw an instance of its own class. Fixes PR12564 and a
fairly embarassing oversight in our C++98/03 support.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154844 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index d2a8535..f04d767 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -59,7 +59,7 @@
}
}
- HandleMemberFunctionDefaultArgs(D, FnD);
+ HandleMemberFunctionDeclDelays(D, FnD);
D.complete(FnD);
@@ -348,6 +348,77 @@
LM.DefaultArgs[I].Toks = 0;
}
}
+
+ // Parse a delayed exception-specification, if there is one.
+ if (CachedTokens *Toks = LM.ExceptionSpecTokens) {
+ // Save the current token position.
+ SourceLocation origLoc = Tok.getLocation();
+
+ // Parse the default argument from its saved token stream.
+ Toks->push_back(Tok); // So that the current token doesn't get lost
+ PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
+
+ // Consume the previously-pushed token.
+ ConsumeAnyToken();
+
+ // 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.
+ CXXMethodDecl *Method;
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(LM.Method))
+ Method = cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = cast<CXXMethodDecl>(LM.Method);
+
+ Sema::CXXThisScopeRAII ThisScope(Actions, Method->getParent(),
+ Method->getTypeQualifiers(),
+ getLangOpts().CPlusPlus0x);
+
+ // Parse the exception-specification.
+ SourceRange SpecificationRange;
+ SmallVector<ParsedType, 4> DynamicExceptions;
+ SmallVector<SourceRange, 4> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
+ CachedTokens *ExceptionSpecTokens;
+
+ ExceptionSpecificationType EST
+ = tryParseExceptionSpecification(/*Delayed=*/false, SpecificationRange,
+ DynamicExceptions,
+ DynamicExceptionRanges, NoexceptExpr,
+ ExceptionSpecTokens);
+
+ // Clean up the remaining tokens.
+ if (Tok.is(tok::cxx_exceptspec_end))
+ ConsumeToken();
+ else if (EST != EST_None)
+ Diag(Tok.getLocation(), diag::err_except_spec_unparsed);
+
+ // Attach the exception-specification to the method.
+ if (EST != EST_None)
+ Actions.actOnDelayedExceptionSpecification(LM.Method, EST,
+ SpecificationRange,
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr.isUsable()?
+ NoexceptExpr.get() : 0);
+
+ assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
+ Tok.getLocation()) &&
+ "tryParseExceptionSpecification went over the exception tokens!");
+
+ // There could be leftover tokens (e.g. because of an error).
+ // Skip through until we reach the original token position.
+ while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ delete LM.ExceptionSpecTokens;
+ LM.ExceptionSpecTokens = 0;
+ }
+
PrototypeScope.Exit();
// Finish the delayed C++ method declaration.
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 16c90e9..932ffb4 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -4197,6 +4197,7 @@
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
+ CachedTokens *ExceptionSpecTokens = 0;
ParsedAttributes FnAttrs(AttrFactory);
ParsedType TrailingReturnType;
@@ -4265,10 +4266,16 @@
IsCXX11MemberFunction);
// Parse exception-specification[opt].
- ESpecType = MaybeParseExceptionSpecification(ESpecRange,
- DynamicExceptions,
- DynamicExceptionRanges,
- NoexceptExpr);
+ bool Delayed = (D.getContext() == Declarator::MemberContext &&
+ D.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_typedef &&
+ !D.getDeclSpec().isFriendSpecified());
+ ESpecType = tryParseExceptionSpecification(Delayed,
+ ESpecRange,
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr,
+ ExceptionSpecTokens);
if (ESpecType != EST_None)
EndLoc = ESpecRange.getEnd();
@@ -4303,6 +4310,7 @@
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : 0,
+ ExceptionSpecTokens,
Tracker.getOpenLocation(),
EndLoc, D,
TrailingReturnType),
@@ -4504,7 +4512,6 @@
// If we're inside a class definition, cache the tokens
// corresponding to the default argument. We'll actually parse
// them when we see the end of the class definition.
- // FIXME: Templates will require something similar.
// FIXME: Can we use a smart pointer for Toks?
DefArgToks = new CachedTokens;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index b2a65ff..b9b51d7 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1534,13 +1534,35 @@
}
}
-void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
- Decl *ThisDecl) {
+/// \brief If the given declarator has any parts for which parsing has to be
+/// delayed, e.g., default arguments or an exception-specification, create a
+/// late-parsed method declaration record to handle the parsing at the end of
+/// the class definition.
+void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
+ Decl *ThisDecl) {
// We just declared a member function. If this member function
- // has any default arguments, we'll need to parse them later.
+ // has any default arguments or an exception-specification, we'll need to
+ // parse them later.
LateParsedMethodDeclaration *LateMethod = 0;
DeclaratorChunk::FunctionTypeInfo &FTI
= DeclaratorInfo.getFunctionTypeInfo();
+
+ // If there was a delayed exception-specification, hold onto its tokens.
+ if (FTI.getExceptionSpecType() == EST_Delayed) {
+ // Push this method onto the stack of late-parsed method
+ // declarations.
+ LateMethod = new LateParsedMethodDeclaration(this, ThisDecl);
+ getCurrentClass().LateParsedDeclarations.push_back(LateMethod);
+ LateMethod->TemplateScope = getCurScope()->isTemplateParamScope();
+
+ // Stash the exception-specification tokens in the late-pased mthod.
+ LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens;
+ FTI.ExceptionSpecTokens = 0;
+
+ // Reserve space for the parameters.
+ LateMethod->DefaultArgs.reserve(FTI.NumArgs);
+ }
+
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) {
if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) {
if (!LateMethod) {
@@ -1558,7 +1580,7 @@
LateParsedDefaultArgument(FTI.ArgInfo[I].Param));
}
- // Add this parameter to the list of parameters (it or may
+ // Add this parameter to the list of parameters (it may or may
// not have a default argument).
LateMethod->DefaultArgs.push_back(
LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param,
@@ -1824,7 +1846,7 @@
// Parse the first declarator.
ParseDeclarator(DeclaratorInfo);
- // Error parsing the declarator?
+ // Error parsin g the declarator?
if (!DeclaratorInfo.hasName()) {
// If so, skip until the semi-colon or a }.
SkipUntil(tok::r_brace, true, true);
@@ -2046,7 +2068,7 @@
if (DeclaratorInfo.isFunctionDeclarator() &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_typedef) {
- HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl);
+ HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl);
}
DeclaratorInfo.complete(ThisDecl);
@@ -2334,13 +2356,11 @@
T.getCloseLocation(),
attrs.getList());
- // C++0x [class.mem]p2: Within the class member-specification, the class is
- // regarded as complete within function bodies, default arguments, exception-
- // specifications, and brace-or-equal-initializers for non-static data
- // members (including such things in nested classes).
- //
- // FIXME: Only function bodies and brace-or-equal-initializers are currently
- // handled. Fix the others!
+ // C++11 [class.mem]p2:
+ // Within the class member-specification, the class is regarded as complete
+ // within function bodies, default arguments, exception-specifications, and
+ // brace-or-equal-initializers for non-static data members (including such
+ // things in nested classes).
if (TagDecl && NonNestedClass) {
// We are not inside a nested class. This class and its nested classes
// are complete and we can parse the delayed portions of method
@@ -2535,12 +2555,63 @@
/// 'noexcept'
/// 'noexcept' '(' constant-expression ')'
ExceptionSpecificationType
-Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange,
+Parser::tryParseExceptionSpecification(bool Delayed,
+ SourceRange &SpecificationRange,
SmallVectorImpl<ParsedType> &DynamicExceptions,
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
- ExprResult &NoexceptExpr) {
+ ExprResult &NoexceptExpr,
+ CachedTokens *&ExceptionSpecTokens) {
ExceptionSpecificationType Result = EST_None;
+ ExceptionSpecTokens = 0;
+
+ // Handle delayed parsing of exception-specifications.
+ if (Delayed) {
+ if (Tok.isNot(tok::kw_throw) && Tok.isNot(tok::kw_noexcept))
+ return EST_None;
+ // Consume and cache the starting token.
+ bool IsNoexcept = Tok.is(tok::kw_noexcept);
+ Token StartTok = Tok;
+ SpecificationRange = SourceRange(ConsumeToken());
+
+ // Check for a '('.
+ if (!Tok.is(tok::l_paren)) {
+ // If this is a bare 'noexcept', we're done.
+ if (IsNoexcept) {
+ Diag(Tok, diag::warn_cxx98_compat_noexcept_decl);
+ NoexceptExpr = 0;
+ return EST_BasicNoexcept;
+ }
+
+ Diag(Tok, diag::err_expected_lparen_after) << "throw";
+ return EST_DynamicNone;
+ }
+
+ // Cache the tokens for the exception-specification.
+ ExceptionSpecTokens = new CachedTokens;
+ ExceptionSpecTokens->push_back(StartTok); // 'throw' or 'noexcept'
+ ExceptionSpecTokens->push_back(Tok); // '('
+ SpecificationRange.setEnd(ConsumeParen()); // '('
+
+ if (!ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/true)) {
+ NoexceptExpr = 0;
+ delete ExceptionSpecTokens;
+ ExceptionSpecTokens = 0;
+ return IsNoexcept? EST_BasicNoexcept : EST_DynamicNone;
+ }
+ SpecificationRange.setEnd(Tok.getLocation());
+
+ // Add the 'stop' token.
+ Token End;
+ End.startToken();
+ End.setKind(tok::cxx_exceptspec_end);
+ End.setLocation(Tok.getLocation());
+ ExceptionSpecTokens->push_back(End);
+ return EST_Delayed;
+ }
+
// See if there's a dynamic specification.
if (Tok.is(tok::kw_throw)) {
Result = ParseDynamicExceptionSpecification(SpecificationRange,
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 6d31396..b6a027b 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -2392,7 +2392,7 @@
SourceLocation(),
EST_None,
SourceLocation(),
- 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
CaretLoc, CaretLoc,
ParamInfo),
attrs, CaretLoc);
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index ed96511..ae6ad0b 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -780,10 +780,13 @@
llvm::SmallVector<ParsedType, 2> DynamicExceptions;
llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
- ESpecType = MaybeParseExceptionSpecification(ESpecRange,
- DynamicExceptions,
- DynamicExceptionRanges,
- NoexceptExpr);
+ CachedTokens *ExceptionSpecTokens;
+ ESpecType = tryParseExceptionSpecification(/*Delayed=*/false,
+ ESpecRange,
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr,
+ ExceptionSpecTokens);
if (ESpecType != EST_None)
DeclEndLoc = ESpecRange.getEnd();
@@ -818,6 +821,7 @@
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : 0,
+ 0,
DeclLoc, DeclEndLoc, D,
TrailingReturnType),
Attr, DeclEndLoc);
@@ -863,6 +867,7 @@
/*ExceptionRanges=*/0,
/*NumExceptions=*/0,
/*NoexceptExpr=*/0,
+ /*ExceptionSpecTokens=*/0,
DeclLoc, DeclEndLoc, D,
TrailingReturnType),
Attr, DeclEndLoc);
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index b531acc..fe63e35 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -162,6 +162,7 @@
SourceRange *ExceptionRanges,
unsigned NumExceptions,
Expr *NoexceptExpr,
+ CachedTokens *ExceptionSpecTokens,
SourceLocation LocalRangeBegin,
SourceLocation LocalRangeEnd,
Declarator &TheDeclarator,
@@ -226,6 +227,10 @@
case EST_ComputedNoexcept:
I.Fun.NoexceptExpr = NoexceptExpr;
break;
+
+ case EST_Delayed:
+ I.Fun.ExceptionSpecTokens = ExceptionSpecTokens;
+ break;
}
return I;
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1d4745d..c7bd72b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4471,6 +4471,11 @@
return false;
}
+static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) {
+ const FunctionProtoType *Proto =Method->getType()->getAs<FunctionProtoType>();
+ return Proto && Proto->getExceptionSpecType() == EST_Delayed;
+}
+
/// AddOverriddenMethods - See if a method overrides any in the base classes,
/// and if so, check that it's a valid override and remember it.
bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -4486,7 +4491,8 @@
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
MD->addOverriddenMethod(OldMD->getCanonicalDecl());
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
- !CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
+ (hasDelayedExceptionSpec(MD) ||
+ !CheckOverridingFunctionExceptionSpec(MD, OldMD)) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
AddedAny = true;
}
@@ -7626,7 +7632,7 @@
SourceLocation(), SourceLocation(),
SourceLocation(),
EST_None, SourceLocation(),
- 0, 0, 0, 0, Loc, Loc, D),
+ 0, 0, 0, 0, 0, Loc, Loc, D),
DS.getAttributes(),
SourceLocation());
D.SetIdentifier(&II, Loc);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f488296..8fe28e9 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -11096,6 +11096,25 @@
return true;
// Check the exception specification.
+ if (checkThisInStaticMemberFunctionExceptionSpec(Method))
+ return true;
+
+ return checkThisInStaticMemberFunctionAttributes(Method);
+}
+
+bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
+ TypeSourceInfo *TSInfo = Method->getTypeSourceInfo();
+ if (!TSInfo)
+ return false;
+
+ TypeLoc TL = TSInfo->getTypeLoc();
+ FunctionProtoTypeLoc *ProtoTL = dyn_cast<FunctionProtoTypeLoc>(&TL);
+ if (!ProtoTL)
+ return false;
+
+ const FunctionProtoType *Proto = ProtoTL->getTypePtr();
+ FindCXXThisExpr Finder(*this);
+
switch (Proto->getExceptionSpecType()) {
case EST_BasicNoexcept:
case EST_Delayed:
@@ -11103,22 +11122,22 @@
case EST_MSAny:
case EST_None:
break;
-
+
case EST_ComputedNoexcept:
if (!Finder.TraverseStmt(Proto->getNoexceptExpr()))
return true;
-
+
case EST_Dynamic:
for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
- EEnd = Proto->exception_end();
+ EEnd = Proto->exception_end();
E != EEnd; ++E) {
if (!Finder.TraverseType(*E))
return true;
}
break;
}
-
- return checkThisInStaticMemberFunctionAttributes(Method);
+
+ return false;
}
bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
@@ -11177,6 +11196,122 @@
return false;
}
+void
+Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
+ ArrayRef<ParsedType> DynamicExceptions,
+ ArrayRef<SourceRange> DynamicExceptionRanges,
+ Expr *NoexceptExpr,
+ llvm::SmallVectorImpl<QualType> &Exceptions,
+ FunctionProtoType::ExtProtoInfo &EPI) {
+ Exceptions.clear();
+ EPI.ExceptionSpecType = EST;
+ if (EST == EST_Dynamic) {
+ Exceptions.reserve(DynamicExceptions.size());
+ for (unsigned ei = 0, ee = DynamicExceptions.size(); ei != ee; ++ei) {
+ // FIXME: Preserve type source info.
+ QualType ET = GetTypeFromParser(DynamicExceptions[ei]);
+
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ collectUnexpandedParameterPacks(ET, Unexpanded);
+ if (!Unexpanded.empty()) {
+ DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(),
+ UPPC_ExceptionType,
+ Unexpanded);
+ continue;
+ }
+
+ // Check that the type is valid for an exception spec, and
+ // drop it if not.
+ if (!CheckSpecifiedExceptionType(ET, DynamicExceptionRanges[ei]))
+ Exceptions.push_back(ET);
+ }
+ EPI.NumExceptions = Exceptions.size();
+ EPI.Exceptions = Exceptions.data();
+ return;
+ }
+
+ if (EST == EST_ComputedNoexcept) {
+ // If an error occurred, there's no expression here.
+ if (NoexceptExpr) {
+ assert((NoexceptExpr->isTypeDependent() ||
+ NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
+ Context.BoolTy) &&
+ "Parser should have made sure that the expression is boolean");
+ if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) {
+ EPI.ExceptionSpecType = EST_BasicNoexcept;
+ return;
+ }
+
+ if (!NoexceptExpr->isValueDependent())
+ NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, 0,
+ PDiag(diag::err_noexcept_needs_constant_expression),
+ /*AllowFold*/ false).take();
+ EPI.NoexceptExpr = NoexceptExpr;
+ }
+ return;
+ }
+}
+
+void Sema::actOnDelayedExceptionSpecification(Decl *MethodD,
+ ExceptionSpecificationType EST,
+ SourceRange SpecificationRange,
+ ArrayRef<ParsedType> DynamicExceptions,
+ ArrayRef<SourceRange> DynamicExceptionRanges,
+ Expr *NoexceptExpr) {
+ if (!MethodD)
+ return;
+
+ // Dig out the method we're referring to.
+ CXXMethodDecl *Method = 0;
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(MethodD))
+ Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = dyn_cast<CXXMethodDecl>(MethodD);
+
+ if (!Method)
+ return;
+
+ // Dig out the prototype. This should never fail.
+ const FunctionProtoType *Proto
+ = dyn_cast<FunctionProtoType>(Method->getType());
+ if (!Proto)
+ return;
+
+ // Check the exception specification.
+ llvm::SmallVector<QualType, 4> Exceptions;
+ FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
+ checkExceptionSpecification(EST, DynamicExceptions, DynamicExceptionRanges,
+ NoexceptExpr, Exceptions, EPI);
+
+ // Rebuild the function type.
+ QualType T = Context.getFunctionType(Proto->getResultType(),
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ EPI);
+ if (TypeSourceInfo *TSInfo = Method->getTypeSourceInfo()) {
+ // FIXME: When we get proper type location information for exceptions,
+ // we'll also have to rebuild the TypeSourceInfo. For now, we just patch
+ // up the TypeSourceInfo;
+ assert(TypeLoc::getFullDataSizeForType(T)
+ == TypeLoc::getFullDataSizeForType(Method->getType()) &&
+ "TypeLoc size mismatch with delayed exception specification");
+ TSInfo->overrideType(T);
+ }
+
+ Method->setType(T);
+
+ if (Method->isStatic())
+ checkThisInStaticMemberFunctionExceptionSpec(Method);
+
+ if (Method->isVirtual()) {
+ // Check overrides, which we previously had to delay.
+ for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(),
+ OEnd = Method->end_overridden_methods();
+ O != OEnd; ++O)
+ CheckOverridingFunctionExceptionSpec(Method, *O);
+ }
+}
+
/// IdentifyCUDATarget - Determine the CUDA compilation target for this function
Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
// Implicitly declared functions (e.g. copy constructors) are
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index c41df82..d0906de 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -561,7 +561,7 @@
/*const qualifier*/SourceLocation(),
/*volatile qualifier*/SourceLocation(),
/*mutable qualifier*/SourceLocation(),
- /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0,
+ /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, 0,
/*parens*/ loc, loc,
declarator));
@@ -2371,34 +2371,33 @@
EPI.ConsumedArguments = ConsumedArguments.data();
SmallVector<QualType, 4> Exceptions;
- EPI.ExceptionSpecType = FTI.getExceptionSpecType();
+ SmallVector<ParsedType, 2> DynamicExceptions;
+ SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ Expr *NoexceptExpr = 0;
+
if (FTI.getExceptionSpecType() == EST_Dynamic) {
- Exceptions.reserve(FTI.NumExceptions);
- for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
- // FIXME: Preserve type source info.
- QualType ET = S.GetTypeFromParser(FTI.Exceptions[ei].Ty);
- // Check that the type is valid for an exception spec, and
- // drop it if not.
- if (!S.CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range))
- Exceptions.push_back(ET);
+ // FIXME: It's rather inefficient to have to split into two vectors
+ // here.
+ unsigned N = FTI.NumExceptions;
+ DynamicExceptions.reserve(N);
+ DynamicExceptionRanges.reserve(N);
+ for (unsigned I = 0; I != N; ++I) {
+ DynamicExceptions.push_back(FTI.Exceptions[I].Ty);
+ DynamicExceptionRanges.push_back(FTI.Exceptions[I].Range);
}
- EPI.NumExceptions = Exceptions.size();
- EPI.Exceptions = Exceptions.data();
} else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) {
- // If an error occurred, there's no expression here.
- if (Expr *NoexceptExpr = FTI.NoexceptExpr) {
- assert((NoexceptExpr->isTypeDependent() ||
- NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
- Context.BoolTy) &&
- "Parser should have made sure that the expression is boolean");
- if (!NoexceptExpr->isValueDependent())
- NoexceptExpr = S.VerifyIntegerConstantExpression(NoexceptExpr, 0,
- S.PDiag(diag::err_noexcept_needs_constant_expression),
- /*AllowFold*/ false).take();
- EPI.NoexceptExpr = NoexceptExpr;
- }
- } else if (FTI.getExceptionSpecType() == EST_None &&
- ImplicitlyNoexcept && chunkIndex == 0) {
+ NoexceptExpr = FTI.NoexceptExpr;
+ }
+
+ S.checkExceptionSpecification(FTI.getExceptionSpecType(),
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr,
+ Exceptions,
+ EPI);
+
+ if (FTI.getExceptionSpecType() == EST_None &&
+ ImplicitlyNoexcept && chunkIndex == 0) {
// Only the outermost chunk is marked noexcept, of course.
EPI.ExceptionSpecType = EST_BasicNoexcept;
}