Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7789,6 +7789,11 @@ "definition or redeclaration of %0 not allowed inside a block">; def err_not_tag_in_scope : Error< "no %select{struct|interface|union|class|enum}0 named %1 in %2">; +def err_export_for_non_namespace_entities : Error < + "We couldn't export %0 which is not in namespace scopes.">; +def err_export_entites_which_is_exported : Error < + "We couldn't export %0 which is exported already. " + "It was exported already at %0.">; def err_no_typeid_with_fno_rtti : Error< "use of typeid requires -frtti">; Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -5745,7 +5745,9 @@ else if (isa(Cur)) Diag(Loc, diag::err_invalid_declarator_in_block) << Name << SS.getRange(); - else + else if (isa(Cur)) { + + } else Diag(Loc, diag::err_invalid_declarator_scope) << Name << cast(Cur) << cast(DC) << SS.getRange(); @@ -5829,6 +5831,22 @@ << D.getCXXScopeSpec().getRange(); return nullptr; } + + if (auto *ED = dyn_cast(CurContext)) { + if (!isa(DC)) { + Diag(ED->getExportLoc(), diag::err_export_for_non_namespace_entities) + << Name; + } else { + auto *TmpDC = DC; + while (TmpDC && !isa(TmpDC)) + TmpDC = TmpDC->getParent(); + if (TmpDC && isa(TmpDC)) { + Diag(ED->getExportLoc(), diag::err_export_entites_which_is_exported) + << Name << NameInfo.getLoc();; + } + } + } + bool IsDependentContext = DC->isDependentContext(); if (!IsDependentContext && @@ -16370,6 +16388,23 @@ Invalid = true; } + if (isa(CurContext) && PrevDecl) { + auto *PrevDC = PrevDecl->getDeclContext(); + if (!isa(PrevDC)) { + Diag(New->getLocation(), diag::err_export_for_non_namespace_entities) + << OrigName; + Invalid = true; + } else { + while (PrevDC && !isa(PrevDC)) + PrevDC = PrevDC->getParent(); + if (PrevDC && isa(PrevDC)) { + Diag(New->getLocation(), diag::err_export_entites_which_is_exported) + << OrigName << PrevDecl->getLocation(); + Invalid = true; + } + } + } + // Maybe add qualifier info. if (SS.isNotEmpty()) { if (SS.isSet()) { Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -3400,11 +3400,11 @@ // class X { // int X::member; // }; - if (DeclContext *DC = computeDeclContext(SS, false)) + if (DeclContext *DC = computeDeclContext(SS, false)) { diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc(), D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId); - else + } else Diag(D.getIdentifierLoc(), diag::err_member_qualification) << Name << SS.getRange(); Index: clang/test/CXX/module/module.interface/tmp6.cpp =================================================================== --- /dev/null +++ clang/test/CXX/module/module.interface/tmp6.cpp @@ -0,0 +1,25 @@ + +// RUN: %clang_cc1 -std=c++20 %s -verify + +export module X; + +export template +struct X { + struct iterator { + T node; + }; +}; + +export template X::iterator; // expected-error {{We couldn't export 'iterator' which is not in namespace scopes.}} +export template typename X::iterator; //expected-error {{declaration does not declare anything}} + +export struct Y { + struct iterator { int Node; }; +}; + +export struct Y::iterator; // expected-error {{We couldn't export 'iterator' which is not in namespace scopes.}} + +struct S { int n; }; +typedef S S; +export typedef S S; // OK, does not redeclare an entity +export struct S; // expected-error {{We couldn't export 'S' which is not in namespace scopes.}}