diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-10-10 22:33:17 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-10-10 22:33:17 +0000 |
commit | 6bbe311027780821d6f83b00aa730e434648b691 (patch) | |
tree | 9afc7f1bb903ef1bec9986049b17da1cf0b69a53 | |
parent | 2e86b2ecf1cfba047a8ccebf5a4499abe58dccb2 (diff) | |
download | clang-6bbe311027780821d6f83b00aa730e434648b691.tar.gz |
[Modules TS] Module ownership semantics for redeclarations.
When declaring an entity in the "purview" of a module, it's never a
redeclaration of an entity in the purview of a default module or in no module
("in the global module"). Don't consider those other declarations as possible
redeclaration targets if they're not visible, and reject any cases where we
pick a prior visible declaration that violates this rule.
This reinstates r315251 and r315256, reverted in r315309 and r315308
respectively, tweaked to avoid triggering a linkage calculation when declaring
implicit special members (this exposed our pre-existing issue with typedef
names for linkage changing the linkage of types whose linkage has already been
computed and cached in more cases). A testcase for that regression has been
added in r315366.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@315379 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Decl.h | 10 | ||||
-rw-r--r-- | include/clang/AST/DeclBase.h | 7 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | include/clang/Sema/Lookup.h | 25 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 41 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 18 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 5 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 85 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 30 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 28 | ||||
-rw-r--r-- | lib/Sema/SemaExprMember.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 30 | ||||
-rw-r--r-- | lib/Sema/SemaOpenMP.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 17 | ||||
-rw-r--r-- | test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp | 55 | ||||
-rw-r--r-- | test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp | 19 | ||||
-rw-r--r-- | test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp | 44 | ||||
-rw-r--r-- | test/Modules/anon-linkage.cpp | 12 | ||||
-rw-r--r-- | test/SemaCXX/modules-ts.cppm | 2 |
21 files changed, 372 insertions, 79 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 5160cc82b4..3dcd7a89a7 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -339,6 +339,12 @@ public: return clang::isExternallyVisible(getLinkageInternal()); } + /// Determine whether this declaration can be redeclared in a + /// different translation unit. + bool isExternallyDeclarable() const { + return isExternallyVisible() && !getOwningModuleForLinkage(); + } + /// \brief Determines the visibility of this entity. Visibility getVisibility() const { return getLinkageAndVisibility().getVisibility(); @@ -379,10 +385,6 @@ public: return hasCachedLinkage(); } - /// Get the module that owns this declaration for linkage purposes. - /// There only ever is such a module under the C++ Modules TS. - Module *getOwningModuleForLinkage() const; - /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. NamedDecl *getUnderlyingDecl() { diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index fe9b96ffe1..47515a848a 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -738,6 +738,13 @@ public: return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule(); } + /// Get the module that owns this declaration for linkage purposes. + /// There only ever is such a module under the C++ Modules TS. + /// + /// \param IgnoreLinkage Ignore the linkage of the entity; assume that + /// all declarations in a global module fragment are unowned. + Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const; + /// \brief Determine whether this declaration might be hidden from name /// lookup. Note that the declaration might be visible even if this returns /// \c false, if the owning module is visible within the query context. diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index df5d7473ec..3479be934a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4801,6 +4801,9 @@ def err_thread_non_thread : Error< def err_thread_thread_different_kind : Error< "thread-local declaration of %0 with %select{static|dynamic}1 initialization " "follows declaration with %select{dynamic|static}1 initialization">; +def err_mismatched_owning_module : Error< + "declaration of %0 in %select{the global module|module %2}1 follows " + "declaration in %select{the global module|module %4}3">; def err_redefinition_different_type : Error< "redefinition of %0 with a different type%diff{: $ vs $|}1,2">; def err_redefinition_different_kind : Error< diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h index ea32997d40..546df8842a 100644 --- a/include/clang/Sema/Lookup.h +++ b/include/clang/Sema/Lookup.h @@ -139,6 +139,7 @@ public: LookupKind(LookupKind), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), + ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration), AllowHidden(false), @@ -161,6 +162,7 @@ public: LookupKind(LookupKind), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), + ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration), AllowHidden(false), @@ -181,6 +183,7 @@ public: LookupKind(Other.LookupKind), IDNS(Other.IDNS), Redecl(Other.Redecl), + ExternalRedecl(Other.ExternalRedecl), HideTags(Other.HideTags), Diagnose(false), AllowHidden(Other.AllowHidden), @@ -201,7 +204,9 @@ public: SemaPtr(std::move(Other.SemaPtr)), NameInfo(std::move(Other.NameInfo)), NameContextRange(std::move(Other.NameContextRange)), LookupKind(std::move(Other.LookupKind)), IDNS(std::move(Other.IDNS)), - Redecl(std::move(Other.Redecl)), HideTags(std::move(Other.HideTags)), + Redecl(std::move(Other.Redecl)), + ExternalRedecl(std::move(Other.ExternalRedecl)), + HideTags(std::move(Other.HideTags)), Diagnose(std::move(Other.Diagnose)), AllowHidden(std::move(Other.AllowHidden)), Shadowed(std::move(Other.Shadowed)) { @@ -221,6 +226,7 @@ public: LookupKind = std::move(Other.LookupKind); IDNS = std::move(Other.IDNS); Redecl = std::move(Other.Redecl); + ExternalRedecl = std::move(Other.ExternalRedecl); HideTags = std::move(Other.HideTags); Diagnose = std::move(Other.Diagnose); AllowHidden = std::move(Other.AllowHidden); @@ -265,6 +271,17 @@ public: return Redecl; } + /// True if this lookup is just looking for an existing declaration to link + /// against a declaration with external linkage. + bool isForExternalRedeclaration() const { + return ExternalRedecl; + } + + Sema::RedeclarationKind redeclarationKind() const { + return ExternalRedecl ? Sema::ForExternalRedeclaration : + Redecl ? Sema::ForVisibleRedeclaration : Sema::NotForRedeclaration; + } + /// \brief Specify whether hidden declarations are visible, e.g., /// for recovery reasons. void setAllowHidden(bool AH) { @@ -275,7 +292,7 @@ public: /// declarations, such as those in modules that have not yet been imported. bool isHiddenDeclarationVisible(NamedDecl *ND) const { return AllowHidden || - (isForRedeclaration() && ND->hasExternalFormalLinkage()); + (isForExternalRedeclaration() && ND->isExternallyDeclarable()); } /// Sets whether tag declarations should be hidden by non-tag @@ -556,7 +573,8 @@ public: /// \brief Change this lookup's redeclaration kind. void setRedeclarationKind(Sema::RedeclarationKind RK) { - Redecl = RK; + Redecl = (RK != Sema::NotForRedeclaration); + ExternalRedecl = (RK == Sema::ForExternalRedeclaration); configure(); } @@ -719,6 +737,7 @@ private: unsigned IDNS; // set by configure() bool Redecl; + bool ExternalRedecl; /// \brief True if tag declarations should be hidden if non-tags /// are present diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b33f63225c..277c62f543 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -285,15 +285,21 @@ class Sema { bool isVisibleSlow(const NamedDecl *D); + /// Determine whether two declarations should be linked together, given that + /// the old declaration might not be visible and the new declaration might + /// not have external linkage. bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, const NamedDecl *New) { - // We are about to link these. It is now safe to compute the linkage of - // the new decl. If the new decl has external linkage, we will - // link it with the hidden decl (which also has external linkage) and - // it will keep having external linkage. If it has internal linkage, we - // will not link it. Since it has no previous decls, it will remain - // with internal linkage. - return isVisible(Old) || New->isExternallyVisible(); + if (isVisible(Old)) + return true; + // See comment in below overload for why it's safe to compute the linkage + // of the new declaration here. + if (New->isExternallyDeclarable()) { + assert(Old->isExternallyDeclarable() && + "should not have found a non-externally-declarable previous decl"); + return true; + } + return false; } bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); @@ -3035,10 +3041,25 @@ public: /// purpose of redeclaring the name. NotForRedeclaration = 0, /// \brief The lookup results will be used for redeclaration of a name, - /// if an entity by that name already exists. - ForRedeclaration + /// if an entity by that name already exists and is visible. + ForVisibleRedeclaration, + /// \brief The lookup results will be used for redeclaration of a name + /// with external linkage; non-visible lookup results with external linkage + /// may also be found. + ForExternalRedeclaration }; + RedeclarationKind forRedeclarationInCurContext() { + // A declaration with an owning module for linkage can never link against + // anything that is not visible. We don't need to check linkage here; if + // the context has internal linkage, redeclaration lookup won't find things + // from other TUs, and we can't safely compute linkage yet in general. + if (cast<Decl>(CurContext) + ->getOwningModuleForLinkage(/*IgnoreLinkage*/true)) + return ForVisibleRedeclaration; + return ForExternalRedeclaration; + } + /// \brief The possible outcomes of name lookup for a literal operator. enum LiteralOperatorLookupResult { /// \brief The lookup resulted in an error. @@ -3266,6 +3287,8 @@ public: void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace); + bool CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old); + void DiagnoseAmbiguousLookup(LookupResult &Result); //@} diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 6e5f638bd5..4a9b9bea83 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -515,6 +515,7 @@ static bool isSingleLineLanguageLinkage(const Decl &D) { } static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { + // FIXME: Handle isModulePrivate. switch (D->getModuleOwnershipKind()) { case Decl::ModuleOwnershipKind::Unowned: case Decl::ModuleOwnershipKind::ModulePrivate: @@ -546,7 +547,8 @@ static LinkageInfo getExternalLinkageFor(const NamedDecl *D) { // declaration has module linkage. if (auto *M = D->getOwningModule()) if (M->Kind == Module::ModuleInterfaceUnit) - if (!isExportedFromModuleIntefaceUnit(D)) + if (!isExportedFromModuleIntefaceUnit( + cast<NamedDecl>(D->getCanonicalDecl()))) return LinkageInfo(ModuleLinkage, DefaultVisibility, false); return LinkageInfo::external(); @@ -1393,7 +1395,7 @@ LinkageInfo LinkageComputer::getDeclLinkageAndVisibility(const NamedDecl *D) { : NamedDecl::VisibilityForValue)); } -Module *NamedDecl::getOwningModuleForLinkage() const { +Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const { Module *M = getOwningModule(); if (!M) return nullptr; @@ -1411,7 +1413,17 @@ Module *NamedDecl::getOwningModuleForLinkage() const { // for linkage purposes. But internal linkage declarations in the global // module fragment of a particular module are owned by that module for // linkage purposes. - return hasExternalFormalLinkage() ? nullptr : M->Parent; + if (IgnoreLinkage) + return nullptr; + bool InternalLinkage; + if (auto *ND = dyn_cast<NamedDecl>(this)) + InternalLinkage = !ND->hasExternalFormalLinkage(); + else { + auto *NSD = dyn_cast<NamespaceDecl>(this); + InternalLinkage = (NSD && NSD->isAnonymousNamespace()) || + isInAnonymousNamespace(); + } + return InternalLinkage ? M->Parent : nullptr; } llvm_unreachable("unknown module kind"); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 42f0ba0bd7..1e15ee98bb 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -315,12 +315,11 @@ bool Decl::isLexicallyWithinFunctionOrMethod() const { } bool Decl::isInAnonymousNamespace() const { - const DeclContext *DC = getDeclContext(); - do { + for (const DeclContext *DC = getDeclContext(); DC; DC = DC->getParent()) { if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC)) if (ND->isAnonymousNamespace()) return true; - } while ((DC = DC->getParent())); + } return false; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index a9759b4c0a..26e5c4ffbe 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -100,7 +100,7 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, - CXXRecordDecl* PrevDecl, + CXXRecordDecl *PrevDecl, bool DelayTypeCreation) { CXXRecordDecl *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 541cf693b6..a74cb57eab 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1448,6 +1448,46 @@ void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, F.done(); } +/// We've determined that \p New is a redeclaration of \p Old. Check that they +/// have compatible owning modules. +bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { + // FIXME: The Modules TS is not clear about how friend declarations are + // to be treated. It's not meaningful to have different owning modules for + // linkage in redeclarations of the same entity, so for now allow the + // redeclaration and change the owning modules to match. + if (New->getFriendObjectKind() && + Old->getOwningModuleForLinkage() != New->getOwningModuleForLinkage()) { + New->setLocalOwningModule(Old->getOwningModule()); + makeMergedDefinitionVisible(New); + return false; + } + + Module *NewM = New->getOwningModule(); + Module *OldM = Old->getOwningModule(); + if (NewM == OldM) + return false; + + // FIXME: Check proclaimed-ownership-declarations here too. + bool NewIsModuleInterface = NewM && NewM->Kind == Module::ModuleInterfaceUnit; + bool OldIsModuleInterface = OldM && OldM->Kind == Module::ModuleInterfaceUnit; + if (NewIsModuleInterface || OldIsModuleInterface) { + // C++ Modules TS [basic.def.odr] 6.2/6.7 [sic]: + // if a declaration of D [...] appears in the purview of a module, all + // other such declarations shall appear in the purview of the same module + Diag(New->getLocation(), diag::err_mismatched_owning_module) + << New + << NewIsModuleInterface + << (NewIsModuleInterface ? NewM->getFullModuleName() : "") + << OldIsModuleInterface + << (OldIsModuleInterface ? OldM->getFullModuleName() : ""); + Diag(Old->getLocation(), diag::note_previous_declaration); + New->setInvalidDecl(); + return true; + } + + return false; +} + static bool isUsingDecl(NamedDecl *D) { return isa<UsingShadowDecl>(D) || isa<UnresolvedUsingTypenameDecl>(D) || @@ -2962,6 +3002,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, New->dropAttr<InternalLinkageAttr>(); } + if (CheckRedeclarationModuleOwnership(New, Old)) + return true; + if (!getLangOpts().CPlusPlus) { bool OldOvl = Old->hasAttr<OverloadableAttr>(); if (OldOvl != New->hasAttr<OverloadableAttr>() && !Old->isImplicit()) { @@ -3831,6 +3874,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } + if (CheckRedeclarationModuleOwnership(New, Old)) + return; + // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still @@ -4382,7 +4428,7 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, SourceLocation NameLoc, bool IsUnion) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName, - Sema::ForRedeclaration); + Sema::ForVisibleRedeclaration); if (!SemaRef.LookupName(R, S)) return false; // Pick a representative declaration. @@ -5321,7 +5367,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.setInvalidType(); LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); // See if this is a redefinition of a variable in the same scope. if (!D.getCXXScopeSpec().isSet()) { @@ -5347,8 +5393,10 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) CreateBuiltins = true; - if (IsLinkageLookup) + if (IsLinkageLookup) { Previous.clear(LookupRedeclarationWithLinkage); + Previous.setRedeclarationKind(ForExternalRedeclaration); + } LookupName(Previous, S, CreateBuiltins); } else { // Something like "int foo::x;" @@ -7112,7 +7160,7 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) { return; LookupResult R(*this, D->getDeclName(), D->getLocation(), - Sema::LookupOrdinaryName, Sema::ForRedeclaration); + Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); LookupName(R, S); if (NamedDecl *ShadowedDecl = getShadowedDeclaration(D, R)) CheckShadow(D, ShadowedDecl, R); @@ -7688,7 +7736,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration( LookupResult Prev(SemaRef, Name, NewFD->getLocation(), IsLocalFriend ? Sema::LookupLocalFriendName : Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + Sema::ForVisibleRedeclaration); NewFD->setInvalidDecl(); if (IsLocalFriend) @@ -11724,7 +11772,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Check for redeclaration of parameters, e.g. int foo(int x, int x); if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, - ForRedeclaration); + ForVisibleRedeclaration); LookupName(R, S); if (R.isSingleResult()) { NamedDecl *PrevDecl = R.getFoundDecl(); @@ -13284,7 +13332,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, bool isStdBadAlloc = false; bool isStdAlignValT = false; - RedeclarationKind Redecl = ForRedeclaration; + RedeclarationKind Redecl = forRedeclarationInCurContext(); if (TUK == TUK_Friend || TUK == TUK_Reference) Redecl = NotForRedeclaration; @@ -13562,10 +13610,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // type declared by an elaborated-type-specifier. In C that is not correct // and we should instead merge compatible types found by lookup. if (getLangOpts().CPlusPlus) { - Previous.setRedeclarationKind(ForRedeclaration); + Previous.setRedeclarationKind(forRedeclarationInCurContext()); LookupQualifiedName(Previous, SearchDC); } else { - Previous.setRedeclarationKind(ForRedeclaration); + Previous.setRedeclarationKind(forRedeclarationInCurContext()); LookupName(Previous, S); } } @@ -14063,6 +14111,9 @@ CreateNewDecl: if (!Invalid && SearchDC->isRecord()) SetMemberAccessSpecifier(New, PrevDecl, AS); + if (PrevDecl) + CheckRedeclarationModuleOwnership(New, PrevDecl); + if (TUK == TUK_Definition) New->startDefinition(); @@ -14416,7 +14467,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = nullptr; - LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); + LookupResult Previous(*this, II, Loc, LookupMemberName, + ForVisibleRedeclaration); LookupName(Previous, S); switch (Previous.getResultKind()) { case LookupResult::Found: @@ -14804,7 +14856,7 @@ Decl *Sema::ActOnIvar(Scope *S, if (II) { NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, - ForRedeclaration); + ForVisibleRedeclaration); if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa<TagDecl>(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; @@ -15525,7 +15577,7 @@ Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, // determine if we should merge the definition with an existing one and // skip the body. NamedDecl *PrevDecl = LookupSingleName(S, II, IILoc, LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); auto *PrevECD = dyn_cast_or_null<EnumConstantDecl>(PrevDecl); if (!PrevECD) return SkipBodyInfo(); @@ -15556,7 +15608,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, // Verify that there isn't already something declared with this name in this // scope. NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName, - ForRedeclaration); + ForVisibleRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); @@ -15583,8 +15635,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, // enum constant will 'hide' the tag. assert((getLangOpts().CPlusPlus || !isa<TagDecl>(PrevDecl)) && "Received TagDecl when not in C++!"); - if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S) && - shouldLinkPossiblyHiddenDecl(PrevDecl, New)) { + if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) { if (isa<EnumConstantDecl>(PrevDecl)) Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; else @@ -16166,7 +16217,8 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, else if (const auto *FE = M->getASTFile()) Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) << FE->getName(); - return nullptr; + Mod = M; + break; } // Create a Module for the module that we're defining. @@ -16185,6 +16237,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, PP.getIdentifierInfo(ModuleName), Path[0].second); Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible, /*IsIncludeDirective=*/false); + // FIXME: Produce an error in this case. if (!Mod) return nullptr; break; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 5d9a39c677..c385e0481b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -790,7 +790,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // Check for name conflicts. DeclarationNameInfo NameInfo(B.Name, B.NameLoc); LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - ForRedeclaration); + ForVisibleRedeclaration); LookupName(Previous, S, /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit()); @@ -822,7 +822,8 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // is unnamed. DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr, Decomp.getLSquareLoc()); - LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForVisibleRedeclaration); // Build the variable that holds the non-decomposed object. bool AddToScope = true; @@ -8465,7 +8466,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // Since namespace names are unique in their scope, and we don't // look through using directives, just look for any ordinary names // as if by qualified name lookup. - LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, ForRedeclaration); + LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, + ForExternalRedeclaration); LookupQualifiedName(R, CurContext->getRedeclContext()); NamedDecl *PrevDecl = R.isSingleResult() ? R.getRepresentativeDecl() : nullptr; @@ -9402,7 +9404,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Do the redeclaration lookup in the current scope. LookupResult Previous(*this, UsingName, LookupUsingDeclName, - ForRedeclaration); + ForVisibleRedeclaration); Previous.setHideTags(false); if (S) { LookupName(Previous, S); @@ -9982,7 +9984,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, TInfo->getTypeLoc().getBeginLoc()); } - LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + TemplateParamLists.size() + ? forRedeclarationInCurContext() + : ForVisibleRedeclaration); LookupName(Previous, S); // Warn about shadowing the name of a template parameter. @@ -10085,8 +10090,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (Invalid) NewDecl->setInvalidDecl(); - else if (OldDecl) + else if (OldDecl) { NewDecl->setPreviousDecl(OldDecl); + CheckRedeclarationModuleOwnership(NewDecl, OldDecl); + } NewND = NewDecl; } else { @@ -10127,7 +10134,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, // Check if we have a previous declaration with the same name. LookupResult PrevR(*this, Alias, AliasLoc, LookupOrdinaryName, - ForRedeclaration); + ForVisibleRedeclaration); LookupName(PrevR, S); // Check we're not shadowing a template parameter. @@ -10340,7 +10347,7 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) { // implicit special members with this name. DeclarationName Name = FD->getDeclName(); LookupResult R(*this, Name, SourceLocation(), LookupOrdinaryName, - ForRedeclaration); + ForExternalRedeclaration); for (auto *D : FD->getParent()->lookup(Name)) if (auto *Acceptable = R.getAcceptableDecl(D)) R.addDecl(Acceptable); @@ -13224,7 +13231,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { IdentifierInfo *II = D.getIdentifier(); if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), LookupOrdinaryName, - ForRedeclaration)) { + ForVisibleRedeclaration)) { // The scope should be freshly made just for us. There is just no way // it contains any previous declaration, except for function parameters in // a function-try-block's catch statement. @@ -13673,7 +13680,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, DeclContext *DC; Scope *DCScope = S; LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - ForRedeclaration); + ForExternalRedeclaration); // There are five cases here. // - There's no scope specifier and we're in a local class. Only look @@ -14947,7 +14954,8 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = nullptr; - LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); + LookupResult Previous(*this, II, Loc, LookupMemberName, + ForVisibleRedeclaration); LookupName(Previous, S); switch (Previous.getResultKind()) { case LookupResult::Found: diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 6b33f7c64c..5ab9d80c00 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -943,8 +943,9 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, assert(ClassName && "Missing class identifier"); // Check for another declaration kind with the same name. - NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc, - LookupOrdinaryName, ForRedeclaration); + NamedDecl *PrevDecl = + LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName, + forRedeclarationInCurContext()); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; @@ -1095,16 +1096,18 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc, IdentifierInfo *ClassName, SourceLocation ClassLocation) { // Look for previous declaration of alias name - NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation, - LookupOrdinaryName, ForRedeclaration); + NamedDecl *ADecl = + LookupSingleName(TUScope, AliasName, AliasLocation, LookupOrdinaryName, + forRedeclarationInCurContext()); if (ADecl) { Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName; Diag(ADecl->getLocation(), diag::note_previous_declaration); return nullptr; } // Check for class declaration - NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, - LookupOrdinaryName, ForRedeclaration); + NamedDecl *CDeclU = + LookupSingleName(TUScope, ClassName, ClassLocation, LookupOrdinaryName, + forRedeclarationInCurContext()); if (const TypedefNameDecl *TDecl = dyn_cast_or_null<TypedefNameDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); @@ -1112,7 +1115,8 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc, if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { ClassName = IDecl->getIdentifier(); CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, - LookupOrdinaryName, ForRedeclaration); + LookupOrdinaryName, + forRedeclarationInCurContext()); } } } @@ -1174,7 +1178,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); ObjCProtocolDecl *PrevDecl = LookupProtocol(ProtocolName, ProtocolLoc, - ForRedeclaration); + forRedeclarationInCurContext()); ObjCProtocolDecl *PDecl = nullptr; if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) { // If we already have a definition, complain. @@ -1730,7 +1734,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, for (const IdentifierLocPair &IdentPair : IdentList) { IdentifierInfo *Ident = IdentPair.first; ObjCProtocolDecl *PrevDecl = LookupProtocol(Ident, IdentPair.second, - ForRedeclaration); + forRedeclarationInCurContext()); ObjCProtocolDecl *PDecl = ObjCProtocolDecl::Create(Context, CurContext, Ident, IdentPair.second, AtProtocolLoc, @@ -1921,7 +1925,7 @@ Decl *Sema::ActOnStartClassImplementation( // Check for another declaration kind with the same name. NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); @@ -2997,7 +3001,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, // Check for another declaration kind with the same name. NamedDecl *PrevDecl = LookupSingleName(TUScope, IdentList[i], IdentLocs[i], - LookupOrdinaryName, ForRedeclaration); + LookupOrdinaryName, forRedeclarationInCurContext()); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { // GCC apparently allows the following idiom: // @@ -4443,7 +4447,7 @@ Decl *Sema::ActOnMethodDeclaration( } LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc, - LookupOrdinaryName, ForRedeclaration); + LookupOrdinaryName, forRedeclarationInCurContext()); LookupName(R, S); if (R.isSingleResult()) { NamedDecl *PrevDecl = R.getFoundDecl(); diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index fc776e31a4..c3561f6400 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -693,8 +693,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, Sema::RedeclarationKind Redecl; }; QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(), - R.isForRedeclaration() ? Sema::ForRedeclaration - : Sema::NotForRedeclaration}; + R.redeclarationKind()}; TE = SemaRef.CorrectTypoDelayed( R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, llvm::make_unique<RecordMemberExprValidatorCCC>(RTy), diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index a89d3ace24..6fb0260075 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1609,11 +1609,39 @@ bool Sema::isVisibleSlow(const NamedDecl *D) { } bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) { + // FIXME: If there are both visible and hidden declarations, we need to take + // into account whether redeclaration is possible. Example: + // + // Non-imported module: + // int f(T); // #1 + // Some TU: + // static int f(U); // #2, not a redeclaration of #1 + // int f(T); // #3, finds both, should link with #1 if T != U, but + // // with #2 if T == U; neither should be ambiguous. for (auto *D : R) { if (isVisible(D)) return true; + assert(D->isExternallyDeclarable() && + "should not have hidden, non-externally-declarable result here"); } - return New->isExternallyVisible(); + + // This function is called once "New" is essentially complete, but before a + // previous declaration is attached. We can't query the linkage of "New" in + // general, because attaching the previous declaration can change the + // linkage of New to match the previous declaration. + // + // However, because we've just determined that there is no *visible* prior + // declaration, we can compute the linkage here. There are two possibilities: + // + // * This is not a redeclaration; it's safe to compute the linkage now. + // + // * This is a redeclaration of a prior declaration that is externally + // redeclarable. In that case, the linkage of the declaration is not + // changed by attaching the prior declaration, because both are externally + // declarable (and thus ExternalLinkage or VisibleNoLinkage). + // + // FIXME: This is subtle and fragile. + return New->isExternallyDeclarable(); } /// \brief Retrieve the visible declaration corresponding to D, if any. diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 4ab78f11ab..a024888fbf 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -11539,7 +11539,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart( Decls.reserve(ReductionTypes.size()); LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName, - ForRedeclaration); + forRedeclarationInCurContext()); // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions // A reduction-identifier may not be re-declared in the current scope for the // same type or for a type that is compatible according to the base language diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 1ce57e56c3..46cda5e9ac 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -778,7 +778,7 @@ static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, SourceLocation Loc, IdentifierInfo *Name) { NamedDecl *PrevDecl = SemaRef.LookupSingleName( - S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForRedeclaration); + S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl); } @@ -1133,7 +1133,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupResult Previous(*this, Name, NameLoc, (SS.isEmpty() && TUK == TUK_Friend) ? LookupTagName : LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); if (SS.isNotEmpty() && !SS.isInvalid()) { SemanticContext = computeDeclContext(SS, true); if (!SemanticContext) { @@ -1192,8 +1192,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // If there is a previous declaration with the same name, check // whether this is a valid redeclaration. - ClassTemplateDecl *PrevClassTemplate - = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); + ClassTemplateDecl *PrevClassTemplate = + dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); // We may have found the injected-class-name of a class template, // class template partial specialization, or class template specialization. @@ -1484,6 +1484,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, CurContext->addDecl(Friend); } + if (PrevClassTemplate) + CheckRedeclarationModuleOwnership(NewTemplate, PrevClassTemplate); + if (Invalid) { NewTemplate->setInvalidDecl(); NewClass->setInvalidDecl(); @@ -3677,7 +3680,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // Check that this isn't a redefinition of this specialization, // merging with previous declarations. LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName, - ForRedeclaration); + forRedeclarationInCurContext()); PrevSpec.addDecl(PrevDecl); D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec)); } else if (Specialization->isStaticDataMember() && diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b37ca664f7..3800ea6659 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1195,7 +1195,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Look for a previous declaration of the template in the owning // context. LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(), - Sema::LookupOrdinaryName, Sema::ForRedeclaration); + Sema::LookupOrdinaryName, + SemaRef.forRedeclarationInCurContext()); SemaRef.LookupQualifiedName(R, DC); if (R.isSingleResult()) { @@ -1735,7 +1736,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, SemaRef, Function->getDeclName(), SourceLocation(), D->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage : Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + D->isLocalExternDecl() ? Sema::ForExternalRedeclaration + : SemaRef.forRedeclarationInCurContext()); if (DependentFunctionTemplateSpecializationInfo *Info = D->getDependentSpecializationInfo()) { @@ -2053,7 +2055,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setInvalidDecl(); LookupResult Previous(SemaRef, NameInfo, Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + Sema::ForExternalRedeclaration); if (!FunctionTemplate || TemplateParams || isFriend) { SemaRef.LookupQualifiedName(Previous, Record); @@ -2492,7 +2494,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { bool CheckRedeclaration = Owner->isRecord(); LookupResult Prev(SemaRef, NameInfo, Sema::LookupUsingDeclName, - Sema::ForRedeclaration); + Sema::ForVisibleRedeclaration); UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(), @@ -2711,7 +2713,7 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( return nullptr; LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + Sema::ForExternalRedeclaration); TemplateArgumentListInfo TemplateArgs; TemplateArgumentListInfo *TemplateArgsPtr = nullptr; @@ -4074,7 +4076,8 @@ void Sema::BuildVariableInstantiation( *this, NewVar->getDeclName(), NewVar->getLocation(), NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage : Sema::LookupOrdinaryName, - Sema::ForRedeclaration); + NewVar->isLocalExternDecl() ? Sema::ForExternalRedeclaration + : forRedeclarationInCurContext()); if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl() && (!OldVar->getPreviousDecl()->getDeclContext()->isDependentContext() || @@ -4432,7 +4435,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // Merge the definition with the declaration. LookupResult R(*this, Var->getDeclName(), Var->getLocation(), - LookupOrdinaryName, ForRedeclaration); + LookupOrdinaryName, forRedeclarationInCurContext()); R.addDecl(OldVar); MergeVarDecl(Var, R); diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp new file mode 100644 index 0000000000..cceca5106c --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -fmodules-ts -verify -std=c++17 %s +// RUN: %clang_cc1 -fmodules-ts -verify -std=c++17 %s -DEXPORT +// RUN: %clang_cc1 -fmodules-ts -verify -std=c++17 %s -DUSING + +#ifndef NO_GLOBAL +extern int var; // expected-note {{previous declaration is here}} +int func(); // expected-note {{previous declaration is here}} +struct str; // expected-note {{previous declaration is here}} +using type = int; + +template<typename> extern int var_tpl; // expected-note {{previous declaration is here}} +template<typename> int func_tpl(); // expected-note-re {{{{previous declaration is here|target of using declaration}}}} +template<typename> struct str_tpl; // expected-note {{previous declaration is here}} +template<typename> using type_tpl = int; // expected-note {{previous declaration is here}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; +#endif + +export module M; + +#ifdef USING +using ::var; +using ::func; +using ::str; +using ::type; +using ::var_tpl; +using ::func_tpl; // expected-note {{using declaration}} +using ::str_tpl; +using ::type_tpl; +#endif + +#ifdef EXPORT +export { +#endif + +extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}} +int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}} +struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}} +using type = int; + +template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}} +// FIXME: Is this the right diagnostic in the -DUSING case? +template<typename> int func_tpl(); // expected-error-re {{{{declaration of 'func_tpl' in module M follows declaration in the global module|conflicts with target of using declaration}}}} +template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}} +template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; + +#ifdef EXPORT +} +#endif diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp new file mode 100644 index 0000000000..f58506dd9c --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules-ts -emit-module-interface -std=c++17 %S/global-vs-module.cpp -o %t -DNO_GLOBAL -DEXPORT +// RUN: %clang_cc1 -fmodules-ts -verify -std=c++17 %s -fmodule-file=%t + +import M; + +extern int var; // expected-error {{declaration of 'var' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:38 {{previous}} +int func(); // expected-error {{declaration of 'func' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:39 {{previous}} +struct str; // expected-error {{declaration of 'str' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:40 {{previous}} +using type = int; + +template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:43 {{previous}} +template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:45 {{previous}} +template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:46 {{previous}} +template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:47 {{previous}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp new file mode 100644 index 0000000000..39e210c4ad --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp @@ -0,0 +1,44 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// +// Some of the following tests intentionally have no -verify in their RUN +// lines; we are testing that those cases do not produce errors. +// +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %S/global-vs-module.cpp -emit-module-interface -o %t/M.pcm -DNO_GLOBAL -DEXPORT +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/M.pcm -DMODULE_INTERFACE -verify +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/M.pcm -DMODULE_INTERFACE -DNO_IMPORT +// +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/M.pcm -emit-module-interface -o %t/N.pcm -DMODULE_INTERFACE -DNO_ERRORS +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/N.pcm -verify +// FIXME: Once we start importing "import" declarations properly, this should +// be rejected (-verify should be added to the following line). +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/N.pcm -DNO_IMPORT +// +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/M.pcm -emit-module-interface -o %t/N-no-M.pcm -DMODULE_INTERFACE -DNO_ERRORS -DNO_IMPORT +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/N-no-M.pcm -verify +// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/N-no-M.pcm -DNO_IMPORT + +#ifdef MODULE_INTERFACE +export +#endif +module N; + +#ifndef NO_IMPORT +import M; +#endif + +#ifndef NO_ERRORS +extern int var; // expected-error {{declaration of 'var' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:38 {{previous}} +int func(); // expected-error {{declaration of 'func' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:39 {{previous}} +struct str; // expected-error {{declaration of 'str' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:40 {{previous}} +using type = int; + +template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:43 {{previous}} +template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:45 {{previous}} +template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:46 {{previous}} +template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:47 {{previous}} + +typedef int type; +namespace ns { using ::func; } +namespace ns_alias = ns; +#endif diff --git a/test/Modules/anon-linkage.cpp b/test/Modules/anon-linkage.cpp new file mode 100644 index 0000000000..590638292b --- /dev/null +++ b/test/Modules/anon-linkage.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s + +typedef struct { + int c; + union { + int n; + char c[4]; + } v; +} mbstate; + +export module M; +export using ::mbstate; diff --git a/test/SemaCXX/modules-ts.cppm b/test/SemaCXX/modules-ts.cppm index 065818c562..f64a4c0ab4 100644 --- a/test/SemaCXX/modules-ts.cppm +++ b/test/SemaCXX/modules-ts.cppm @@ -14,7 +14,7 @@ export module foo; #endif static int m; -#if TEST == 2 // FIXME: 'm' has internal linkage, so there should be no error here +#if TEST == 2 // expected-error@-2 {{redefinition of '}} // expected-note@-3 {{unguarded header; consider using #ifdef guards or #pragma once}} // FIXME: We should drop the "header from" in this diagnostic. |