r177003 - Flag that friend function definitions are "late parsed" so that

John McCall rjmccall at apple.com
Wed Mar 13 22:13:41 PDT 2013


Author: rjmccall
Date: Thu Mar 14 00:13:41 2013
New Revision: 177003

URL: http://llvm.org/viewvc/llvm-project?rev=177003&view=rev
Log:
Flag that friend function definitions are "late parsed" so that
template instantiation will still consider them to be definitions
if we instantiate the containing class before we get around
to parsing the friend.

This seems like a legitimate use of "late template parsed" to me,
but I'd appreciate it if someone responsible for the MS feature
would look over this.

This file already appears to access AST nodes directly, which
is arguably not kosher in the parser, but the performance of this
path matters enough that perpetuating the sin is justifiable.
Probably we ought to reconsider this policy for very simple
manipulations like this.

The reason this entire thing is necessary is that
function template instantiation plays some very gross games
in order to not associate an instantiated function template
with the class it came from unless it's a definition, and
the reason *that's* necessary is that the AST currently
cannot represent the instantiation history of individual
function template declarations, but instead tracks it in
common for the entire function template.  That probably
prevents us from correctly reporting ill-formed calls to
ambiguously instantiated friend function templates.

rdar://12350696

Modified:
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
    cfe/trunk/test/SemaTemplate/friend-template.cpp

Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=177003&r1=177002&r2=177003&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Thu Mar 14 00:13:41 2013
@@ -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::ParseCXXInlineMethodD
     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::ParseCXXInlineMethodD
     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(LexedMe
 
   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

Modified: cfe/trunk/test/SemaTemplate/friend-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/friend-template.cpp?rev=177003&r1=177002&r2=177003&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/friend-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/friend-template.cpp Thu Mar 14 00:13:41 2013
@@ -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}}
+  }
+}





More information about the cfe-commits mailing list