iains created this revision. Herald added a project: All. iains added reviewers: dblaikie, ChuanqiXu. iains published this revision for review. iains added a comment. Herald added a project: clang. Herald added a subscriber: cfe-commits.
@dblaikie - I suspect that this would be useful on the llvm-16 release branch, and so I've added you as a reviewer, if you have some chance to look .. (I do not think @ChuanqiXu is available until February). The issue here is that the function decl is extracted from function templates (and looks just like any other function definition at this point), so that we need to remember that it came from a template. This addresses part of https://github.com/llvm/llvm-project/issues/60079 The test for external functions was not considering function templates. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D142704 Files: clang/lib/Sema/SemaDecl.cpp clang/test/CXX/module/module.import/p6.cpp Index: clang/test/CXX/module/module.import/p6.cpp =================================================================== --- clang/test/CXX/module/module.import/p6.cpp +++ clang/test/CXX/module/module.import/p6.cpp @@ -22,6 +22,8 @@ int bad_var_definition = 3; // expected-error {{non-inline external definitions are not permitted in C++ header units}} +/* The cases below should compile without diagnostics. */ + class A { public: // This is a declaration instead of definition. @@ -36,3 +38,10 @@ S(S&); }; S::S(S&) = default; + +template<class _Ep> +int tmpl_OK (_Ep) { return 0; } + +template <class _T1> +bool +operator==(_T1& , _T1& ) { return false; } Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -15108,10 +15108,12 @@ } FunctionDecl *FD = nullptr; + bool IsFnTemplate = false; - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) { FD = FunTmpl->getTemplatedDecl(); - else + IsFnTemplate = true; + } else FD = cast<FunctionDecl>(D); // Do not push if it is a lambda because one is already pushed when building @@ -15260,7 +15262,7 @@ // state is complete. if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() && FD->getFormalLinkage() == Linkage::ExternalLinkage && - !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete && + !FD->isInvalidDecl() && !IsFnTemplate && BodyKind != FnBodyKind::Delete && BodyKind != FnBodyKind::Default && !FD->isInlined()) { assert(FD->isThisDeclarationADefinition()); Diag(FD->getLocation(), diag::err_extern_def_in_header_unit);
Index: clang/test/CXX/module/module.import/p6.cpp =================================================================== --- clang/test/CXX/module/module.import/p6.cpp +++ clang/test/CXX/module/module.import/p6.cpp @@ -22,6 +22,8 @@ int bad_var_definition = 3; // expected-error {{non-inline external definitions are not permitted in C++ header units}} +/* The cases below should compile without diagnostics. */ + class A { public: // This is a declaration instead of definition. @@ -36,3 +38,10 @@ S(S&); }; S::S(S&) = default; + +template<class _Ep> +int tmpl_OK (_Ep) { return 0; } + +template <class _T1> +bool +operator==(_T1& , _T1& ) { return false; } Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -15108,10 +15108,12 @@ } FunctionDecl *FD = nullptr; + bool IsFnTemplate = false; - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) { FD = FunTmpl->getTemplatedDecl(); - else + IsFnTemplate = true; + } else FD = cast<FunctionDecl>(D); // Do not push if it is a lambda because one is already pushed when building @@ -15260,7 +15262,7 @@ // state is complete. if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() && FD->getFormalLinkage() == Linkage::ExternalLinkage && - !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete && + !FD->isInvalidDecl() && !IsFnTemplate && BodyKind != FnBodyKind::Delete && BodyKind != FnBodyKind::Default && !FD->isInlined()) { assert(FD->isThisDeclarationADefinition()); Diag(FD->getLocation(), diag::err_extern_def_in_header_unit);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits