diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -227,7 +227,12 @@ /// This declaration has an owning module, but is only visible to /// lookups that occur within that module. - ModulePrivate + ModulePrivate, + + /// This declaration is part of a Global Module Fragment, but is not + /// reachable or visible to importers of the named module of which the + /// GMF is part. + ModuleUnreachable }; protected: @@ -235,8 +240,8 @@ /// DeclContext. These pointers form the linked list that is /// traversed via DeclContext's decls_begin()/decls_end(). /// - /// The extra two bits are used for the ModuleOwnershipKind. - llvm::PointerIntPair NextInContextAndBits; + /// The extra three bits are used for the ModuleOwnershipKind. + llvm::PointerIntPair NextInContextAndBits; private: friend class DeclContext; @@ -587,6 +592,12 @@ void setReferenced(bool R = true) { Referenced = R; } + /// Whether this declaration should be retained if it is used. + bool isModuleUnreachable() const { + return getModuleOwnershipKind() + == Decl::ModuleOwnershipKind::ModuleUnreachable; + } + /// Whether this declaration is a top-level declaration (function, /// global variable, etc.) that is lexically inside an objc container /// definition. diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h --- a/clang/include/clang/Sema/Lookup.h +++ b/clang/include/clang/Sema/Lookup.h @@ -347,6 +347,13 @@ /// Determine whether the given declaration is visible to the /// program. static bool isVisible(Sema &SemaRef, NamedDecl *D) { + // [module.global.frag/note 2] A discarded declaration is neither reachable + // nor visible to name lookup outside the module unit, nor in template + // instantiations whose points of instantiation are outside the module unit, + // even when the instantiation context includes the module unit. + if (D->isFromASTFile() && D->isModuleUnreachable()) + return false; + // If this declaration is not hidden, it's visible. if (D->isUnconditionallyVisible()) return true; @@ -362,6 +369,10 @@ if (!D->isInIdentifierNamespace(IDNS)) return nullptr; + // see comment about [module.global.frag/note 2] above. + if (D->isFromASTFile() && D->isModuleUnreachable()) + return nullptr; + if (isVisible(getSema(), D) || isHiddenDeclarationVisible(D)) return D; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2263,7 +2263,37 @@ bool isUsableModule(const Module *M); + /// Given a Decl D (which is from the GMF) which has been made reachable by + /// use, mark any additional decls which this makes reachable. + void markReachableGMFDecls(Decl *D); + + void HandleGMFReachability(Decl *D) { + if (D->isModuleUnreachable() && isCurrentModulePurview()) { + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + markReachableGMFDecls(D); + } + } + public: + /// To implement C++20 GMF elision semantics, we initially mark decls in the + /// Global Module Fragment as "ModuleUnreachable". If the decl is then used + /// within the module purview, we reset that to visible. + void setDeclIsUsed(Decl *D) { + D->setIsUsed(); + HandleGMFReachability(D); + } + + /// Likewise when the decl is marked used and notifies mutation listeners. + void markDeclUsed(Decl *D, ASTContext &C) { + D->markUsed(C); + HandleGMFReachability(D); + } + + void setDeclReferenced(Decl *D, bool R = true) { + D->setReferenced(R); + HandleGMFReachability(D); + } + /// Get the module whose scope we are currently within. Module *getCurrentModule() const { return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -589,6 +589,7 @@ switch (D->getModuleOwnershipKind()) { case Decl::ModuleOwnershipKind::Unowned: case Decl::ModuleOwnershipKind::ModulePrivate: + case Decl::ModuleOwnershipKind::ModuleUnreachable: return false; case Decl::ModuleOwnershipKind::Visible: case Decl::ModuleOwnershipKind::VisibleWhenImported: diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -12,6 +12,7 @@ #include "clang/AST/TextNodeDumper.h" #include "clang/AST/APValue.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" @@ -1617,6 +1618,8 @@ dumpType(D->getUnderlyingType()); if (D->isModulePrivate()) OS << " __module_private__"; + if (D->isModuleUnreachable()) + OS << " ModuleUnreachable"; } void TextNodeDumper::VisitEnumDecl(const EnumDecl *D) { @@ -1629,6 +1632,8 @@ dumpName(D); if (D->isModulePrivate()) OS << " __module_private__"; + if (D->isModuleUnreachable()) + OS << " ModuleUnreachable"; if (D->isFixed()) dumpType(D->getIntegerType()); } @@ -1638,6 +1643,8 @@ dumpName(D); if (D->isModulePrivate()) OS << " __module_private__"; + if (D->isModuleUnreachable()) + OS << " ModuleUnreachable"; if (D->isCompleteDefinition()) OS << " definition"; } @@ -1668,6 +1675,8 @@ OS << " virtual"; if (D->isModulePrivate()) OS << " __module_private__"; + if (D->isModuleUnreachable()) + OS << " ModuleUnreachable"; if (D->isPure()) OS << " pure"; @@ -1743,6 +1752,8 @@ OS << " mutable"; if (D->isModulePrivate()) OS << " __module_private__"; + if (D->isModuleUnreachable()) + OS << " ModuleUnreachable"; } void TextNodeDumper::VisitVarDecl(const VarDecl *D) { @@ -1763,6 +1774,8 @@ } if (D->isModulePrivate()) OS << " __module_private__"; + if (D->isModuleUnreachable()) + OS << " ModuleUnreachable"; if (D->isNRVOVariable()) OS << " nrvo"; if (D->isInline()) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4121,7 +4121,7 @@ // Merge "used" flag. if (Old->getMostRecentDecl()->isUsed(false)) - New->setIsUsed(); + setDeclIsUsed(New); // Merge attributes from the parameters. These can mismatch with K&R // declarations. @@ -4537,7 +4537,7 @@ // Merge "used" flag. if (Old->getMostRecentDecl()->isUsed(false)) - New->setIsUsed(); + setDeclIsUsed(New); // Keep a chain of previous declarations. New->setPreviousDecl(Old); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2012,7 +2012,7 @@ LookupResult LR(S, target, Sema::LookupOrdinaryName); if (S.LookupQualifiedName(LR, S.getCurLexicalContext())) for (NamedDecl *ND : LR) - ND->markUsed(S.Context); + S.markDeclUsed(ND, S.Context); } D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str)); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -8797,7 +8797,7 @@ return; } FD->setBody(Body.get()); - FD->markUsed(Context); + markDeclUsed(FD,Context); } // The exception specification is needed because we are defining the @@ -13491,7 +13491,7 @@ ? Constructor->getEndLoc() : Constructor->getLocation(); Constructor->setBody(new (Context) CompoundStmt(Loc)); - Constructor->markUsed(Context); + markDeclUsed(Constructor,Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -13670,7 +13670,7 @@ } Constructor->setBody(new (Context) CompoundStmt(InitLoc)); - Constructor->markUsed(Context); + markDeclUsed(Constructor, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -13781,7 +13781,7 @@ ? Destructor->getEndLoc() : Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Loc)); - Destructor->markUsed(Context); + markDeclUsed(Destructor, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Destructor); @@ -14640,7 +14640,7 @@ assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } CopyAssignOperator->setBody(Body.getAs()); - CopyAssignOperator->markUsed(Context); + markDeclUsed(CopyAssignOperator, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyAssignOperator); @@ -15010,7 +15010,7 @@ assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } MoveAssignOperator->setBody(Body.getAs()); - MoveAssignOperator->markUsed(Context); + markDeclUsed(MoveAssignOperator, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveAssignOperator); @@ -15154,7 +15154,7 @@ Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs()); - CopyConstructor->markUsed(Context); + markDeclUsed(CopyConstructor, Context); } if (ASTMutationListener *L = getASTMutationListener()) { @@ -15280,7 +15280,7 @@ Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody(ActOnCompoundStmt( Loc, Loc, None, /*isStmtExpr=*/ false).getAs()); - MoveConstructor->markUsed(Context); + markDeclUsed(MoveConstructor, Context); } if (ASTMutationListener *L = getASTMutationListener()) { @@ -15331,7 +15331,7 @@ // Fill in the __invoke function with a dummy implementation. IR generation // will fill in the actual details. Update its type in case it contained // an 'auto'. - Invoker->markUsed(Context); + markDeclUsed(Invoker, Context); Invoker->setReferenced(); Invoker->setType(Conv->getReturnType()->getPointeeType()); Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); @@ -15343,7 +15343,7 @@ Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get(); Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(), Conv->getLocation())); - Conv->markUsed(Context); + markDeclUsed(Conv, Context); Conv->setReferenced(); if (ASTMutationListener *L = getASTMutationListener()) { @@ -15398,7 +15398,7 @@ Stmt *ReturnS = Return.get(); Conv->setBody(CompoundStmt::Create(Context, ReturnS, Conv->getLocation(), Conv->getLocation())); - Conv->markUsed(Context); + markDeclUsed(Conv, Context); // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -47,6 +47,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaFixItUtils.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" @@ -15719,7 +15720,7 @@ /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl) { - TheDecl->markUsed(Context); + markDeclUsed(TheDecl, Context); // Create the AST node. The address of a label always has type 'void*'. return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy)); @@ -17804,7 +17805,7 @@ bool MightBeOdrUse) { assert(Func && "No function?"); - Func->setReferenced(); + setDeclReferenced(Func); // Recursive functions aren't really used until they're used from some other // context. @@ -18037,7 +18038,7 @@ } } - Func->markUsed(Context); + markDeclUsed(Func, Context); } } @@ -18108,7 +18109,7 @@ } } - Var->markUsed(SemaRef.Context); + SemaRef.markDeclUsed(Var, SemaRef.Context); } void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture, @@ -19264,7 +19265,7 @@ assert((!E || isa(E) || isa(E) || isa(E)) && "Invalid Expr argument to DoMarkVarDeclReferenced"); - Var->setReferenced(); + SemaRef.setDeclReferenced(Var); if (Var->isInvalidDecl()) return; @@ -19540,7 +19541,7 @@ MarkFunctionReferenced(Loc, FD, MightBeOdrUse); return; } - D->setReferenced(); + setDeclReferenced(D); } namespace { diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4692,7 +4692,7 @@ FunctionDecl *Function = Best->Function; // This is the overload that will be used for this initialization step if we // use this initialization. Mark it as referenced. - Function->setReferenced(); + S.setDeclReferenced(Function); // Compute the returned type and value kind of the conversion. QualType cv3T3; @@ -5363,7 +5363,7 @@ } FunctionDecl *Function = Best->Function; - Function->setReferenced(); + S.setDeclReferenced(Function); bool HadMultipleCandidates = (CandidateSet.size() > 1); if (isa(Function)) { diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -874,7 +874,7 @@ NewVD->setReferenced(true); // FIXME: Pass in a VarDecl::InitializationStyle. NewVD->setInitStyle(static_cast(InitStyle)); - NewVD->markUsed(Context); + markDeclUsed(static_cast(NewVD), Context); NewVD->setInit(Init); if (NewVD->isParameterPack()) getCurLambda()->LocalPacks.push_back(NewVD); @@ -1975,7 +1975,7 @@ Lambda->lookup( Context.DeclarationNames.getCXXOperatorName(OO_Call)).front()); CallOperator->setReferenced(); - CallOperator->markUsed(Context); + markDeclUsed(CallOperator, Context); ExprResult Init = PerformCopyInitialization( InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType()), diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -83,14 +83,18 @@ return nullptr; } - // We start in the global module; all those declarations are implicitly - // module-private (though they do not have module linkage). Module *GlobalModule = PushGlobalModuleFragment(ModuleLoc, /*IsImplicit=*/false); // All declarations created from now on are owned by the global module. auto *TU = Context.getTranslationUnitDecl(); - TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + // For C++20 modules, we are expected to elide GMF decls that are not used + // in the purview of the named module. In order to do that, create GMF decls + // with a marker that is updated when a decl is used. + if (getLangOpts().CPlusPlusModules) + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModuleUnreachable); + else + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); TU->setLocalOwningModule(GlobalModule); // FIXME: Consider creating an explicit representation of this declaration. @@ -254,9 +258,8 @@ const_cast(getLangOpts()).CurrentModule = ModuleName; auto &Map = PP.getHeaderSearchInfo().getModuleMap(); - Module *Mod; - - ImportDecl *Import = nullptr; + Module *Mod; // The module we are creating. + Module *Interface = nullptr; // The interface fir an implementation. switch (MDK) { case ModuleDeclKind::Interface: case ModuleDeclKind::PartitionInterface: { @@ -291,22 +294,18 @@ // declaration. // First find the interface we need to import. - Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, - Module::AllVisible, - /*IsInclusionDirective=*/false); - if (!Mod) { + Interface = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, + Module::AllVisible, + /*IsInclusionDirective=*/false); + if (!Interface) { Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName; // Create an empty module interface unit for error recovery. Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, GlobalModuleFragment); - } else { - // Make the decl. - Import = ImportDecl::Create(Context, CurContext, ModuleLoc, Mod, - Path[0].second); - // now create the implementation module + } else + // We found the interface, now create the implementation module Mod = Map.createModuleForImplementationUnit(ModuleLoc, ModuleName, GlobalModuleFragment); - } } break; case ModuleDeclKind::PartitionImplementation: @@ -348,13 +347,23 @@ // We already potentially made an implicit import (in the case of a module // implementation unit importing its interface). Make this module visible // and return the import decl to be added to the current TU. - if (Import) - VisibleModules.setVisible(Import->getImportedModule(), ModuleLoc); - + if (Interface) { + // Make the import decl for the interface. + ImportDecl *Import = ImportDecl::Create(Context, CurContext, ModuleLoc, + Interface, Path[0].second); + VisibleModules.setVisible(Interface, ModuleLoc); + if (auto *InterfaceGMF = Interface->getGlobalModuleFragment()) + // The fact that the GMF is a seaprate sub-module is an implementation + // detail, if it's present then it should also be made visible here. + // Elision of unreachable decls is handled by marking them. + VisibleModules.setVisible(InterfaceGMF, ModuleLoc); + + // If we made an implicit import of the module interface, then return the + // imported module decl. + return ConvertDeclToDeclGroup(Import); + } // FIXME: Create a ModuleDecl. - // If we made an implicit import of the module interface, then return the - // imported module decl. - return Import ? ConvertDeclToDeclGroup(Import) : nullptr; + return nullptr; } Sema::DeclGroupPtrTy @@ -942,3 +951,56 @@ "left the wrong module scope, which is not global module fragment"); ModuleScopes.pop_back(); } + +// A helper to recurse through the statement tree finding DeclRefExprs and +// marking the referenced decls as reachable. +static void FindDeclRefExprs(clang::Stmt *S) { + if (DeclRefExpr *DR = dyn_cast(S)) { + auto *D = DR->getFoundDecl(); +// llvm::dbgs() << "DR:"; D->dump(); + if (D->isModuleUnreachable()) { + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + } + } else + for (auto *CH : S->children()) + FindDeclRefExprs(CH); +} + +// Given that we mark a decl 'orig' as reachable, this then analyzes that decl +// to determine if it, in turn, makes other decls reachable. We can simplify +// some checking here - we know we are in a module purview. +void Sema::markReachableGMFDecls(Decl *Orig) { + + if (isa(*Orig)) { + auto *FD = cast(Orig); + for (auto *P : FD->parameters()) { +// bool Changed = false; + if (P->isModuleUnreachable()) { + P->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); +// Changed = true; + } + if (auto *E = P->getDefaultArg()) { + if (isa(*E)) { + Decl *D = cast(E)->getCalleeDecl(); + if (D->isModuleUnreachable()) { + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); +// Changed = true; + } + } + } +// if (Changed) { +// llvm::dbgs() << "P:"; P->dump(); +// } + } + const FunctionDecl *BodyDecl; + if (auto *S = FD->getBody(BodyDecl)) { + FindDeclRefExprs(S); + } + } else if (isa(*Orig)) { + auto *VD = cast(Orig); + QualType T = VD->getTypeSourceInfo() + ? VD->getTypeSourceInfo()->getType() + : VD->getASTContext().getUnqualifiedObjCPointerType(VD->getType()); + T.dump(); + } +} diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -1455,7 +1455,7 @@ SourceLocation Loc, bool RefersToCapture = false) { D->setReferenced(); - D->markUsed(S.Context); + S.markDeclUsed(D, S.Context); return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), D, RefersToCapture, Loc, Ty, VK_LValue); @@ -3004,7 +3004,7 @@ // Mark variable as used. VD->setReferenced(); - VD->markUsed(Context); + markDeclUsed(static_cast(VD), Context); QualType QType = VD->getType(); if (QType->isDependentType() || QType->isInstantiationDependentType()) { diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2751,7 +2751,7 @@ if (RangeVarType->isDependentType()) { // The range is implicitly used as a placeholder when it is dependent. - RangeVar->markUsed(Context); + markDeclUsed(static_cast(RangeVar), Context); // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill // them in properly when we instantiate the loop. @@ -3266,7 +3266,7 @@ SourceLocation LabelLoc, LabelDecl *TheDecl) { setFunctionHasBranchIntoScope(); - TheDecl->markUsed(Context); + markDeclUsed(TheDecl, Context); return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc); } diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -956,7 +956,7 @@ if (Label->isMSAsmLabel()) { // If we have previously created this label implicitly, mark it as used. - Label->markUsed(Context); + markDeclUsed(Label, Context); } else { // Otherwise, insert it, but only resolve it if we have seen the label itself. std::string InternalName; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1004,7 +1004,7 @@ SemaRef.inferGslPointerAttribute(Typedef); Typedef->setAccess(D->getAccess()); - Typedef->setReferenced(D->isReferenced()); + SemaRef.setDeclReferenced(Typedef, D->isReferenced()); return Typedef; } @@ -1069,7 +1069,7 @@ Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) { auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier()); - NewBD->setReferenced(D->isReferenced()); + SemaRef.setDeclReferenced(NewBD, D->isReferenced()); SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD); return NewBD; } @@ -5210,8 +5210,8 @@ if (!OldVar->isStaticDataMember()) { if (OldVar->isUsed(false)) - NewVar->setIsUsed(); - NewVar->setReferenced(OldVar->isReferenced()); + setDeclIsUsed(NewVar); + setDeclReferenced(static_cast(NewVar), OldVar->isReferenced()); } InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -606,14 +606,16 @@ D->setAccess((AccessSpecifier)Record.readInt()); D->FromASTFile = true; bool ModulePrivate = Record.readInt(); + bool ModuleUnreachable = Record.readInt(); // Determine whether this declaration is part of a (sub)module. If so, it // may not yet be visible. if (unsigned SubmoduleID = readSubmoduleID()) { // Store the owning submodule ID in the declaration. D->setModuleOwnershipKind( - ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate - : Decl::ModuleOwnershipKind::VisibleWhenImported); + ModuleUnreachable ? Decl::ModuleOwnershipKind::ModuleUnreachable + : ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate + : Decl::ModuleOwnershipKind::VisibleWhenImported); D->setOwningModuleID(SubmoduleID); if (ModulePrivate) { @@ -629,6 +631,8 @@ else Reader.HiddenNamesMap[Owner].push_back(D); } + } else if (ModuleUnreachable) { + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModuleUnreachable); } else if (ModulePrivate) { D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -312,6 +312,7 @@ Record.push_back(D->isTopLevelDeclInObjCContainer()); Record.push_back(D->getAccess()); Record.push_back(D->isModulePrivate()); + Record.push_back(D->isModuleUnreachable()); Record.push_back(Writer.getSubmoduleID(D->getOwningModule())); // If this declaration injected a name into a context different from its @@ -394,6 +395,7 @@ !D->isInvalidDecl() && !D->isTopLevelDeclInObjCContainer() && !D->isModulePrivate() && + !D->isModuleUnreachable() && !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclTypedefAbbrev(); @@ -464,6 +466,7 @@ !D->isTopLevelDeclInObjCContainer() && D->getAccess() == AS_none && !D->isModulePrivate() && + !D->isModuleUnreachable() && !CXXRecordDecl::classofKind(D->getKind()) && !D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() && @@ -501,6 +504,7 @@ !D->isTopLevelDeclInObjCContainer() && D->getAccess() == AS_none && !D->isModulePrivate() && + !D->isModuleUnreachable() && !CXXRecordDecl::classofKind(D->getKind()) && !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier) @@ -803,6 +807,7 @@ !D->isInvalidDecl() && !D->isReferenced() && !D->isModulePrivate() && + !D->isModuleUnreachable() && !D->getBitWidth() && !D->hasExtInfo() && D->getDeclName()) @@ -938,6 +943,7 @@ !D->isReferenced() && !D->isTopLevelDeclInObjCContainer() && !D->isModulePrivate() && + !D->isModuleUnreachable() && !D->getBitWidth() && !D->hasInClassInitializer() && !D->hasCapturedVLAType() && @@ -1069,6 +1075,7 @@ !D->isTopLevelDeclInObjCContainer() && D->getAccess() == AS_none && !D->isModulePrivate() && + !D->isModuleUnreachable() && !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier && !D->hasExtInfo() && @@ -1117,6 +1124,7 @@ !D->isReferenced() && D->getAccess() == AS_none && !D->isModulePrivate() && + !D->isModuleUnreachable() && D->getStorageClass() == 0 && D->getInitStyle() == VarDecl::CInit && // Can params have anything else? D->getFunctionScopeDepth() == 0 && @@ -1929,6 +1937,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(0)); // ModuleUnreachable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -1962,6 +1971,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(0)); // ModuleUnreachable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2000,6 +2010,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(0)); // ModuleUnreachable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2050,6 +2061,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(0)); // ModuleUnreachable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2112,6 +2124,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(0)); // ModuleUnreachable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2160,6 +2173,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(0)); // ModuleUnreachable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2189,6 +2203,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(0)); // ModuleUnreachable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier @@ -2241,6 +2256,7 @@ Abv->Add(BitCodeAbbrevOp(0)); // InObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Access Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModulePrivate + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModuleUnreachable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind diff --git a/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp b/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp --- a/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp +++ b/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp @@ -29,8 +29,7 @@ #endif void test_early() { - in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}} - // expected-note@*{{not visible}} + in_header = 1; // expected-error {{use of undeclared identifier 'in_header'}} global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}} // expected-note@p2.cpp:16 {{not visible}} @@ -54,8 +53,7 @@ #endif void test_late() { - in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}} - // expected-note@*{{not visible}} + in_header = 1; // expected-error {{use of undeclared identifier 'in_header'}} global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}} // expected-note@p2.cpp:16 {{not visible}}