diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-04-16 18:27:27 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-04-16 18:27:27 +0000 |
commit | 74e2fc332e07c76d4e69ccbd0e9e47a0bafd3908 (patch) | |
tree | e13935dca7e6eaa9e934215f7517e99dd591fcb4 /lib | |
parent | 0f90590c96375052c67116f620fafa2b1eadb41e (diff) |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 73 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 17 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 103 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/DeclSpec.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 145 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 51 |
9 files changed, 359 insertions, 60 deletions
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index d2a85355b6..f04d76723b 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -59,7 +59,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, } } - HandleMemberFunctionDefaultArgs(D, FnD); + HandleMemberFunctionDeclDelays(D, FnD); D.complete(FnD); @@ -348,6 +348,77 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { 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 16c90e9b71..932ffb440f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4197,6 +4197,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, SmallVector<ParsedType, 2> DynamicExceptions; SmallVector<SourceRange, 2> DynamicExceptionRanges; ExprResult NoexceptExpr; + CachedTokens *ExceptionSpecTokens = 0; ParsedAttributes FnAttrs(AttrFactory); ParsedType TrailingReturnType; @@ -4265,10 +4266,16 @@ void Parser::ParseFunctionDeclarator(Declarator &D, 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 @@ void Parser::ParseFunctionDeclarator(Declarator &D, DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, + ExceptionSpecTokens, Tracker.getOpenLocation(), EndLoc, D, TrailingReturnType), @@ -4504,7 +4512,6 @@ void Parser::ParseParameterDeclarationClause( // 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 b2a65ff0f3..b9b51d7518 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1534,13 +1534,35 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const { } } -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 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, 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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // 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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (DeclaratorInfo.isFunctionDeclarator() && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) { - HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl); + HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl); } DeclaratorInfo.complete(ThisDecl); @@ -2334,13 +2356,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, 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 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { /// '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 6d31396cc0..b6a027b0d7 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2392,7 +2392,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { 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 ed965115e3..ae6ad0b275 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -780,10 +780,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( 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 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, + 0, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); @@ -863,6 +867,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*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 b531accf86..fe63e359a1 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -162,6 +162,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, + CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, @@ -226,6 +227,10 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, 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 1d4745dcaa..c7bd72b03e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4471,6 +4471,11 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, 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 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { 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 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, 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 f488296336..8fe28e9555 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -11096,6 +11096,25 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) { 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 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) { 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 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { 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 c41df82a48..d0906ded0c 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -561,7 +561,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*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 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, 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; } |