Author: Iain Sandoe Date: 2023-02-02T10:51:08Z New Revision: cdd44e2c85542d152aef19cfd1d2ad451d774935
URL: https://github.com/llvm/llvm-project/commit/cdd44e2c85542d152aef19cfd1d2ad451d774935 DIFF: https://github.com/llvm/llvm-project/commit/cdd44e2c85542d152aef19cfd1d2ad451d774935.diff LOG: [C++20][Modules] Handle template declarations in header units. This addresses part of https://github.com/llvm/llvm-project/issues/60079 The test for external functions was not considering function templates. Differential Revision: https://reviews.llvm.org/D142704 Added: Modified: clang/lib/Sema/SemaDecl.cpp clang/test/CXX/module/module.import/p6.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0cfabed8c7dc..b2bece4d9db0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13090,9 +13090,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // C++ [module.import/6] external definitions are not permitted in header // units. if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() && - VDecl->isThisDeclarationADefinition() && + !VDecl->isInvalidDecl() && VDecl->isThisDeclarationADefinition() && VDecl->getFormalLinkage() == Linkage::ExternalLinkage && - !VDecl->isInline()) { + !VDecl->isInline() && !VDecl->isTemplated() && + !isa<VarTemplateSpecializationDecl>(VDecl)) { Diag(VDecl->getLocation(), diag::err_extern_def_in_header_unit); VDecl->setInvalidDecl(); } @@ -15261,9 +15262,10 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, // FIXME: Consider an alternate location for the test where the inlined() // state is complete. if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() && + !FD->isInvalidDecl() && !FD->isInlined() && + BodyKind != FnBodyKind::Delete && BodyKind != FnBodyKind::Default && FD->getFormalLinkage() == Linkage::ExternalLinkage && - !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete && - BodyKind != FnBodyKind::Default && !FD->isInlined()) { + !FD->isTemplated() && !FD->isTemplateInstantiation()) { assert(FD->isThisDeclarationADefinition()); Diag(FD->getLocation(), diag::err_extern_def_in_header_unit); FD->setInvalidDecl(); diff --git a/clang/test/CXX/module/module.import/p6.cpp b/clang/test/CXX/module/module.import/p6.cpp index 4360d3e67385..0ed8b5958dff 100644 --- a/clang/test/CXX/module/module.import/p6.cpp +++ b/clang/test/CXX/module/module.import/p6.cpp @@ -22,6 +22,8 @@ int ok_var_decl; 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,32 @@ struct S { S(S&); }; S::S(S&) = default; + +template <class _X> +_X tmpl_var_ok_0 = static_cast<_X>(-1); + +template <typename _T> +constexpr _T tmpl_var_ok_1 = static_cast<_T>(42); + +inline int a = tmpl_var_ok_1<int>; + +template <typename _Tp, + template <typename> class _T> +constexpr int tmpl_var_ok_2 = _T<_Tp>::value ? 42 : 6174 ; + +template<class _Ep> +int tmpl_OK (_Ep) { return 0; } + +template <class _T1> +bool +operator==(_T1& , _T1& ) { return false; } + +constexpr long one_k = 1000L; + +template <class ..._Args> +void* tmpl_fn_ok +(_Args ...__args) { return nullptr; } + +inline int foo (int a) { + return tmpl_OK (a); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits