This patch fixes 18432, where a friend decl for a nested class's member function clobbered its default arg. http://llvm.org/bugs/show_bug.cgi?id=18432

As the report says, such a friend decl is unneeded, but it shouldn't break things. There are 3 components to the problem:

1) Sema::MergeCXXFunctionDecl doesn't realize the Older decl could have an unparsed default argument. Fixed by propagating that info to the new decl (but not the tokens themselves). We now have a new possible state for a ParmVarDecl -- null tokens but hasUnparsedDefaultArg set.

2) HandleMemberFunctionDeclDelays only looked at if there were default arg tokens to parse. Changed to check the hasUnparsedDefaultArg state instead. This puts both the original function decl and the befriending decl on the late parsing list.

3) Parser::ParseLexedMethodDeclaration now needs to handle the case of an inherited default parm. At the point it meets this decl, the original default parm will have been parsed, so it just needs to duplicate the code that is now skipped in MergeCXXFunctionDecl.

It has to look at the hasUnparsedDefaultArg flag before the ActOnDelayedCXXMethodParameter call, because that clears the state. I wonder whether the processing I've added to ParseLexedMethodDeclaration should be put in ActOnDelayedCXXMethodParameter anyway? (we'd need to add FunctionDecl and ParmIndex parameters if so). Alternatively should the now duplicated code propagating the default arg be broken out of MergeCXXFunctionDecl and called from there and ParseLexedMethodDeclaration?

I added a new test tools/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p9.cpp, as this is a bug in default arg handling, not in friendliness.

tested on x86_64-linux, ok?

nathan
Index: tools/clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- tools/clang/lib/Sema/SemaDeclCXX.cpp	(revision 227577)
+++ tools/clang/lib/Sema/SemaDeclCXX.cpp	(working copy)
@@ -521,7 +521,9 @@ bool Sema::MergeCXXFunctionDecl(Function
       // It's important to use getInit() here;  getDefaultArg()
       // strips off any top-level ExprWithCleanups.
       NewParam->setHasInheritedDefaultArg();
-      if (OldParam->hasUninstantiatedDefaultArg())
+      if (OldParam->hasUnparsedDefaultArg ())
+        NewParam->setUnparsedDefaultArg ();
+      else if (OldParam->hasUninstantiatedDefaultArg())
         NewParam->setUninstantiatedDefaultArg(
                                       OldParam->getUninstantiatedDefaultArg());
       else
Index: tools/clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- tools/clang/lib/Parse/ParseDeclCXX.cpp	(revision 227577)
+++ tools/clang/lib/Parse/ParseDeclCXX.cpp	(working copy)
@@ -1890,11 +1890,13 @@ void Parser::HandleMemberFunctionDeclDel
 
   if (!NeedLateParse)
     // Look ahead to see if there are any default args
-    for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx)
-      if (FTI.Params[ParamIdx].DefaultArgTokens) {
+    for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) {
+      auto Param = cast<ParmVarDecl>(FTI.Params[ParamIdx].Param);
+      if (Param->hasUnparsedDefaultArg()) {
         NeedLateParse = true;
         break;
       }
+    }
 
   if (NeedLateParse) {
     // Push this method onto the stack of late-parsed method
Index: tools/clang/lib/Parse/ParseCXXInlineMethods.cpp
===================================================================
--- tools/clang/lib/Parse/ParseCXXInlineMethods.cpp	(revision 227577)
+++ tools/clang/lib/Parse/ParseCXXInlineMethods.cpp	(working copy)
@@ -306,8 +306,9 @@ void Parser::ParseLexedMethodDeclaration
   ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
                             Scope::FunctionDeclarationScope | Scope::DeclScope);
   for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
-    auto Param = LM.DefaultArgs[I].Param;
+    auto Param = cast<ParmVarDecl>(LM.DefaultArgs[I].Param);
     // Introduce the parameter into scope.
+    bool HasUnparsed = Param->hasUnparsedDefaultArg();
     Actions.ActOnDelayedCXXMethodParameter(getCurScope(), Param);
     if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
       // Mark the end of the default argument so that we know when to stop when
@@ -371,6 +372,16 @@ void Parser::ParseLexedMethodDeclaration
 
       delete Toks;
       LM.DefaultArgs[I].Toks = nullptr;
+    } else if (HasUnparsed) {
+      assert(Param->hasInheritedDefaultArg());
+      FunctionDecl *Old = cast<FunctionDecl>(LM.Method)->getPreviousDecl();
+      ParmVarDecl *OldParam = Old->getParamDecl(I);
+      assert (!OldParam->hasUnparsedDefaultArg());
+      if (OldParam->hasUninstantiatedDefaultArg())
+        Param->setUninstantiatedDefaultArg(
+                                      Param->getUninstantiatedDefaultArg());
+      else
+        Param->setDefaultArg(OldParam->getInit());
     }
   }
 
Index: tools/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p9.cpp
===================================================================
--- tools/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p9.cpp	(revision 0)
+++ tools/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p9.cpp	(working copy)
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR 18432
+
+struct A {
+  struct B {
+    static void Foo (int = 0);
+  };
+
+  // should not hide default args
+  friend void B::Foo (int);
+};
+
+void Test ()
+{
+  A::B::Foo ();
+}
# svn diff ./tools/clang/tools/extra
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to