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