-
Notifications
You must be signed in to change notification settings - Fork 13.3k
friend function with default parameters causes "redefinition of default argument" error in templates #130917
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Slightly reduced example (Godbolt link): template <int>
void Create(const void* = nullptr);
template <int>
struct ObjImpl {
template <int>
friend void ::Create(const void*);
};
template <int I>
void Create(const void*) {
(void) ObjImpl<I>{};
}
int main() {
Create<42>();
} This is probably a regression since Clang 20. |
@llvm/issue-subscribers-clang-frontend Author: None (wingerZYM)
### Summary:
Starting from commit `38b3d87bd384a469a6618ec6a971352cb4f813ba` in LLVM, Clang 20 reports
`error: redefinition of default argument` when using `friend` functions
in template classes, even though the default argument is only defined once.
Steps to Reproduce:Compile the following minimal example with Clang 20: #include <iostream>
#include <memory>
namespace Work {
namespace detail {
class Obj;
} // namespace detail
using Ptr = std::unique_ptr<detail::Obj>;
template <int>
Ptr Create(const void* key = nullptr); // default argument only once.
namespace detail {
class Obj {
protected:
Obj(const void* key) {
std::cout << "Obj::Obj\n";
}
};
template <int>
class ObjImpl : public Obj {
public:
ObjImpl(const void* key)
: Obj(key) {
std::cout << "ObjImpl::ObjImpl\n";
}
template <int>
friend Ptr Work::Create(const void*);
};
} // namespace detail
template <int i>
Ptr Create(const void* key) { // error: redefinition of default argument
return Ptr(new detail::ObjImpl<i>(key));
}
} // namespace Work
int main() {
auto ptr = Work::Create<192>(nullptr);
return 0;
} Result:clang++ reports:
Workaround:If we remove the default parameter from Ptr Create(const void* key = nullptr);, then Clang++ compiles correctly. Regression:git branch: release/20.x |
If you look at commit which the author pointed out, it's pretty suspect of this problem: #111992 It has changes to template instantiation friend definition tracking, outside of the serialization / modules area, which look suspect and would need careful review. CC @dmpolukhin @ChuanqiXu9 as authors and reviewer of the original commit. |
Oops, sorry I didn't even notice that line! |
I'll take a look what is happening with this example and how to fix it. Unfortunately I don't know the way how to distinguish real redeclarations from artificial redeclaration that happens on AST merges. |
Should I merges this fix to clang-20? |
I think so, yes |
…y a declaration during AST deserialization (llvm#132214) Fix for regression llvm#130917, changes in llvm#111992 were too broad. This change reduces scope of previous fix. Added `ExternalASTSource::wasThisDeclarationADefinition` to detect cases when FunctionDecl lost body due to declaration merges.
Fix cannot be cherry-picked to clang-20, see discussion in #134232 so closing this bug. |
Summary:
Starting from commit
38b3d87bd384a469a6618ec6a971352cb4f813ba
in LLVM, Clang 20 reportserror: redefinition of default argument
when usingfriend
functionsin template classes, even though the default argument is only defined once.
Steps to Reproduce:
Compile the following minimal example with Clang 20:
Result:
clang++ reports:
Workaround:
If we remove the default parameter from Ptr Create(const void* key = nullptr);, then Clang++ compiles correctly.
If we remove the friend declaration, Clang++ also compiles correctly.
Regression:
git branch: release/20.x
First bad commit: 38b3d87
This issue does not occur in earlier versions of branch.
The text was updated successfully, but these errors were encountered: