From d54eb4410330383f48d3cc22b2ad8d23f120836b Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 12 Oct 2010 16:25:54 +0000 Subject: [PATCH] Parse default arguments within member functions in source order, from Manuel Klimek! Fixes PR7715. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116311 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 85 +++++--- lib/Frontend/ASTUnit.cpp | 1 + lib/Parse/ParseCXXInlineMethods.cpp | 294 +++++++++++++++------------- lib/Parse/ParseDeclCXX.cpp | 16 +- test/CXX/class/class.mem/p1b.cpp | 46 +++++ test/SemaCXX/default2.cpp | 3 + 6 files changed, 277 insertions(+), 168 deletions(-) create mode 100644 test/CXX/class/class.mem/p1b.cpp diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index cb28bde8d3..c4cf05c31d 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -566,7 +566,44 @@ private: //===--------------------------------------------------------------------===// // Lexing and parsing of C++ inline methods. - struct LexedMethod { + struct ParsingClass; + + /// [class.mem]p1: "... the class is regarded as complete within + /// - function bodies + /// - default arguments + /// - exception-specifications (TODO: C++0x) + /// - and brace-or-equal-initializers (TODO: C++0x) + /// for non-static data members (including such things in nested classes)." + /// LateParsedDeclarations build the tree of those elements so they can + /// be parsed after parsing the top-level class. + class LateParsedDeclaration { + public: + virtual ~LateParsedDeclaration(); + + virtual void ParseLexedMethodDeclarations(); + virtual void ParseLexedMethodDefs(); + }; + + /// Inner node of the LateParsedDeclaration tree that parses + /// all its members recursively. + class LateParsedClass : public LateParsedDeclaration { + public: + LateParsedClass(Parser *P, ParsingClass *C); + virtual ~LateParsedClass(); + + virtual void ParseLexedMethodDeclarations(); + virtual void ParseLexedMethodDefs(); + + private: + Parser *Self; + ParsingClass *Class; + }; + + /// Contains the lexed tokens of a member function definition + /// which needs to be parsed at the end of the class declaration + /// after parsing all other member declarations. + struct LexedMethod : public LateParsedDeclaration { + Parser *Self; Decl *D; CachedTokens Toks; @@ -575,7 +612,10 @@ private: /// othewise, it is a member function declaration. bool TemplateScope; - explicit LexedMethod(Decl *MD) : D(MD), TemplateScope(false) {} + explicit LexedMethod(Parser* P, Decl *MD) + : Self(P), D(MD), TemplateScope(false) {} + + virtual void ParseLexedMethodDefs(); }; /// LateParsedDefaultArgument - Keeps track of a parameter that may @@ -601,9 +641,13 @@ private: /// contains at least one entity whose parsing needs to be delayed /// until the class itself is completely-defined, such as a default /// argument (C++ [class.mem]p2). - struct LateParsedMethodDeclaration { - explicit LateParsedMethodDeclaration(Decl *M) - : Method(M), TemplateScope(false) { } + struct LateParsedMethodDeclaration : public LateParsedDeclaration { + explicit LateParsedMethodDeclaration(Parser *P, Decl *M) + : Self(P), Method(M), TemplateScope(false) { } + + virtual void ParseLexedMethodDeclarations(); + + Parser* Self; /// Method - The method declaration. Decl *Method; @@ -621,17 +665,12 @@ private: llvm::SmallVector DefaultArgs; }; - /// LateParsedMethodDecls - During parsing of a top (non-nested) C++ - /// class, its method declarations that contain parts that won't be + /// LateParsedDeclarationsContainer - During parsing of a top (non-nested) + /// C++ class, its method declarations that contain parts that won't be /// parsed until after the definiton is completed (C++ [class.mem]p2), - /// the method declarations will be stored here with the tokens that - /// will be parsed to create those entities. - typedef std::list LateParsedMethodDecls; - - /// LexedMethodsForTopClass - During parsing of a top (non-nested) C++ class, - /// its inline method definitions and the inline method definitions of its - /// nested classes are lexed and stored here. - typedef std::list LexedMethodsForTopClass; + /// the method declarations and possibly attached inline definitions + /// will be stored here with the tokens that will be parsed to create those entities. + typedef llvm::SmallVector LateParsedDeclarationsContainer; /// \brief Representation of a class that has been parsed, including /// any member function declarations or definitions that need to be @@ -653,16 +692,10 @@ private: /// \brief The class or class template whose definition we are parsing. Decl *TagOrTemplate; - /// MethodDecls - Method declarations that contain pieces whose - /// parsing will be delayed until the class is fully defined. - LateParsedMethodDecls MethodDecls; - - /// MethodDefs - Methods whose definitions will be parsed once the - /// class has been fully defined. - LexedMethodsForTopClass MethodDefs; - - /// \brief Nested classes inside this class. - llvm::SmallVector NestedClasses; + /// LateParsedDeclarations - Method declarations, inline definitions and + /// nested classes that contain pieces whose parsing will be delayed until + /// the top-level class is fully defined. + LateParsedDeclarationsContainer LateParsedDeclarations; }; /// \brief The stack of classes that is currently being @@ -868,7 +901,9 @@ private: Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, const ParsedTemplateInfo &TemplateInfo); void ParseLexedMethodDeclarations(ParsingClass &Class); + void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM); void ParseLexedMethodDefs(ParsingClass &Class); + void ParseLexedMethodDef(LexedMethod &LM); bool ConsumeAndStoreUntil(tok::TokenKind T1, CachedTokens &Toks, bool StopAtSemi = true, diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 4319df3e92..e8e80647b4 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -807,6 +807,7 @@ error: SavedMainFileBuffer = 0; } + StoredDiagnostics.clear(); Clang.takeSourceManager(); Clang.takeFileManager(); Invocation.reset(Clang.takeInvocation()); diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 8b2fb55d9d..718c71be02 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -45,10 +45,10 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, // Consume the tokens and store them for later parsing. - getCurrentClass().MethodDefs.push_back(LexedMethod(FnD)); - getCurrentClass().MethodDefs.back().TemplateScope - = getCurScope()->isTemplateParamScope(); - CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks; + LexedMethod* LM = new LexedMethod(this, FnD); + getCurrentClass().LateParsedDeclarations.push_back(LM); + LM->TemplateScope = getCurScope()->isTemplateParamScope(); + CachedTokens &Toks = LM->Toks; tok::TokenKind kind = Tok.getKind(); // We may have a constructor initializer or function-try-block here. @@ -62,7 +62,8 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, // don't try to parse this method later. Diag(Tok.getLocation(), diag::err_expected_lbrace); ConsumeAnyToken(); - getCurrentClass().MethodDefs.pop_back(); + delete getCurrentClass().LateParsedDeclarations.back(); + getCurrentClass().LateParsedDeclarations.pop_back(); return FnD; } } @@ -86,13 +87,40 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, return FnD; } +Parser::LateParsedDeclaration::~LateParsedDeclaration() {} +void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {} +void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {} + +Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C) + : Self(P), Class(C) {} + +Parser::LateParsedClass::~LateParsedClass() { + Self->DeallocateParsedClasses(Class); +} + +void Parser::LateParsedClass::ParseLexedMethodDeclarations() { + Self->ParseLexedMethodDeclarations(*Class); +} + +void Parser::LateParsedClass::ParseLexedMethodDefs() { + Self->ParseLexedMethodDefs(*Class); +} + +void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() { + Self->ParseLexedMethodDeclaration(*this); +} + +void Parser::LexedMethod::ParseLexedMethodDefs() { + Self->ParseLexedMethodDef(*this); +} + /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was /// delayed (such as default arguments) and parse them. void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); @@ -104,80 +132,79 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { if (HasClassScope) Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); - for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) { - LateParsedMethodDeclaration &LM = Class.MethodDecls.front(); - - // If this is a member template, introduce the template parameter scope. - ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) - Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); - - // Start the delayed C++ method declaration - Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); - - // Introduce the parameters into scope and parse their default - // arguments. - ParseScope PrototypeScope(this, - Scope::FunctionPrototypeScope|Scope::DeclScope); - for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { - // Introduce the parameter into scope. - Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param); + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMethodDeclarations(); + } - if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { - // Save the current token position. - SourceLocation origLoc = Tok.getLocation(); + if (HasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); +} - // 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); +void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); + + // Start the delayed C++ method declaration + Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); + + // Introduce the parameters into scope and parse their default + // arguments. + ParseScope PrototypeScope(this, + Scope::FunctionPrototypeScope|Scope::DeclScope); + for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { + // Introduce the parameter into scope. + Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param); + + if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { + // 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(); + + // Consume the '='. + assert(Tok.is(tok::equal) && "Default argument not starting with '='"); + SourceLocation EqualLoc = ConsumeToken(); + + // The argument isn't actually potentially evaluated unless it is + // used. + EnterExpressionEvaluationContext Eval(Actions, + Sema::PotentiallyEvaluatedIfUsed); + + ExprResult DefArgResult(ParseAssignmentExpression()); + if (DefArgResult.isInvalid()) + Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); + else { + if (Tok.is(tok::cxx_defaultarg_end)) + ConsumeToken(); + else + Diag(Tok.getLocation(), diag::err_default_arg_unparsed); + Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, + DefArgResult.take()); + } - // Consume the previously-pushed token. + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseAssignmentExpression went over the default arg 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(); - // Consume the '='. - assert(Tok.is(tok::equal) && "Default argument not starting with '='"); - SourceLocation EqualLoc = ConsumeToken(); - - // The argument isn't actually potentially evaluated unless it is - // used. - EnterExpressionEvaluationContext Eval(Actions, - Sema::PotentiallyEvaluatedIfUsed); - - ExprResult DefArgResult(ParseAssignmentExpression()); - if (DefArgResult.isInvalid()) - Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); - else { - if (Tok.is(tok::cxx_defaultarg_end)) - ConsumeToken(); - else - Diag(Tok.getLocation(), diag::err_default_arg_unparsed); - Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, - DefArgResult.take()); - } - - assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, - Tok.getLocation()) && - "ParseAssignmentExpression went over the default arg 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.DefaultArgs[I].Toks = 0; - } + delete Toks; + LM.DefaultArgs[I].Toks = 0; } - PrototypeScope.Exit(); - - // Finish the delayed C++ method declaration. - Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method); } + PrototypeScope.Exit(); - for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) - ParseLexedMethodDeclarations(*Class.NestedClasses[I]); - - if (HasClassScope) - Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); + // Finish the delayed C++ method declaration. + Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method); } /// ParseLexedMethodDefs - We finished parsing the member specification of a top @@ -185,7 +212,7 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { /// collected during its parsing and parse them all. void Parser::ParseLexedMethodDefs(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); if (HasTemplateScope) Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); @@ -193,73 +220,72 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); - for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) { - LexedMethod &LM = Class.MethodDefs.front(); - - // If this is a member template, introduce the template parameter scope. - ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) - Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); - - // Save the current token position. - SourceLocation origLoc = Tok.getLocation(); - - assert(!LM.Toks.empty() && "Empty body!"); - // Append the current token at the end of the new token stream so that it - // doesn't get lost. - LM.Toks.push_back(Tok); - PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); - - // Consume the previously pushed token. - ConsumeAnyToken(); - assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) - && "Inline method not starting with '{', ':' or 'try'"); + for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { + Class.LateParsedDeclarations[i]->ParseLexedMethodDefs(); + } +} - // Parse the method body. Function body parsing code is similar enough - // to be re-used for method bodies as well. - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); - Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); +void Parser::ParseLexedMethodDef(LexedMethod &LM) { + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); + + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + + assert(!LM.Toks.empty() && "Empty body!"); + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LM.Toks.push_back(Tok); + PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) + && "Inline method not starting with '{', ':' or 'try'"); + + // Parse the method body. Function body parsing code is similar enough + // to be re-used for method bodies as well. + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); + + if (Tok.is(tok::kw_try)) { + ParseFunctionTryBlock(LM.D); + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseFunctionTryBlock went over the cached 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(); + return; + } + if (Tok.is(tok::colon)) { + ParseConstructorInitializer(LM.D); - if (Tok.is(tok::kw_try)) { - ParseFunctionTryBlock(LM.D); - assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, - Tok.getLocation()) && - "ParseFunctionTryBlock went over the cached tokens!"); - // There could be leftover tokens (e.g. because of an error). - // Skip through until we reach the original token position. + // Error recovery. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(LM.D, 0); + return; + } + } else + Actions.ActOnDefaultCtorInitializers(LM.D); + + ParseFunctionStatementBody(LM.D); + + if (Tok.getLocation() != origLoc) { + // Due to parsing error, we either went over the cached tokens or + // there are still cached tokens left. If it's the latter case skip the + // leftover tokens. + // Since this is an uncommon situation that should be avoided, use the + // expensive isBeforeInTranslationUnit call. + if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), + origLoc)) while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); - continue; - } - if (Tok.is(tok::colon)) { - ParseConstructorInitializer(LM.D); - - // Error recovery. - if (!Tok.is(tok::l_brace)) { - Actions.ActOnFinishFunctionBody(LM.D, 0); - continue; - } - } else - Actions.ActOnDefaultCtorInitializers(LM.D); - - ParseFunctionStatementBody(LM.D); - - if (Tok.getLocation() != origLoc) { - // Due to parsing error, we either went over the cached tokens or - // there are still cached tokens left. If it's the latter case skip the - // leftover tokens. - // Since this is an uncommon situation that should be avoided, use the - // expensive isBeforeInTranslationUnit call. - if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), - origLoc)) - while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) - ConsumeAnyToken(); - } } - - for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) - ParseLexedMethodDefs(*Class.NestedClasses[I]); } /// ConsumeAndStoreUntil - Consume and store the token at the passed token diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index c02f41a268..8fed447bc2 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1203,9 +1203,8 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, if (!LateMethod) { // Push this method onto the stack of late-parsed method // declarations. - getCurrentClass().MethodDecls.push_back( - LateParsedMethodDeclaration(ThisDecl)); - LateMethod = &getCurrentClass().MethodDecls.back(); + LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); + getCurrentClass().LateParsedDeclarations.push_back(LateMethod); LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); // Add all of the parameters prior to this one (they don't @@ -1911,8 +1910,8 @@ void Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) { /// \brief Deallocate the given parsed class and all of its nested /// classes. void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) { - for (unsigned I = 0, N = Class->NestedClasses.size(); I != N; ++I) - DeallocateParsedClasses(Class->NestedClasses[I]); + for (unsigned I = 0, N = Class->LateParsedDeclarations.size(); I != N; ++I) + delete Class->LateParsedDeclarations[I]; delete Class; } @@ -1938,13 +1937,12 @@ void Parser::PopParsingClass() { } assert(!ClassStack.empty() && "Missing top-level class?"); - if (Victim->MethodDecls.empty() && Victim->MethodDefs.empty() && - Victim->NestedClasses.empty()) { + if (Victim->LateParsedDeclarations.empty()) { // The victim is a nested class, but we will not need to perform // any processing after the definition of this class since it has // no members whose handling was delayed. Therefore, we can just // remove this nested class. - delete Victim; + DeallocateParsedClasses(Victim); return; } @@ -1952,7 +1950,7 @@ void Parser::PopParsingClass() { // after the top-level class is completely defined. Therefore, add // it to the list of nested classes within its parent. assert(getCurScope()->isClassScope() && "Nested class outside of class scope?"); - ClassStack.top()->NestedClasses.push_back(Victim); + ClassStack.top()->LateParsedDeclarations.push_back(new LateParsedClass(this, Victim)); Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope(); } diff --git a/test/CXX/class/class.mem/p1b.cpp b/test/CXX/class/class.mem/p1b.cpp new file mode 100644 index 0000000000..d3493f6fd7 --- /dev/null +++ b/test/CXX/class/class.mem/p1b.cpp @@ -0,0 +1,46 @@ +// The first run checks that the correct errors are generated, +// implicitly checking the order of default argument parsing: +// RUN: %clang_cc1 -fsyntax-only -verify %s +// The second run checks the order of inline method definitions: +// RUN: not %clang_cc1 -fsyntax-only %s 2> %t +// RUN: FileCheck %s < %t + +class A { +public: + void a1() { + B b = B(); + } + + class B; + void a2(B b = B()); // expected-error{{use of default argument to function 'B' that is declared later in class 'B'}} + + void a3(int a = 42); + + // CHEKC: error: use of undeclared identifier 'first' + void a4(int a = first); // expected-error{{use of undeclared identifier 'first'}} + + class B { + public: + B(int b = 42) { // expected-note{{default argument declared here}} + A a; + a.a3(); + a.a6(); + } + + void b1(A a = A()); // expected-error{{use of default argument to function 'A' that is declared later in class 'A'}} + + // CHECK: error: use of undeclared identifier 'second' + void b2(int a = second); // expected-error{{use of undeclared identifier 'second'}} + }; + + void a5() { + B b = B(); + } + + void a6(B b = B()); + + A(int a = 42); // expected-note{{default argument declared here}} + + // CHECK: error: use of undeclared identifier 'third' + void a7(int a = third); // expected-error{{use of undeclared identifier 'third'}} +}; diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp index d9f1edf3b2..20763229cf 100644 --- a/test/SemaCXX/default2.cpp +++ b/test/SemaCXX/default2.cpp @@ -68,8 +68,11 @@ struct Y { Nested* self = this, // expected-error{{invalid use of 'this' outside of a nonstatic member function}} int m); // expected-error{{missing default argument on parameter 'm'}} static int c; + Nested(int i = 42); }; + int mem7(Nested n = Nested()); + static int b; }; -- 2.40.0