diff options
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 29 | ||||
-rw-r--r-- | test/SemaTemplate/friend-template.cpp | 20 |
2 files changed, 44 insertions, 5 deletions
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index e15ab0ae98..30aee20b26 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -19,6 +19,13 @@ #include "clang/Sema/Scope.h" using namespace clang; +/// Get the FunctionDecl for a function or function template decl. +static FunctionDecl *getFunctionDecl(Decl *D) { + if (FunctionDecl *fn = dyn_cast<FunctionDecl>(D)) + return fn; + return cast<FunctionTemplateDecl>(D)->getTemplatedDecl(); +} + /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. @@ -117,11 +124,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, if (FnD) { LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD); - FunctionDecl *FD = 0; - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD)) - FD = FunTmpl->getTemplatedDecl(); - else - FD = cast<FunctionDecl>(FnD); + FunctionDecl *FD = getFunctionDecl(FnD); Actions.CheckForFunctionRedefinition(FD); LateParsedTemplateMap[FD] = LPT; @@ -176,6 +179,19 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, getCurrentClass().LateParsedDeclarations.pop_back(); } + // If this is a friend function, mark that it's late-parsed so that + // it's still known to be a definition even before we attach the + // parsed body. Sema needs to treat friend function definitions + // differently during template instantiation, and it's possible for + // the containing class to be instantiated before all its member + // function definitions are parsed. + // + // If you remove this, you can remove the code that clears the flag + // after parsing the member. + if (D.getDeclSpec().isFriendSpecified()) { + getFunctionDecl(FnD)->setLateTemplateParsed(true); + } + return FnD; } @@ -427,6 +443,9 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { ParseFunctionStatementBody(LM.D, FnScope); + // Clear the late-template-parsed bit if we set it before. + if (LM.D) getFunctionDecl(LM.D)->setLateTemplateParsed(false); + 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 diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp index 9acbfdcea2..8a478777eb 100644 --- a/test/SemaTemplate/friend-template.cpp +++ b/test/SemaTemplate/friend-template.cpp @@ -302,3 +302,23 @@ namespace PR12585 { H<int> h1; // ok H<char> h2; // expected-note {{instantiation}} } + +// Ensure that we can still instantiate a friend function template +// after the friend declaration is instantiated during the delayed +// parsing of a member function, but before the friend function has +// been parsed. +namespace rdar12350696 { + template <class T> struct A { + void foo() { + A<int> a; + } + template <class U> friend void foo(const A<U> & a) { + int array[sizeof(T) == sizeof(U) ? -1 : 1]; // expected-error {{negative size}} + } + }; + + void test() { + A<int> b; + foo(b); // expected-note {{in instantiation}} + } +} |