diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 56 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Parse/ParseCXXInlineMethods.cpp | 70 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 82 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 46 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 6 |
13 files changed, 313 insertions, 50 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index ae72c5853ce..1804c006476 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2111,6 +2111,62 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, L->DeducedReturnType(FD, ResultType); } +/// Get a function type and produce the equivalent function type with the +/// specified exception specification. Type sugar that can be present on a +/// declaration of a function with an exception specification is permitted +/// and preserved. Other type sugar (for instance, typedefs) is not. +static QualType getFunctionTypeWithExceptionSpec( + ASTContext &Context, QualType Orig, + const FunctionProtoType::ExceptionSpecInfo &ESI) { + // Might have some parens. + if (auto *PT = dyn_cast<ParenType>(Orig)) + return Context.getParenType( + getFunctionTypeWithExceptionSpec(Context, PT->getInnerType(), ESI)); + + // Might have a calling-convention attribute. + if (auto *AT = dyn_cast<AttributedType>(Orig)) + return Context.getAttributedType( + AT->getAttrKind(), + getFunctionTypeWithExceptionSpec(Context, AT->getModifiedType(), ESI), + getFunctionTypeWithExceptionSpec(Context, AT->getEquivalentType(), + ESI)); + + // Anything else must be a function type. Rebuild it with the new exception + // specification. + const FunctionProtoType *Proto = cast<FunctionProtoType>(Orig); + return Context.getFunctionType( + Proto->getReturnType(), Proto->getParamTypes(), + Proto->getExtProtoInfo().withExceptionSpec(ESI)); +} + +void ASTContext::adjustExceptionSpec( + FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI, + bool AsWritten) { + // Update the type. + QualType Updated = + getFunctionTypeWithExceptionSpec(*this, FD->getType(), ESI); + FD->setType(Updated); + + if (!AsWritten) + return; + + // Update the type in the type source information too. + if (TypeSourceInfo *TSInfo = FD->getTypeSourceInfo()) { + // If the type and the type-as-written differ, we may need to update + // the type-as-written too. + if (TSInfo->getType() != FD->getType()) + Updated = getFunctionTypeWithExceptionSpec(*this, TSInfo->getType(), ESI); + + // 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(Updated) == + TypeLoc::getFullDataSizeForType(TSInfo->getType()) && + "TypeLoc size mismatch from updating exception specification"); + TSInfo->overrideType(Updated); + } +} + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType ASTContext::getComplexType(QualType T) const { diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 19a3add700d..abceb8af41f 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1593,7 +1593,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, QualType canonical, const ExtProtoInfo &epi) - : FunctionType(FunctionProto, result, epi.TypeQuals, canonical, + : FunctionType(FunctionProto, result, canonical, result->isDependentType(), result->isInstantiationDependentType(), result->isVariablyModifiedType(), @@ -1602,10 +1602,12 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, NumExceptions(epi.ExceptionSpec.Exceptions.size()), ExceptionSpecType(epi.ExceptionSpec.Type), HasAnyConsumedParams(epi.ConsumedParameters != nullptr), - Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn), - RefQualifier(epi.RefQualifier) { + Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn) { assert(NumParams == params.size() && "function has too many parameters"); + FunctionTypeBits.TypeQuals = epi.TypeQuals; + FunctionTypeBits.RefQualifier = epi.RefQualifier; + // Fill in the trailing argument array. QualType *argSlot = reinterpret_cast<QualType*>(this+1); for (unsigned i = 0; i != NumParams; ++i) { @@ -1772,7 +1774,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, assert(!(unsigned(epi.Variadic) & ~1) && !(unsigned(epi.TypeQuals) & ~255) && !(unsigned(epi.RefQualifier) & ~3) && - !(unsigned(epi.ExceptionSpec.Type) & ~7) && + !(unsigned(epi.ExceptionSpec.Type) & ~15) && "Values larger than expected."); ID.AddInteger(unsigned(epi.Variadic) + (epi.TypeQuals << 1) + diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 3571d5ab413..2a2f3b10461 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -366,6 +366,76 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { } } + // 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().CPlusPlus11); + + // 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() : nullptr); + + 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 Toks; + LM.ExceptionSpecTokens = nullptr; + } + PrototypeScope.Exit(); // Finish the delayed C++ method declaration. diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 66b98c2c4da..8fbe7833a1f 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5193,6 +5193,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, SmallVector<ParsedType, 2> DynamicExceptions; SmallVector<SourceRange, 2> DynamicExceptionRanges; ExprResult NoexceptExpr; + CachedTokens *ExceptionSpecTokens = 0; ParsedAttributes FnAttrs(AttrFactory); TypeResult TrailingReturnType; @@ -5279,10 +5280,14 @@ void Parser::ParseFunctionDeclarator(Declarator &D, IsCXX11MemberFunction); // Parse exception-specification[opt]. - ESpecType = tryParseExceptionSpecification(ESpecRange, + bool Delayed = D.isFirstDeclarationOfMember() && + D.isFunctionDeclaratorAFunctionDeclaration(); + ESpecType = tryParseExceptionSpecification(Delayed, + ESpecRange, DynamicExceptions, DynamicExceptionRanges, - NoexceptExpr); + NoexceptExpr, + ExceptionSpecTokens); if (ESpecType != EST_None) EndLoc = ESpecRange.getEnd(); @@ -5322,6 +5327,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, + ExceptionSpecTokens, StartLoc, LocalEndLoc, D, TrailingReturnType), FnAttrs, EndLoc); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 7c98d70b683..91c1372c633 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1875,16 +1875,34 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const { } /// \brief If the given declarator has any parts for which parsing has to be -/// delayed, e.g., default arguments, create a late-parsed method declaration -/// record to handle the parsing at the end of the class definition. +/// 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 = nullptr; DeclaratorChunk::FunctionTypeInfo &FTI = DeclaratorInfo.getFunctionTypeInfo(); + // If there was a late-parsed exception-specification, hold onto its tokens. + if (FTI.getExceptionSpecType() == EST_Unparsed) { + // 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.NumParams); + } + for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) { if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) { if (!LateMethod) { @@ -2857,7 +2875,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // C++11 [class.mem]p2: // Within the class member-specification, the class is regarded as complete - // within function bodies, default arguments, and + // 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) { @@ -3076,13 +3094,63 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { /// 'noexcept' /// 'noexcept' '(' constant-expression ')' ExceptionSpecificationType -Parser::tryParseExceptionSpecification( +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_Unparsed; + } + // See if there's a dynamic specification. if (Tok.is(tok::kw_throw)) { Result = ParseDynamicExceptionSpecification(SpecificationRange, diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index f4eef811755..b4ba0bc8d8c 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -2642,6 +2642,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, + /*ExceptionSpecTokens=*/nullptr, CaretLoc, CaretLoc, ParamInfo), attrs, CaretLoc); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 33ebb197704..fbe5de14167 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1061,10 +1061,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( SmallVector<ParsedType, 2> DynamicExceptions; SmallVector<SourceRange, 2> DynamicExceptionRanges; ExprResult NoexceptExpr; - ESpecType = tryParseExceptionSpecification(ESpecRange, + CachedTokens *ExceptionSpecTokens; + ESpecType = tryParseExceptionSpecification(/*Delayed=*/false, + ESpecRange, DynamicExceptions, DynamicExceptionRanges, - NoexceptExpr); + NoexceptExpr, + ExceptionSpecTokens); if (ESpecType != EST_None) DeclEndLoc = ESpecRange.getEnd(); @@ -1105,6 +1108,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, + /*ExceptionSpecTokens*/nullptr, LParenLoc, FunLocalRangeEnd, D, TrailingReturnType), Attr, DeclEndLoc); @@ -1173,6 +1177,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, + /*ExceptionSpecTokens=*/nullptr, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 6e77d2769fa..7b2e7ffbaa4 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -182,6 +182,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, + CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, @@ -219,6 +220,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, TrailingReturnType.isInvalid(); I.Fun.TrailingReturnType = TrailingReturnType.get(); + assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow"); + assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow"); + // new[] a parameter array if needed. if (NumParams) { // If the 'InlineParams' in Declarator is unused and big enough, put our @@ -255,6 +259,10 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, case EST_ComputedNoexcept: I.Fun.NoexceptExpr = NoexceptExpr; break; + + case EST_Unparsed: + I.Fun.ExceptionSpecTokens = ExceptionSpecTokens; + break; } return I; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 109c01c8892..bc4d458aca9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10682,6 +10682,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, + /*ExceptionSpecTokens=*/nullptr, Loc, Loc, D), DS.getAttributes(), SourceLocation()); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d4cb2fe3504..925bd99051e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5286,6 +5286,12 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { /// C++11 [dcl.fct.def.default]p2. void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) { + // If the exception specification was explicitly specified but hadn't been + // parsed when the method was defaulted, grab it now. + if (SpecifiedType->getExceptionSpecType() == EST_Unparsed) + SpecifiedType = + MD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); + // Compute the implicit exception specification. CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false, /*IsCXXMethod=*/true); @@ -13245,6 +13251,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { FindCXXThisExpr Finder(*this); switch (Proto->getExceptionSpecType()) { + case EST_Unparsed: case EST_Uninstantiated: case EST_Unevaluated: case EST_BasicNoexcept: @@ -13372,6 +13379,45 @@ void Sema::checkExceptionSpecification( } } +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. + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(MethodD)) + MethodD = FunTmpl->getTemplatedDecl(); + + CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(MethodD); + if (!Method) + return; + + // Check the exception specification. + llvm::SmallVector<QualType, 4> Exceptions; + FunctionProtoType::ExceptionSpecInfo ESI; + checkExceptionSpecification(/*IsTopLevel*/true, EST, DynamicExceptions, + DynamicExceptionRanges, NoexceptExpr, Exceptions, + ESI); + + // Update the exception specification on the function type. + Context.adjustExceptionSpec(Method, ESI, /*AsWritten*/true); + + 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); + } +} + /// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class. /// MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index abac6134cc9..c35de6b8eda 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -112,6 +112,11 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { const FunctionProtoType * Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { + if (FPT->getExceptionSpecType() == EST_Unparsed) { + Diag(Loc, diag::err_exception_spec_not_parsed); + return nullptr; + } + if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) return FPT; @@ -135,16 +140,8 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { void Sema::UpdateExceptionSpec(FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI) { - for (auto *Redecl : FD->redecls()) { - auto *RedeclFD = dyn_cast<FunctionDecl>(Redecl); - const FunctionProtoType *Proto = - RedeclFD->getType()->castAs<FunctionProtoType>(); - - // Overwrite the exception spec and rebuild the function type. - RedeclFD->setType(Context.getFunctionType( - Proto->getReturnType(), Proto->getParamTypes(), - Proto->getExtProtoInfo().withExceptionSpec(ESI))); - } + for (auto *Redecl : FD->redecls()) + Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); // If we've fully resolved the exception specification, notify listeners. if (!isUnresolvedExceptionSpec(ESI.Type)) @@ -790,6 +787,11 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, return false; } } + // If the exception specification hasn't been parsed yet, skip the check. + // We'll get called again once it's been parsed. + if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == + EST_Unparsed) + return false; unsigned DiagID = diag::err_override_exception_spec; if (getLangOpts().MicrosoftExt) DiagID = diag::ext_override_exception_spec; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 87bc3140ae7..8c2f917cfdb 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -661,27 +661,27 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, // ...and *prepend* it to the declarator. SourceLocation NoLoc; declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction( - /*HasProto=*/true, - /*IsAmbiguous=*/false, - /*LParenLoc=*/NoLoc, - /*ArgInfo=*/nullptr, - /*NumArgs=*/0, - /*EllipsisLoc=*/NoLoc, - /*RParenLoc=*/NoLoc, - /*TypeQuals=*/0, - /*RefQualifierIsLvalueRef=*/true, - /*RefQualifierLoc=*/NoLoc, - /*ConstQualifierLoc=*/NoLoc, - /*VolatileQualifierLoc=*/NoLoc, - /*RestrictQualifierLoc=*/NoLoc, - /*MutableLoc=*/NoLoc, - EST_None, - /*ESpecLoc=*/NoLoc, - /*Exceptions=*/nullptr, - /*ExceptionRanges=*/nullptr, - /*NumExceptions=*/0, - /*NoexceptExpr=*/nullptr, - loc, loc, declarator)); + /*HasProto=*/true, + /*IsAmbiguous=*/false, + /*LParenLoc=*/NoLoc, + /*ArgInfo=*/nullptr, + /*NumArgs=*/0, + /*EllipsisLoc=*/NoLoc, + /*RParenLoc=*/NoLoc, + /*TypeQuals=*/0, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, + /*RestrictQualifierLoc=*/NoLoc, + /*MutableLoc=*/NoLoc, EST_None, + /*ESpecLoc=*/NoLoc, + /*Exceptions=*/nullptr, + /*ExceptionRanges=*/nullptr, + /*NumExceptions=*/0, + /*NoexceptExpr=*/nullptr, + /*ExceptionSpecTokens=*/nullptr, + loc, loc, declarator)); // For consistency, make sure the state still has us as processing // the decl spec. diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 0fbbf18c23b..75ac2c34227 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2782,10 +2782,8 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, if (FPT && PrevFPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) && !isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType())) { - FunctionProtoType::ExtProtoInfo EPI = PrevFPT->getExtProtoInfo(); - FD->setType(Reader.Context.getFunctionType( - FPT->getReturnType(), FPT->getParamTypes(), - FPT->getExtProtoInfo().withExceptionSpec(EPI.ExceptionSpec))); + Reader.Context.adjustExceptionSpec( + FD, PrevFPT->getExtProtoInfo().ExceptionSpec); } } } |