Hi Doug,<br><br>- <span class="il">ConsumeAndStoreUntil</span>(<span class="il">tok</span>::r_brace,
Toks);<br><div id=":g" class="ii gt">
+ <span class="il">ConsumeAndStoreUntil</span>(<span class="il">tok</span>::r_brace,
<span class="il">tok</span>::<span class="il">unknown</span>, Toks);<br>
</div><br>Why did you add tok::unknown as a "cut-off" token ?<br>This created an "asymmetry" with SkipUntil() which just skips tok::unknown and resulted in PR6903 (<a href="http://llvm.org/bugs/show_bug.cgi?id=6903">http://llvm.org/bugs/show_bug.cgi?id=6903</a>)<br>
<br><span class="il">ConsumeAndStoreUntil() stops at tok::unknown when caching the inline method, but SkipUntil() goes past it when parsing the method.<br><br>-Argiris<br></span><br><br><div class="gmail_quote">On Wed, Dec 17, 2008 at 12:30 AM, Douglas Gregor <span dir="ltr"><<a href="mailto:dgregor@apple.com">dgregor@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">Author: dgregor<br>
Date: Tue Dec 16 15:30:33 2008<br>
New Revision: 61103<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=61103&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=61103&view=rev</a><br>
Log:<br>
Delay parsing of default arguments of member functions until the class<br>
is completely defined (C++ [class.mem]p2).<br>
<br>
Reverse the order in which we process the definitions of member<br>
functions specified inline. This way, we'll get diagnostics in the<br>
order in which the member functions were declared in the class.<br>
<br>
<br>
Modified:<br>
cfe/trunk/include/clang/Parse/Action.h<br>
cfe/trunk/include/clang/Parse/DeclSpec.h<br>
cfe/trunk/include/clang/Parse/Parser.h<br>
cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp<br>
cfe/trunk/lib/Parse/ParseDecl.cpp<br>
cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
cfe/trunk/lib/Sema/Sema.h<br>
cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp<br>
cfe/trunk/lib/Sema/SemaDecl.cpp<br>
cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
cfe/trunk/test/SemaCXX/default2.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Parse/Action.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/include/clang/Parse/Action.h (original)<br>
+++ cfe/trunk/include/clang/Parse/Action.h Tue Dec 16 15:30:33 2008<br>
@@ -216,7 +216,7 @@<br>
return;<br>
}<br>
<br>
- /// ActOnFunctionDefBody - This is called when a function body has completed<br>
+ /// ActOnFinishFunctionBody - This is called when a function body has completed<br>
/// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef.<br>
virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtArg Body) {<br>
return Decl;<br>
@@ -681,6 +681,10 @@<br>
ExprTy *defarg) {<br>
}<br>
<br>
+ /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of<br>
+ /// the default argument for the parameter param failed.<br>
+ virtual void ActOnParamDefaultArgumentError(DeclTy *param) { }<br>
+<br>
/// AddCXXDirectInitializerToDecl - This action is called immediately after<br>
/// ActOnDeclarator, when a C++ direct initializer is present.<br>
/// e.g: "int x(1);"<br>
@@ -692,6 +696,34 @@<br>
return;<br>
}<br>
<br>
+ /// ActOnStartDelayedCXXMethodDeclaration - We have completed<br>
+ /// parsing a top-level (non-nested) C++ class, and we are now<br>
+ /// parsing those parts of the given Method declaration that could<br>
+ /// not be parsed earlier (C++ [class.mem]p2), such as default<br>
+ /// arguments. This action should enter the scope of the given<br>
+ /// Method declaration as if we had just parsed the qualified method<br>
+ /// name. However, it should not bring the parameters into scope;<br>
+ /// that will be performed by ActOnDelayedCXXMethodParameter.<br>
+ virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {<br>
+ }<br>
+<br>
+ /// ActOnDelayedCXXMethodParameter - We've already started a delayed<br>
+ /// C++ method declaration. We're (re-)introducing the given<br>
+ /// function parameter into scope for use in parsing later parts of<br>
+ /// the method declaration. For example, we could see an<br>
+ /// ActOnParamDefaultArgument event for this parameter.<br>
+ virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *Param) {<br>
+ }<br>
+<br>
+ /// ActOnFinishDelayedCXXMethodDeclaration - We have finished<br>
+ /// processing the delayed method declaration for Method. The method<br>
+ /// declaration is now considered finished. There may be a separate<br>
+ /// ActOnStartOfFunctionDef action later (not necessarily<br>
+ /// immediately!) for this method, if it was also defined inside the<br>
+ /// class body.<br>
+ virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {<br>
+ }<br>
+<br>
//===------------------------- C++ Expressions --------------------------===//<br>
<br>
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.<br>
<br>
Modified: cfe/trunk/include/clang/Parse/DeclSpec.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)<br>
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Tue Dec 16 15:30:33 2008<br>
@@ -16,6 +16,7 @@<br>
<br>
#include "clang/Parse/Action.h"<br>
#include "clang/Parse/AttributeList.h"<br>
+#include "clang/Lex/Token.h"<br>
#include "llvm/ADT/SmallVector.h"<br>
<br>
namespace clang {<br>
@@ -414,6 +415,10 @@<br>
}<br>
};<br>
<br>
+/// CachedTokens - A set of tokens that has been cached for later<br>
+/// parsing.<br>
+typedef llvm::SmallVector<Token, 4> CachedTokens;<br>
+<br>
/// DeclaratorChunk - One instance of this struct is used for each type in a<br>
/// declarator that is parsed.<br>
///<br>
@@ -471,9 +476,19 @@<br>
IdentifierInfo *Ident;<br>
SourceLocation IdentLoc;<br>
Action::DeclTy *Param;<br>
+<br>
+ /// DefaultArgTokens - When the parameter's default argument<br>
+ /// cannot be parsed immediately (because it occurs within the<br>
+ /// declaration of a member function), it will be stored here as a<br>
+ /// sequence of tokens to be parsed once the class definition is<br>
+ /// complete. Non-NULL indicates that there is a default argument.<br>
+ CachedTokens *DefaultArgTokens;<br>
+<br>
ParamInfo() {}<br>
- ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::DeclTy *param)<br>
- : Ident(ident), IdentLoc(iloc), Param(param) {}<br>
+ ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::DeclTy *param,<br>
+ CachedTokens *DefArgTokens = 0)<br>
+ : Ident(ident), IdentLoc(iloc), Param(param),<br>
+ DefaultArgTokens(DefArgTokens) {}<br>
};<br>
<br>
struct FunctionTypeInfo {<br>
@@ -605,7 +620,6 @@<br>
}<br>
};<br>
<br>
-<br>
/// Declarator - Information about one declarator, including the parsed type<br>
/// information and the identifier. When the declarator is fully formed, this<br>
/// is turned into the appropriate Decl object.<br>
<br>
Modified: cfe/trunk/include/clang/Parse/Parser.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/include/clang/Parse/Parser.h (original)<br>
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Dec 16 15:30:33 2008<br>
@@ -394,38 +394,98 @@<br>
//===--------------------------------------------------------------------===//<br>
// Lexing and parsing of C++ inline methods.<br>
<br>
- typedef llvm::SmallVector<Token, 32> TokensTy;<br>
struct LexedMethod {<br>
Action::DeclTy *D;<br>
- TokensTy Toks;<br>
+ CachedTokens Toks;<br>
explicit LexedMethod(Action::DeclTy *MD) : D(MD) {}<br>
};<br>
<br>
+ /// LateParsedDefaultArgument - Keeps track of a parameter that may<br>
+ /// have a default argument that cannot be parsed yet because it<br>
+ /// occurs within a member function declaration inside the class<br>
+ /// (C++ [class.mem]p2).<br>
+ struct LateParsedDefaultArgument {<br>
+ explicit LateParsedDefaultArgument(Action::DeclTy *P,<br>
+ CachedTokens *Toks = 0)<br>
+ : Param(P), Toks(Toks) { }<br>
+<br>
+ /// Param - The parameter declaration for this parameter.<br>
+ Action::DeclTy *Param;<br>
+<br>
+ /// Toks - The sequence of tokens that comprises the default<br>
+ /// argument expression, not including the '=' or the terminating<br>
+ /// ')' or ','. This will be NULL for parameters that have no<br>
+ /// default argument.<br>
+ CachedTokens *Toks;<br>
+ };<br>
+<br>
+ /// LateParsedMethodDeclaration - A method declaration inside a class that<br>
+ /// contains at least one entity whose parsing needs to be delayed<br>
+ /// until the class itself is completely-defined, such as a default<br>
+ /// argument (C++ [class.mem]p2).<br>
+ struct LateParsedMethodDeclaration {<br>
+ explicit LateParsedMethodDeclaration(Action::DeclTy *M) : Method(M) { }<br>
+<br>
+ /// Method - The method declaration.<br>
+ Action::DeclTy *Method;<br>
+<br>
+ /// DefaultArgs - Contains the parameters of the function and<br>
+ /// their default arguments. At least one of the parameters will<br>
+ /// have a default argument, but all of the parameters of the<br>
+ /// method will be stored so that they can be reintroduced into<br>
+ /// scope at the appropriate times.<br>
+ llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;<br>
+ };<br>
+<br>
+ /// LateParsedMethodDecls - During parsing of a top (non-nested) C++<br>
+ /// class, its method declarations that contain parts that won't be<br>
+ /// parsed until after the definiton is completed (C++ [class.mem]p2),<br>
+ /// the method declarations will be stored here with the tokens that<br>
+ /// will be parsed to create those entities.<br>
+ typedef std::list<LateParsedMethodDeclaration> LateParsedMethodDecls;<br>
+<br>
/// LexedMethodsForTopClass - During parsing of a top (non-nested) C++ class,<br>
/// its inline method definitions and the inline method definitions of its<br>
/// nested classes are lexed and stored here.<br>
- typedef std::stack<LexedMethod> LexedMethodsForTopClass;<br>
+ typedef std::list<LexedMethod> LexedMethodsForTopClass;<br>
+<br>
+<br>
+ /// TopClass - Contains information about parts of the top<br>
+ /// (non-nested) C++ class that will need to be parsed after the<br>
+ /// class is fully defined.<br>
+ struct TopClass {<br>
+ /// MethodDecls - Method declarations that contain pieces whose<br>
+ /// parsing will be delayed until the class is fully defined.<br>
+ LateParsedMethodDecls MethodDecls;<br>
+<br>
+ /// MethodDefs - Methods whose definitions will be parsed once the<br>
+ /// class has been fully defined.<br>
+ LexedMethodsForTopClass MethodDefs;<br>
+ };<br>
<br>
- /// TopClassStacks - This is initialized with one LexedMethodsForTopClass used<br>
+ /// TopClassStacks - This is initialized with one TopClass used<br>
/// for lexing all top classes, until a local class in an inline method is<br>
- /// encountered, at which point a new LexedMethodsForTopClass is pushed here<br>
+ /// encountered, at which point a new TopClass is pushed here<br>
/// and used until the parsing of that local class is finished.<br>
- std::stack<LexedMethodsForTopClass> TopClassStacks;<br>
+ std::stack<TopClass> TopClassStacks;<br>
<br>
- LexedMethodsForTopClass &getCurTopClassStack() {<br>
+ TopClass &getCurTopClassStack() {<br>
assert(!TopClassStacks.empty() && "No lexed method stacks!");<br>
return TopClassStacks.top();<br>
}<br>
<br>
void PushTopClassStack() {<br>
- TopClassStacks.push(LexedMethodsForTopClass());<br>
+ TopClassStacks.push(TopClass());<br>
}<br>
void PopTopClassStack() { TopClassStacks.pop(); }<br>
<br>
DeclTy *ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D);<br>
+ void ParseLexedMethodDeclarations();<br>
void ParseLexedMethodDefs();<br>
- bool ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks,<br>
- tok::TokenKind EarlyAbortIf = tok::unknown);<br>
+ bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,<br>
+ CachedTokens &Toks,<br>
+ tok::TokenKind EarlyAbortIf = tok::unknown,<br>
+ bool ConsumeFinalToken = true);<br>
<br>
//===--------------------------------------------------------------------===//<br>
// C99 6.9: External Definitions.<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Tue Dec 16 15:30:33 2008<br>
@@ -31,13 +31,13 @@<br>
<br>
// Consume the tokens and store them for later parsing.<br>
<br>
- getCurTopClassStack().push(LexedMethod(FnD));<br>
- TokensTy &Toks = getCurTopClassStack().top().Toks;<br>
+ getCurTopClassStack().MethodDefs.push_back(LexedMethod(FnD));<br>
+ CachedTokens &Toks = getCurTopClassStack().MethodDefs.back().Toks;<br>
<br>
// We may have a constructor initializer here.<br>
if (Tok.is(tok::colon)) {<br>
// Consume everything up to (and including) the left brace.<br>
- if (!ConsumeAndStoreUntil(tok::l_brace, Toks, tok::semi)) {<br>
+ if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) {<br>
// We didn't find the left-brace we expected after the<br>
// constructor initializer.<br>
if (Tok.is(tok::semi)) {<br>
@@ -45,7 +45,7 @@<br>
// don't try to parse this method later.<br>
Diag(Tok.getLocation(), diag::err_expected_lbrace);<br>
ConsumeAnyToken();<br>
- getCurTopClassStack().pop();<br>
+ getCurTopClassStack().MethodDefs.pop_back();<br>
return FnD;<br>
}<br>
}<br>
@@ -56,17 +56,66 @@<br>
ConsumeBrace();<br>
}<br>
// Consume everything up to (and including) the matching right brace.<br>
- ConsumeAndStoreUntil(tok::r_brace, Toks);<br>
+ ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);<br>
<br>
return FnD;<br>
}<br>
<br>
+/// ParseLexedMethodDeclarations - We finished parsing the member<br>
+/// specification of a top (non-nested) C++ class. Now go over the<br>
+/// stack of method declarations with some parts for which parsing was<br>
+/// delayed (such as default arguments) and parse them.<br>
+void Parser::ParseLexedMethodDeclarations() {<br>
+ for (; !getCurTopClassStack().MethodDecls.empty();<br>
+ getCurTopClassStack().MethodDecls.pop_front()) {<br>
+ LateParsedMethodDeclaration &LM = getCurTopClassStack().MethodDecls.front();<br>
+<br>
+ // Start the delayed C++ method declaration<br>
+ Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method);<br>
+<br>
+ // Introduce the parameters into scope and parse their default<br>
+ // arguments.<br>
+ ParseScope PrototypeScope(this, Scope::FnScope|Scope::DeclScope);<br>
+ for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {<br>
+ // Introduce the parameter into scope.<br>
+ Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param);<br>
+<br>
+ if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {<br>
+ // Parse the default argument from its saved token stream.<br>
+ Toks->push_back(Tok); // So that the current token doesn't get lost<br>
+ PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);<br>
+<br>
+ // Consume the previously-pushed token.<br>
+ ConsumeAnyToken();<br>
+<br>
+ // Consume the '='.<br>
+ assert(Tok.is(tok::equal) && "Default argument not starting with '='");<br>
+ SourceLocation EqualLoc = ConsumeToken();<br>
+<br>
+ OwningExprResult DefArgResult(ParseAssignmentExpression());<br>
+ if (DefArgResult.isInvalid())<br>
+ Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);<br>
+ else<br>
+ Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,<br>
+ DefArgResult.release());<br>
+ delete Toks;<br>
+ LM.DefaultArgs[I].Toks = 0;<br>
+ }<br>
+ }<br>
+ PrototypeScope.Exit();<br>
+<br>
+ // Finish the delayed C++ method declaration.<br>
+ Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method);<br>
+ }<br>
+}<br>
+<br>
/// ParseLexedMethodDefs - We finished parsing the member specification of a top<br>
/// (non-nested) C++ class. Now go over the stack of lexed methods that were<br>
/// collected during its parsing and parse them all.<br>
void Parser::ParseLexedMethodDefs() {<br>
- for (; !getCurTopClassStack().empty(); getCurTopClassStack().pop()) {<br>
- LexedMethod &LM = getCurTopClassStack().top();<br>
+ for (; !getCurTopClassStack().MethodDefs.empty();<br>
+ getCurTopClassStack().MethodDefs.pop_front()) {<br>
+ LexedMethod &LM = getCurTopClassStack().MethodDefs.front();<br>
<br>
assert(!LM.Toks.empty() && "Empty body!");<br>
// Append the current token at the end of the new token stream so that it<br>
@@ -92,21 +141,26 @@<br>
}<br>
<br>
/// ConsumeAndStoreUntil - Consume and store the token at the passed token<br>
-/// container until the token 'T' is reached (which gets consumed/stored too).<br>
+/// container until the token 'T' is reached (which gets<br>
+/// consumed/stored too, if ConsumeFinalToken).<br>
/// If EarlyAbortIf is specified, then we will stop early if we find that<br>
/// token at the top level.<br>
-/// Returns true if token 'T' was found.<br>
+/// Returns true if token 'T1' or 'T2' was found.<br>
/// NOTE: This is a specialized version of Parser::SkipUntil.<br>
-bool Parser::ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks,<br>
- tok::TokenKind EarlyAbortIf) {<br>
+bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,<br>
+ CachedTokens &Toks,<br>
+ tok::TokenKind EarlyAbortIf,<br>
+ bool ConsumeFinalToken) {<br>
// We always want this function to consume at least one token if the first<br>
// token isn't T and if not at EOF.<br>
bool isFirstTokenConsumed = true;<br>
while (1) {<br>
// If we found one of the tokens, stop and return true.<br>
- if (Tok.is(T)) {<br>
- Toks.push_back(Tok);<br>
- ConsumeAnyToken();<br>
+ if (Tok.is(T1) || Tok.is(T2)) {<br>
+ if (ConsumeFinalToken) {<br>
+ Toks.push_back(Tok);<br>
+ ConsumeAnyToken();<br>
+ }<br>
return true;<br>
}<br>
<br>
@@ -123,19 +177,19 @@<br>
// Recursively consume properly-nested parens.<br>
Toks.push_back(Tok);<br>
ConsumeParen();<br>
- ConsumeAndStoreUntil(tok::r_paren, Toks);<br>
+ ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks);<br>
break;<br>
case tok::l_square:<br>
// Recursively consume properly-nested square brackets.<br>
Toks.push_back(Tok);<br>
ConsumeBracket();<br>
- ConsumeAndStoreUntil(tok::r_square, Toks);<br>
+ ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks);<br>
break;<br>
case tok::l_brace:<br>
// Recursively consume properly-nested braces.<br>
Toks.push_back(Tok);<br>
ConsumeBrace();<br>
- ConsumeAndStoreUntil(tok::r_brace, Toks);<br>
+ ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);<br>
break;<br>
<br>
// Okay, we found a ']' or '}' or ')', which we think should be balanced.<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Dec 16 15:30:33 2008<br>
@@ -1771,6 +1771,10 @@<br>
// Remember this parsed parameter in ParamInfo.<br>
IdentifierInfo *ParmII = ParmDecl.getIdentifier();<br>
<br>
+ // DefArgToks is used when the parsing of default arguments needs<br>
+ // to be delayed.<br>
+ CachedTokens *DefArgToks = 0;<br>
+<br>
// If no parameter was specified, verify that *something* was specified,<br>
// otherwise we have a missing type and identifier.<br>
if (DS.getParsedSpecifiers() == DeclSpec::PQ_None &&<br>
@@ -1790,24 +1794,39 @@<br>
// ActOnParamDefaultArgument will reject the default argument in<br>
// C.<br>
if (Tok.is(tok::equal)) {<br>
- SourceLocation EqualLoc = Tok.getLocation();<br>
-<br>
- // Consume the '='.<br>
- ConsumeToken();<br>
-<br>
// Parse the default argument<br>
- OwningExprResult DefArgResult(ParseAssignmentExpression());<br>
- if (DefArgResult.isInvalid()) {<br>
- SkipUntil(tok::comma, tok::r_paren, true, true);<br>
+ if (D.getContext() == Declarator::MemberContext) {<br>
+ // If we're inside a class definition, cache the tokens<br>
+ // corresponding to the default argument. We'll actually parse<br>
+ // them when we see the end of the class definition.<br>
+ // FIXME: Templates will require something similar.<br>
+ // FIXME: Can we use a smart pointer for Toks?<br>
+ DefArgToks = new CachedTokens;<br>
+<br>
+ if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,<br>
+ tok::semi, false)) {<br>
+ delete DefArgToks;<br>
+ DefArgToks = 0;<br>
+ }<br>
} else {<br>
- // Inform the actions module about the default argument<br>
- Actions.ActOnParamDefaultArgument(Param, EqualLoc,<br>
- DefArgResult.release());<br>
+ // Consume the '='.<br>
+ SourceLocation EqualLoc = ConsumeToken();<br>
+<br>
+ OwningExprResult DefArgResult(ParseAssignmentExpression());<br>
+ if (DefArgResult.isInvalid()) {<br>
+ Actions.ActOnParamDefaultArgumentError(Param);<br>
+ SkipUntil(tok::comma, tok::r_paren, true, true);<br>
+ } else {<br>
+ // Inform the actions module about the default argument<br>
+ Actions.ActOnParamDefaultArgument(Param, EqualLoc,<br>
+ DefArgResult.release());<br>
+ }<br>
}<br>
}<br>
<br>
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,<br>
- ParmDecl.getIdentifierLoc(), Param));<br>
+ ParmDecl.getIdentifierLoc(), Param,<br>
+ DefArgToks));<br>
}<br>
<br>
// If the next token is a comma, consume it and keep reading arguments.<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Dec 16 15:30:33 2008<br>
@@ -533,6 +533,40 @@<br>
Init.release(),<br>
LastDeclInGroup);<br>
<br>
+ if (DeclaratorInfo.isFunctionDeclarator() &&<br>
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec()<br>
+ != DeclSpec::SCS_typedef) {<br>
+ // We just declared a member function. If this member function<br>
+ // has any default arguments, we'll need to parse them later.<br>
+ LateParsedMethodDeclaration *LateMethod = 0;<br>
+ DeclaratorChunk::FunctionTypeInfo &FTI<br>
+ = DeclaratorInfo.getTypeObject(0).Fun;<br>
+ for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) {<br>
+ if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) {<br>
+ if (!LateMethod) {<br>
+ // Push this method onto the stack of late-parsed method<br>
+ // declarations.<br>
+ getCurTopClassStack().MethodDecls.push_back(<br>
+ LateParsedMethodDeclaration(LastDeclInGroup));<br>
+ LateMethod = &getCurTopClassStack().MethodDecls.back();<br>
+<br>
+ // Add all of the parameters prior to this one (they don't<br>
+ // have default arguments).<br>
+ LateMethod->DefaultArgs.reserve(FTI.NumArgs);<br>
+ for (unsigned I = 0; I < ParamIdx; ++I)<br>
+ LateMethod->DefaultArgs.push_back(<br>
+ LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param));<br>
+ }<br>
+<br>
+ // Add this parameter to the list of parameters (it or may<br>
+ // not have a default argument).<br>
+ LateMethod->DefaultArgs.push_back(<br>
+ LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param,<br>
+ FTI.ArgInfo[ParamIdx].DefaultArgTokens));<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
// If we don't have a comma, it is either the end of the list (a ';')<br>
// or an error, bail out.<br>
if (Tok.isNot(tok::comma))<br>
@@ -642,10 +676,13 @@<br>
// exception-specifications, and constructor ctor-initializers (including<br>
// such things in nested classes).<br>
//<br>
- // FIXME: Only function bodies are parsed correctly, fix the rest.<br>
+ // FIXME: Only function bodies and constructor ctor-initializers are<br>
+ // parsed correctly, fix the rest.<br>
if (!CurScope->getParent()->isCXXClassScope()) {<br>
// We are not inside a nested class. This class and its nested classes<br>
- // are complete and we can parse the lexed inline method definitions.<br>
+ // are complete and we can parse the delayed portions of method<br>
+ // declarations and the lexed inline method definitions.<br>
+ ParseLexedMethodDeclarations();<br>
ParseLexedMethodDefs();<br>
<br>
// For a local class of inline method, pop the LexedMethodsForTopClass that<br>
<br>
Modified: cfe/trunk/lib/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/Sema.h (original)<br>
+++ cfe/trunk/lib/Sema/Sema.h Tue Dec 16 15:30:33 2008<br>
@@ -276,6 +276,7 @@<br>
virtual void ActOnParamDefaultArgument(DeclTy *param,<br>
SourceLocation EqualLoc,<br>
ExprTy *defarg);<br>
+ virtual void ActOnParamDefaultArgumentError(DeclTy *param);<br>
void AddInitializerToDecl(DeclTy *dcl, ExprArg init);<br>
void ActOnUninitializedDecl(DeclTy *dcl);<br>
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);<br>
@@ -960,9 +961,13 @@<br>
<br>
virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl);<br>
<br>
-<br>
+ virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method);<br>
+ virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *Param);<br>
+ virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method);<br>
+<br>
bool CheckConstructorDeclarator(Declarator &D, QualType &R,<br>
FunctionDecl::StorageClass& SC);<br>
+ bool CheckConstructor(CXXConstructorDecl *Constructor);<br>
bool CheckDestructorDeclarator(Declarator &D, QualType &R,<br>
FunctionDecl::StorageClass& SC);<br>
bool CheckConversionDeclarator(Declarator &D, QualType &R,<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Tue Dec 16 15:30:33 2008<br>
@@ -134,7 +134,8 @@<br>
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");<br>
assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");<br>
PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());<br>
- S->setEntity(static_cast<DeclContext*>(SS.getScopeRep()));<br>
+ CurContext = static_cast<DeclContext*>(SS.getScopeRep());<br>
+ S->setEntity(CurContext);<br>
}<br>
<br>
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously<br>
@@ -147,4 +148,9 @@<br>
assert(S->getEntity() == SS.getScopeRep() && "Context imbalance!");<br>
S->setEntity(PreDeclaratorDC);<br>
PreDeclaratorDC = 0;<br>
+<br>
+ // Reset CurContext to the nearest enclosing context.<br>
+ while (!S->getEntity() && S->getParent())<br>
+ S = S->getParent();<br>
+ CurContext = static_cast<DeclContext*>(S->getEntity());<br>
}<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Dec 16 15:30:33 2008<br>
@@ -1230,30 +1230,8 @@<br>
}<br>
}<br>
<br>
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {<br>
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DC);<br>
-<br>
- // C++ [class.copy]p3:<br>
- // A declaration of a constructor for a class X is ill-formed if<br>
- // its first parameter is of type (optionally cv-qualified) X and<br>
- // either there are no other parameters or else all other<br>
- // parameters have default arguments.<br>
- if ((Constructor->getNumParams() == 1) ||<br>
- (Constructor->getNumParams() > 1 &&<br>
- Constructor->getParamDecl(1)->getDefaultArg() != 0)) {<br>
- QualType ParamType = Constructor->getParamDecl(0)->getType();<br>
- QualType ClassTy = Context.getTagDeclType(ClassDecl);<br>
- if (Context.getCanonicalType(ParamType).getUnqualifiedType()<br>
- == ClassTy) {<br>
- Diag(Constructor->getLocation(), diag::err_constructor_byvalue_arg)<br>
- << SourceRange(Constructor->getParamDecl(0)->getLocation());<br>
- Constructor->setInvalidDecl();<br>
- }<br>
- }<br>
-<br>
- // Notify the class that we've added a constructor.<br>
- ClassDecl->addedConstructor(Context, Constructor);<br>
- }<br>
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))<br>
+ InvalidDecl = InvalidDecl || CheckConstructor(Constructor);<br>
else if (isa<CXXDestructorDecl>(NewFD))<br>
cast<CXXRecordDecl>(NewFD->getParent())->setUserDeclaredDestructor(true);<br>
else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))<br>
@@ -2865,6 +2843,9 @@<br>
DeclSpec::SCS_mutable,<br>
/*PrevDecl=*/0);<br>
<br>
+ if (getLangOptions().CPlusPlus)<br>
+ CheckExtraCXXDefaultArguments(D);<br>
+<br>
ProcessDeclAttributes(NewFD, D);<br>
<br>
if (D.getInvalidType() || InvalidDecl)<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Dec 16 15:30:33 2008<br>
@@ -114,6 +114,7 @@<br>
if (!getLangOptions().CPlusPlus) {<br>
Diag(EqualLoc, diag::err_param_default_argument)<br>
<< DefaultArg->getSourceRange();<br>
+ Param->setInvalidDecl();<br>
return;<br>
}<br>
<br>
@@ -136,13 +137,21 @@<br>
<br>
// Check that the default argument is well-formed<br>
CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this);<br>
- if (DefaultArgChecker.Visit(DefaultArg.get()))<br>
+ if (DefaultArgChecker.Visit(DefaultArg.get())) {<br>
+ Param->setInvalidDecl();<br>
return;<br>
+ }<br>
<br>
// Okay: add the default argument to the parameter<br>
Param->setDefaultArg(DefaultArg.take());<br>
}<br>
<br>
+/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of<br>
+/// the default argument for the parameter param failed.<br>
+void Sema::ActOnParamDefaultArgumentError(DeclTy *param) {<br>
+ ((ParmVarDecl*)param)->setInvalidDecl();<br>
+}<br>
+<br>
/// CheckExtraCXXDefaultArguments - Check for any extra default<br>
/// arguments in the declarator, which is not a function declaration<br>
/// or definition and therefore is not permitted to have default<br>
@@ -165,6 +174,12 @@<br>
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)<br>
<< Param->getDefaultArg()->getSourceRange();<br>
Param->setDefaultArg(0);<br>
+ } else if (CachedTokens *Toks<br>
+ = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens) {<br>
+ Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)<br>
+ << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());<br>
+ delete Toks;<br>
+ chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;<br>
}<br>
}<br>
}<br>
@@ -231,7 +246,9 @@<br>
for(; p < NumParams; ++p) {<br>
ParmVarDecl *Param = FD->getParamDecl(p);<br>
if (!Param->getDefaultArg()) {<br>
- if (Param->getIdentifier())<br>
+ if (Param->isInvalidDecl())<br>
+ /* We already complained about this parameter. */;<br>
+ else if (Param->getIdentifier())<br>
Diag(Param->getLocation(),<br>
diag::err_param_default_argument_missing_name)<br>
<< Param->getIdentifier();<br>
@@ -401,6 +418,7 @@<br>
/// any. 'LastInGroup' is non-null for cases where one declspec has multiple<br>
/// declarators on it.<br>
///<br>
+/// FIXME: The note below is out-of-date.<br>
/// NOTE: Because of CXXFieldDecl's inability to be chained like ScopedDecls, if<br>
/// an instance field is declared, a new CXXFieldDecl is created but the method<br>
/// does *not* return it; it returns LastInGroup instead. The other C++ members<br>
@@ -875,8 +893,60 @@<br>
Consumer.HandleTagDeclDefinition(Rec);<br>
}<br>
<br>
+/// ActOnStartDelayedCXXMethodDeclaration - We have completed<br>
+/// parsing a top-level (non-nested) C++ class, and we are now<br>
+/// parsing those parts of the given Method declaration that could<br>
+/// not be parsed earlier (C++ [class.mem]p2), such as default<br>
+/// arguments. This action should enter the scope of the given<br>
+/// Method declaration as if we had just parsed the qualified method<br>
+/// name. However, it should not bring the parameters into scope;<br>
+/// that will be performed by ActOnDelayedCXXMethodParameter.<br>
+void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {<br>
+ CXXScopeSpec SS;<br>
+ SS.setScopeRep(((FunctionDecl*)Method)->getDeclContext());<br>
+ ActOnCXXEnterDeclaratorScope(S, SS);<br>
+}<br>
+<br>
+/// ActOnDelayedCXXMethodParameter - We've already started a delayed<br>
+/// C++ method declaration. We're (re-)introducing the given<br>
+/// function parameter into scope for use in parsing later parts of<br>
+/// the method declaration. For example, we could see an<br>
+/// ActOnParamDefaultArgument event for this parameter.<br>
+void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *ParamD) {<br>
+ ParmVarDecl *Param = (ParmVarDecl*)ParamD;<br>
+ S->AddDecl(Param);<br>
+ if (Param->getDeclName())<br>
+ IdResolver.AddDecl(Param);<br>
+}<br>
+<br>
+/// ActOnFinishDelayedCXXMethodDeclaration - We have finished<br>
+/// processing the delayed method declaration for Method. The method<br>
+/// declaration is now considered finished. There may be a separate<br>
+/// ActOnStartOfFunctionDef action later (not necessarily<br>
+/// immediately!) for this method, if it was also defined inside the<br>
+/// class body.<br>
+void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *MethodD) {<br>
+ FunctionDecl *Method = (FunctionDecl*)MethodD;<br>
+ CXXScopeSpec SS;<br>
+ SS.setScopeRep(Method->getDeclContext());<br>
+ ActOnCXXExitDeclaratorScope(S, SS);<br>
+<br>
+ // Now that we have our default arguments, check the constructor<br>
+ // again. It could produce additional diagnostics or affect whether<br>
+ // the class has implicitly-declared destructors, among other<br>
+ // things.<br>
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Method)) {<br>
+ if (CheckConstructor(Constructor))<br>
+ Constructor->setInvalidDecl();<br>
+ }<br>
+<br>
+ // Check the default arguments, which we may have added.<br>
+ if (!Method->isInvalidDecl())<br>
+ CheckCXXDefaultArguments(Method);<br>
+}<br>
+<br>
/// CheckConstructorDeclarator - Called by ActOnDeclarator to check<br>
-/// the well-formednes of the constructor declarator @p D with type @p<br>
+/// the well-formedness of the constructor declarator @p D with type @p<br>
/// R. If there are any errors in the declarator, this routine will<br>
/// emit diagnostics and return true. Otherwise, it will return<br>
/// false. Either way, the type @p R will be updated to reflect a<br>
@@ -944,6 +1014,39 @@<br>
return isInvalid;<br>
}<br>
<br>
+/// CheckConstructor - Checks a fully-formed constructor for<br>
+/// well-formedness, issuing any diagnostics required. Returns true if<br>
+/// the constructor declarator is invalid.<br>
+bool Sema::CheckConstructor(CXXConstructorDecl *Constructor) {<br>
+ if (Constructor->isInvalidDecl())<br>
+ return true;<br>
+<br>
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());<br>
+ bool Invalid = false;<br>
+<br>
+ // C++ [class.copy]p3:<br>
+ // A declaration of a constructor for a class X is ill-formed if<br>
+ // its first parameter is of type (optionally cv-qualified) X and<br>
+ // either there are no other parameters or else all other<br>
+ // parameters have default arguments.<br>
+ if ((Constructor->getNumParams() == 1) ||<br>
+ (Constructor->getNumParams() > 1 &&<br>
+ Constructor->getParamDecl(1)->getDefaultArg() != 0)) {<br>
+ QualType ParamType = Constructor->getParamDecl(0)->getType();<br>
+ QualType ClassTy = Context.getTagDeclType(ClassDecl);<br>
+ if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {<br>
+ Diag(Constructor->getLocation(), diag::err_constructor_byvalue_arg)<br>
+ << SourceRange(Constructor->getParamDecl(0)->getLocation());<br>
+ Invalid = true;<br>
+ }<br>
+ }<br>
+<br>
+ // Notify the class that we've added a constructor.<br>
+ ClassDecl->addedConstructor(Context, Constructor);<br>
+<br>
+ return Invalid;<br>
+}<br>
+<br>
/// CheckDestructorDeclarator - Called by ActOnDeclarator to check<br>
/// the well-formednes of the destructor declarator @p D with type @p<br>
/// R. If there are any errors in the declarator, this routine will<br>
<br>
Modified: cfe/trunk/test/SemaCXX/default2.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/default2.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/default2.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>
<br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/default2.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/default2.cpp Tue Dec 16 15:30:33 2008<br>
@@ -63,17 +63,48 @@<br>
}<br>
<br>
// C++ [dcl.fct.default]p9<br>
-class Y {<br>
+struct Y {<br>
int a;<br>
int mem1(int i = a); // expected-error{{invalid use of nonstatic data member 'a'}}<br>
- // FIXME: The code below is well-formed.<br>
- // int mem2(int i = b); // OK; use X::b<br>
+ int mem2(int i = b); // OK; use Y::b<br>
int mem3(int i);<br>
int mem4(int i);<br>
+<br>
+ struct Nested {<br>
+ int mem5(int i = b, // OK; use Y::b<br>
+ int j = c, // OK; use Y::Nested::c<br>
+ int k = j, // expected-error{{default argument references parameter 'j'}}<br>
+ int l = a, // expected-error{{invalid use of nonstatic data member 'a'}}<br>
+ Nested* self = this, // expected-error{{invalid use of 'this' outside of a nonstatic member function}}<br>
+ int m); // expected-error{{missing default argument on parameter 'm'}}<br>
+ static int c;<br>
+ };<br>
+<br>
static int b;<br>
+<br>
+ int (*f)(int = 17); // expected-error{{default arguments can only be specified for parameters in a function declaration}}<br>
+<br>
+ void mem8(int (*fp)(int) = (int (*)(int = 17))0); // expected-error{{default arguments can only be specified for parameters in a function declaration}}<br>
};<br>
<br>
int Y::mem3(int i = b) { return i; } // OK; use X::b<br>
<br>
int Y::mem4(int i = a) // expected-error{{invalid use of nonstatic data member 'a'}}<br>
{ return i; }<br>
+<br>
+<br>
+// Try to verify that default arguments interact properly with copy<br>
+// constructors.<br>
+class Z {<br>
+public:<br>
+ Z(Z&, int i = 17); // expected-note{{candidate function}}<br>
+<br>
+ void f(Z& z) {<br>
+ Z z2; // expected-error{{no matching constructor for initialization}}<br>
+ Z z3(z);<br>
+ }<br>
+};<br>
+<br>
+void test_Z(const Z& z) {<br>
+ Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}}<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>