diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index de6b8c668de3..b62760f6ae3b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -383,6 +383,7 @@ class ASTContext : public RefCountedBase { ImportDecl *LastLocalImport; TranslationUnitDecl *TUDecl; + mutable ExternCContextDecl *ExternCContext; /// \brief The associated SourceManager object.a SourceManager &SourceMgr; @@ -782,6 +783,7 @@ class ASTContext : public RefCountedBase { TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; } + ExternCContextDecl *getExternCContextDecl() const; // Builtin Types. CanQualType VoidTy; diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index c0526e1cfd45..cc967e652fd0 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -1284,6 +1284,8 @@ DEF_TRAVERSE_DECL( // D->getAnonymousNamespace(). }) +DEF_TRAVERSE_DECL(ExternCContextDecl, {}) + DEF_TRAVERSE_DECL(NamespaceAliasDecl, { // We shouldn't traverse an aliased namespace, since it will be // defined (and, therefore, traversed) somewhere else. diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 63ef79616f7b..5380339f509e 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -104,6 +104,43 @@ class TranslationUnitDecl : public Decl, public DeclContext { } }; +/// \brief Declaration context for names declared as extern "C" in C++. This +/// is neither the semantic nor lexical context for such declarations, but is +/// used to check for conflicts with other extern "C" declarations. Example: +/// +/// \code +/// namespace N { extern "C" void f(); } // #1 +/// void N::f() {} // #2 +/// namespace M { extern "C" void f(); } // #3 +/// \endcode +/// +/// The semantic context of #1 is namespace N and its lexical context is the +/// LinkageSpecDecl; the semantic context of #2 is namespace N and its lexical +/// context is the TU. However, both declarations are also visible in the +/// extern "C" context. +/// +/// The declaration at #3 finds it is a redeclaration of \c N::f through +/// lookup in the extern "C" context. +class ExternCContextDecl : public Decl, public DeclContext { + virtual void anchor(); + + explicit ExternCContextDecl(TranslationUnitDecl *TU) + : Decl(ExternCContext, TU, SourceLocation()), + DeclContext(ExternCContext) {} +public: + static ExternCContextDecl *Create(const ASTContext &C, + TranslationUnitDecl *TU); + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ExternCContext; } + static DeclContext *castToDeclContext(const ExternCContextDecl *D) { + return static_cast(const_cast(D)); + } + static ExternCContextDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast(const_cast(DC)); + } +}; + /// NamedDecl - This represents a decl with a name. Many decls have names such /// as ObjCMethodDecl, but not \@class, etc. class NamedDecl : public Decl { diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index ff8e74b650d2..f91008fde267 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1356,6 +1356,8 @@ DEF_TRAVERSE_DECL( // D->getAnonymousNamespace(). }) +DEF_TRAVERSE_DECL(ExternCContextDecl, {}) + DEF_TRAVERSE_DECL(NamespaceAliasDecl, { // We shouldn't traverse an aliased namespace, since it will be // defined (and, therefore, traversed) somewhere else. diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index 18bca5741962..dece8f9ed2ec 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -11,6 +11,7 @@ class DDecl : Decl { class DeclContext { } def TranslationUnit : Decl, DeclContext; +def ExternCContext : Decl, DeclContext; def Named : Decl<1>; def Namespace : DDecl, DeclContext; def UsingDirective : DDecl; diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index 168835b17874..1083784fb7f0 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -137,16 +137,6 @@ class ExternalSemaSource : public ExternalASTSource { virtual void ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector &Decls) {}; - /// \brief Read the set of locally-scoped external declarations known to the - /// external Sema source. - /// - /// The external source should append its own locally-scoped external - /// declarations to the given vector of declarations. Note that this routine - /// may be invoked multiple times; the external source should take care not - /// to introduce the same declarations repeatedly. - virtual void ReadLocallyScopedExternCDecls( - SmallVectorImpl &Decls) {} - /// \brief Read the set of referenced selectors known to the /// external Sema source. /// diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h index 50e2553f2bf0..d90eefd302d9 100644 --- a/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/include/clang/Sema/MultiplexExternalSemaSource.h @@ -283,16 +283,6 @@ class MultiplexExternalSemaSource : public ExternalSemaSource { void ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector &Decls) override; - /// \brief Read the set of locally-scoped extern "C" declarations known to the - /// external Sema source. - /// - /// The external source should append its own locally-scoped external - /// declarations to the given vector of declarations. Note that this routine - /// may be invoked multiple times; the external source should take care not - /// to introduce the same declarations repeatedly. - void ReadLocallyScopedExternCDecls( - SmallVectorImpl &Decls) override; - /// \brief Read the set of referenced selectors known to the /// external Sema source. /// diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 8e03911af340..460111f522df 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -410,33 +410,6 @@ class Sema { /// we are currently parsing the initializer. llvm::SmallPtrSet ParsingInitForAutoVars; - /// \brief A mapping from external names to the most recent - /// locally-scoped extern "C" declaration with that name. - /// - /// This map contains external declarations introduced in local - /// scopes, e.g., - /// - /// \code - /// extern "C" void f() { - /// void foo(int, int); - /// } - /// \endcode - /// - /// Here, the name "foo" will be associated with the declaration of - /// "foo" within f. This name is not visible outside of - /// "f". However, we still find it in two cases: - /// - /// - If we are declaring another global or extern "C" entity with - /// the name "foo", we can find "foo" as a previous declaration, - /// so that the types of this external declaration can be checked - /// for compatibility. - /// - /// - If we would implicitly declare "foo" (e.g., due to a call to - /// "foo" in C when no prototype or definition is visible), then - /// we find this declaration of "foo" and complain that it is - /// not visible. - llvm::DenseMap LocallyScopedExternCDecls; - /// \brief Look for a locally scoped extern "C" declaration by the given name. NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 71c55c60958c..1e26927fbffb 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -385,9 +385,7 @@ namespace clang { /// \brief Record code for the array of tentative definitions. TENTATIVE_DEFINITIONS = 9, - /// \brief Record code for the array of locally-scoped extern "C" - /// declarations. - LOCALLY_SCOPED_EXTERN_C_DECLS = 10, + // ID 10 used to be for a list of extern "C" declarations. /// \brief Record code for the table of offsets into the /// Objective-C method pool. @@ -925,14 +923,17 @@ namespace clang { PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8, /// \brief The internal '__builtin_va_list' typedef. - PREDEF_DECL_BUILTIN_VA_LIST_ID = 9 + PREDEF_DECL_BUILTIN_VA_LIST_ID = 9, + + /// \brief The extern "C" context. + PREDEF_DECL_EXTERN_C_CONTEXT_ID = 10, }; /// \brief The number of declaration IDs that are predefined. /// /// For more information about predefined declarations, see the /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. - const unsigned int NUM_PREDEF_DECL_IDS = 10; + const unsigned int NUM_PREDEF_DECL_IDS = 11; /// \brief Record codes for each kind of declaration. /// diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 8ccf94c0e2ea..1037160ab252 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -770,12 +770,6 @@ class ASTReader /// \brief Fields containing data that is used for semantic analysis //@{ - /// \brief The IDs of all locally scoped extern "C" decls in the chain. - /// - /// Sema tracks these to validate that the types are consistent across all - /// local extern "C" declarations. - SmallVector LocallyScopedExternCDecls; - /// \brief The IDs of all potentially unused typedef names in the chain. /// /// Sema tracks these to emit warnings. @@ -1795,9 +1789,6 @@ class ASTReader void ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector &Decls) override; - void ReadLocallyScopedExternCDecls( - SmallVectorImpl &Decls) override; - void ReadReferencedSelectors( SmallVectorImpl > &Sels) override; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 9cfc97b926d3..20d2aa68187a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -738,7 +738,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr), BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr), - FirstLocalImport(), LastLocalImport(), SourceMgr(SM), LangOpts(LOpts), + FirstLocalImport(), LastLocalImport(), ExternCContext(nullptr), + SourceMgr(SM), LangOpts(LOpts), SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts), Idents(idents), Selectors(sels), BuiltinInfo(builtins), @@ -865,6 +866,13 @@ void ASTContext::PrintStats() const { BumpAlloc.PrintStats(); } +ExternCContextDecl *ASTContext::getExternCContextDecl() const { + if (!ExternCContext) + ExternCContext = ExternCContextDecl::Create(*this, getTranslationUnitDecl()); + + return ExternCContext; +} + RecordDecl *ASTContext::buildImplicitRecord(StringRef Name, RecordDecl::TagKind TK) const { SourceLocation Loc; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index c7aac37524ee..bd0e503d386b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3799,6 +3799,13 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { return new (C, (DeclContext *)nullptr) TranslationUnitDecl(C); } +void ExternCContextDecl::anchor() { } + +ExternCContextDecl *ExternCContextDecl::Create(const ASTContext &C, + TranslationUnitDecl *DC) { + return new (C, DC) ExternCContextDecl(DC); +} + void LabelDecl::anchor() { } LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 0390d81263a2..a8e151cc937d 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -597,6 +597,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Block: case Captured: case TranslationUnit: + case ExternCContext: case UsingDirective: case ClassTemplateSpecialization: @@ -907,6 +908,7 @@ bool DeclContext::Encloses(const DeclContext *DC) const { DeclContext *DeclContext::getPrimaryContext() { switch (DeclKind) { case Decl::TranslationUnit: + case Decl::ExternCContext: case Decl::LinkageSpec: case Decl::Block: case Decl::Captured: diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index fb72a9a54339..f79d1373d41a 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -34,6 +34,7 @@ using namespace CodeGen; void CodeGenFunction::EmitDecl(const Decl &D) { switch (D.getKind()) { case Decl::TranslationUnit: + case Decl::ExternCContext: case Decl::Namespace: case Decl::UnresolvedUsingTypename: case Decl::ClassTemplateSpecialization: diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp index a03157776752..194c3693c1d5 100644 --- a/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/lib/Sema/MultiplexExternalSemaSource.cpp @@ -242,12 +242,6 @@ void MultiplexExternalSemaSource::ReadUnusedLocalTypedefNameCandidates( Sources[i]->ReadUnusedLocalTypedefNameCandidates(Decls); } -void MultiplexExternalSemaSource::ReadLocallyScopedExternCDecls( - SmallVectorImpl &Decls) { - for(size_t i = 0; i < Sources.size(); ++i) - Sources[i]->ReadLocallyScopedExternCDecls(Decls); -} - void MultiplexExternalSemaSource::ReadReferencedSelectors( SmallVectorImpl > &Sels) { for(size_t i = 0; i < Sources.size(); ++i) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 462854417e10..778b617628e1 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4864,27 +4864,13 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) { return; // Note that we have a locally-scoped external with this name. - // FIXME: There can be multiple such declarations if they are functions marked - // __attribute__((overloadable)) declared in function scope in C. - LocallyScopedExternCDecls[ND->getDeclName()] = ND; + Context.getExternCContextDecl()->makeDeclVisibleInContext(ND); } NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) { - if (ExternalSource) { - // Load locally-scoped external decls from the external source. - // FIXME: This is inefficient. Maybe add a DeclContext for extern "C" decls? - SmallVector Decls; - ExternalSource->ReadLocallyScopedExternCDecls(Decls); - for (unsigned I = 0, N = Decls.size(); I != N; ++I) { - llvm::DenseMap::iterator Pos - = LocallyScopedExternCDecls.find(Decls[I]->getDeclName()); - if (Pos == LocallyScopedExternCDecls.end()) - LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I]; - } - } - - NamedDecl *D = LocallyScopedExternCDecls.lookup(Name); - return D ? D->getMostRecentDecl() : nullptr; + // FIXME: We can have multiple results via __attribute__((overloadable)). + auto Result = Context.getExternCContextDecl()->lookup(Name); + return Result.empty() ? nullptr : *Result.begin(); } /// \brief Diagnose function specifiers on a declaration of an identifier that diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1df0701ee9f4..6936539f1caa 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -288,6 +288,11 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { llvm_unreachable("Translation units cannot be instantiated"); } +Decl * +TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) { + llvm_unreachable("extern \"C\" context cannot be instantiated"); +} + Decl * TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) { LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(), diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 04425acb4c5d..85c574c2021a 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -94,6 +94,7 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) { switch (DC->getDeclKind()) { // These entities may have multiple definitions. case Decl::TranslationUnit: + case Decl::ExternCContext: case Decl::Namespace: case Decl::LinkageSpec: return nullptr; @@ -149,7 +150,11 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) { bool serialization::isRedeclarableDeclKind(unsigned Kind) { switch (static_cast(Kind)) { - case Decl::TranslationUnit: // Special case of a "merged" declaration. + case Decl::TranslationUnit: + case Decl::ExternCContext: + // Special case of a "merged" declaration. + return true; + case Decl::Namespace: case Decl::NamespaceAlias: case Decl::Typedef: diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index d3721bbe3423..7e3a779b076c 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2892,11 +2892,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } break; - case LOCALLY_SCOPED_EXTERN_C_DECLS: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - LocallyScopedExternCDecls.push_back(getGlobalDeclID(F, Record[I])); - break; - case SELECTOR_OFFSETS: { F.SelectorOffsets = (const uint32_t *)Blob.data(); F.LocalNumSelectors = Record[0]; @@ -6284,6 +6279,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) { case PREDEF_DECL_BUILTIN_VA_LIST_ID: return Context.getBuiltinVaListDecl(); + + case PREDEF_DECL_EXTERN_C_CONTEXT_ID: + return Context.getExternCContextDecl(); } llvm_unreachable("PredefinedDeclIDs unknown enum value"); } @@ -7326,17 +7324,6 @@ void ASTReader::ReadUnusedLocalTypedefNameCandidates( UnusedLocalTypedefNameCandidates.clear(); } -void -ASTReader::ReadLocallyScopedExternCDecls(SmallVectorImpl &Decls) { - for (unsigned I = 0, N = LocallyScopedExternCDecls.size(); I != N; ++I) { - NamedDecl *D - = dyn_cast_or_null(GetDecl(LocallyScopedExternCDecls[I])); - if (D) - Decls.push_back(D); - } - LocallyScopedExternCDecls.clear(); -} - void ASTReader::ReadReferencedSelectors( SmallVectorImpl > &Sels) { if (ReferencedSelectorsData.empty()) diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 19c7a966253c..f92848ad21f8 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -892,7 +892,6 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); RECORD(UNUSED_FILESCOPED_DECLS); - RECORD(LOCALLY_SCOPED_EXTERN_C_DECLS); RECORD(SELECTOR_OFFSETS); RECORD(METHOD_POOL); RECORD(PP_COUNTER_VALUE); @@ -4231,6 +4230,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID; if (Context.BuiltinVaListDecl) DeclIDs[Context.getBuiltinVaListDecl()] = PREDEF_DECL_BUILTIN_VA_LIST_ID; + if (Context.ExternCContext) + DeclIDs[Context.ExternCContext] = PREDEF_DECL_EXTERN_C_CONTEXT_ID; if (!Chain) { // Make sure that we emit IdentifierInfos (and any attached @@ -4289,20 +4290,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, } } - // Build a record containing all of the locally-scoped extern "C" - // declarations in this header file. Generally, this record will be - // empty. - RecordData LocallyScopedExternCDecls; - // FIXME: This is filling in the AST file in densemap order which is - // nondeterminstic! - for (llvm::DenseMap::iterator - TD = SemaRef.LocallyScopedExternCDecls.begin(), - TDEnd = SemaRef.LocallyScopedExternCDecls.end(); - TD != TDEnd; ++TD) { - if (!TD->second->isFromASTFile()) - AddDeclRef(TD->second, LocallyScopedExternCDecls); - } - // Build a record containing all of the ext_vector declarations. RecordData ExtVectorDecls; AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls); @@ -4405,6 +4392,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv); WriteDeclContextVisibleUpdate(TU); + + // If we have any extern "C" names, write out a visible update for them. + if (Context.ExternCContext) + WriteDeclContextVisibleUpdate(Context.ExternCContext); // If the translation unit has an anonymous namespace, and we don't already // have an update block for it, write it as an update block. @@ -4589,11 +4580,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS, WeakUndeclaredIdentifiers); - // Write the record containing locally-scoped extern "C" definitions. - if (!LocallyScopedExternCDecls.empty()) - Stream.EmitRecord(LOCALLY_SCOPED_EXTERN_C_DECLS, - LocallyScopedExternCDecls); - // Write the record containing ext_vector type names. if (!ExtVectorDecls.empty()) Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 9729531c0f85..d9f3f42e3245 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -4951,6 +4951,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { // nonetheless harmless. case Decl::Empty: case Decl::TranslationUnit: + case Decl::ExternCContext: break; // Declaration kinds for which the definition is not resolvable.