diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 570f60fb94799f..ee08cfc589e123 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1367,7 +1367,7 @@ class Parser : public CodeCompletionHandler { void ParseLexedMethodDeclarations() override; - Parser* Self; + Parser *Self; /// Method - The method declaration. Decl *Method; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index d6b2eb8a9877e2..79628cfed1b2e3 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -6486,6 +6486,10 @@ void Parser::ParseFunctionDeclarator(Declarator &D, InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope); // Parse exception-specification[opt]. + // FIXME: Per [class.mem]p6, all exception-specifications at class scope + // should be delayed, including those for non-members (eg, friend + // declarations). But only applying this to member declarations is + // consistent with what other implementations do. bool Delayed = D.isFirstDeclarationOfMember() && D.isFunctionDeclaratorAFunctionDeclaration(); if (Delayed && Actions.isLibstdcxxEagerExceptionSpecHack(D) && diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 290b3c5df9592e..059d875d683df4 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2186,17 +2186,20 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, auto LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); getCurrentClass().LateParsedDeclarations.push_back(LateMethod); - // Stash the exception-specification tokens in the late-pased method. - LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens; - FTI.ExceptionSpecTokens = nullptr; - - // Push tokens for each parameter. Those that do not have - // defaults will be NULL. + // Push tokens for each parameter. Those that do not have defaults will be + // NULL. We need to track all the parameters so that we can push them into + // scope for later parameters and perhaps for the exception specification. LateMethod->DefaultArgs.reserve(FTI.NumParams); for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) LateMethod->DefaultArgs.push_back(LateParsedDefaultArgument( FTI.Params[ParamIdx].Param, std::move(FTI.Params[ParamIdx].DefaultArgTokens))); + + // Stash the exception-specification tokens in the late-pased method. + if (FTI.getExceptionSpecType() == EST_Unparsed) { + LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens; + FTI.ExceptionSpecTokens = nullptr; + } } } diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp index 4ddcb8ccfd0fe5..8be98d6ef29989 100644 --- a/clang/test/Parser/cxx0x-decl.cpp +++ b/clang/test/Parser/cxx0x-decl.cpp @@ -199,6 +199,11 @@ namespace AliasDeclEndLocation { B something_else; } +class PR47176 { + friend void f(PR47176, int = 0) noexcept(true) {} +}; +static_assert(noexcept(f(PR47176())), ""); + struct Base { virtual void f() = 0; virtual void g() = 0; virtual void h() = 0; }; struct MemberComponentOrder : Base { void f() override __asm__("foobar") __attribute__(( )) {}