summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-17 20:22:49 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-17 20:22:49 +0000
commit1ce08792766261dcaa25d8215f9d1c2f70d7b7e9 (patch)
tree4022bfb5dc1b2e6f7fc5c337048e370656cc2260
parent2410013d9382b8129702fa3a3bf19a370ae7afc3 (diff)
Notes
-rw-r--r--include/clang/AST/Decl.h10
-rw-r--r--include/clang/AST/DeclBase.h14
-rw-r--r--include/clang/Basic/LangOptions.h5
-rw-r--r--include/clang/Basic/SourceManager.h2
-rw-r--r--include/clang/Frontend/ASTUnit.h6
-rw-r--r--include/clang/Sema/Sema.h4
-rw-r--r--lib/AST/ASTDumper.cpp6
-rw-r--r--lib/AST/Decl.cpp4
-rw-r--r--lib/AST/DeclBase.cpp10
-rw-r--r--lib/AST/ODRHash.cpp80
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp2
-rw-r--r--lib/Driver/ToolChains/MSVC.cpp11
-rw-r--r--lib/Frontend/ASTUnit.cpp23
-rw-r--r--lib/Headers/xmmintrin.h25
-rw-r--r--lib/Lex/Lexer.cpp4
-rw-r--r--lib/Sema/Sema.cpp9
-rw-r--r--lib/Sema/SemaDecl.cpp15
-rw-r--r--lib/Sema/SemaLookup.cpp57
-rw-r--r--lib/Serialization/ASTReader.cpp31
-rw-r--r--test/CodeGenCXX/debug-info-namespace.cpp6
-rw-r--r--test/Modules/Inputs/module.map4
-rw-r--r--test/Modules/Inputs/objcAtKeywordMissingEnd.h3
-rw-r--r--test/Modules/Inputs/submodule-visibility/b.h6
-rw-r--r--test/Modules/Inputs/submodule-visibility/other.h9
-rw-r--r--test/Modules/objc-at-keyword.m7
-rw-r--r--test/Modules/odr_hash.cpp231
-rw-r--r--test/Modules/submodule-visibility.cpp9
27 files changed, 429 insertions, 164 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index facef8e55f7a..4f8042ac9291 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -301,16 +301,6 @@ public:
using Decl::isModulePrivate;
using Decl::setModulePrivate;
- /// \brief Determine whether this declaration is hidden from name lookup.
- bool isHidden() const { return Hidden; }
-
- /// \brief Set whether this declaration is hidden from name lookup.
- void setHidden(bool Hide) {
- assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) &&
- "declaration with no owning module can't be hidden");
- Hidden = Hide;
- }
-
/// \brief Determine whether this declaration is a C++ class member.
bool isCXXClassMember() const {
const DeclContext *DC = getDeclContext();
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 15ac11a5a777..08879b36cce5 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -706,6 +706,20 @@ public:
reinterpret_cast<Module **>(this)[-1] = M;
}
+ Module *getOwningModule() const {
+ return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule();
+ }
+
+ /// \brief Determine whether this declaration is hidden from name lookup.
+ bool isHidden() const { return Hidden; }
+
+ /// \brief Set whether this declaration is hidden from name lookup.
+ void setHidden(bool Hide) {
+ assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) &&
+ "declaration with no owning module can't be hidden");
+ Hidden = Hide;
+ }
+
unsigned getIdentifierNamespace() const {
return IdentifierNamespace;
}
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 20a0e5845602..ceaedf58574f 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -166,6 +166,11 @@ public:
return getCompilingModule() != CMK_None;
}
+ /// Do we need to track the owning module for a local declaration?
+ bool trackLocalOwningModule() const {
+ return ModulesLocalVisibility;
+ }
+
bool isSignedOverflowDefined() const {
return getSignedOverflowBehavior() == SOB_Defined;
}
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index c8fe2ab90c29..6960ea690b91 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -865,7 +865,7 @@ public:
const FileEntry *NewFile);
/// \brief Returns true if the file contents have been overridden.
- bool isFileOverridden(const FileEntry *File) {
+ bool isFileOverridden(const FileEntry *File) const {
if (OverriddenFilesInfo) {
if (OverriddenFilesInfo->OverriddenFilesWithBuffer.count(File))
return true;
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 2a8df1b7b9ae..46395cf6e861 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -419,7 +419,6 @@ private:
explicit ASTUnit(bool MainFileIsAST);
- void CleanTemporaryFiles();
bool Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer);
@@ -530,11 +529,6 @@ public:
ASTMutationListener *getASTMutationListener();
ASTDeserializationListener *getDeserializationListener();
- /// \brief Add a temporary file that the ASTUnit depends on.
- ///
- /// This file will be erased when the ASTUnit is destroyed.
- void addTemporaryFile(StringRef TempFile);
-
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; }
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index e910be14f969..ba2da92c5be1 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1467,11 +1467,9 @@ private:
VisibleModuleSet VisibleModules;
- Module *CachedFakeTopLevelModule;
-
public:
/// \brief Get the module owning an entity.
- Module *getOwningModule(Decl *Entity);
+ Module *getOwningModule(Decl *Entity) { return Entity->getOwningModule(); }
/// \brief Make a merged definition of an existing hidden definition \p ND
/// visible at the specified location.
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index ef491ab06f8c..d89be0d9e6fa 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -1038,10 +1038,10 @@ void ASTDumper::dumpDecl(const Decl *D) {
dumpSourceRange(D->getSourceRange());
OS << ' ';
dumpLocation(D->getLocation());
- if (Module *M = D->getImportedOwningModule())
+ if (D->isFromASTFile())
+ OS << " imported";
+ if (Module *M = D->getOwningModule())
OS << " in " << M->getFullModuleName();
- else if (Module *M = D->getLocalOwningModule())
- OS << " in (local) " << M->getFullModuleName();
if (auto *ND = dyn_cast<NamedDecl>(D))
for (Module *M : D->getASTContext().getModulesWithMergedDefinition(
const_cast<NamedDecl *>(ND)))
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 0f2558e24ba5..a1342f477b68 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -47,9 +47,7 @@ bool Decl::isOutOfLine() const {
TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx)
: Decl(TranslationUnit, nullptr, SourceLocation()),
- DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {
- Hidden = Ctx.getLangOpts().ModulesLocalVisibility;
-}
+ DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {}
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 5c2c9cbd0180..f6f81692611d 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -75,7 +75,7 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
assert(!Parent || &Parent->getParentASTContext() == &Ctx);
// With local visibility enabled, we track the owning module even for local
// declarations.
- if (Ctx.getLangOpts().ModulesLocalVisibility) {
+ if (Ctx.getLangOpts().trackLocalOwningModule()) {
// Ensure required alignment of the resulting object by adding extra
// padding at the start if required.
size_t ExtraAlign =
@@ -83,7 +83,9 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
char *Buffer = reinterpret_cast<char *>(
::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx));
Buffer += ExtraAlign;
- return new (Buffer) Module*(nullptr) + 1;
+ auto *ParentModule =
+ Parent ? cast<Decl>(Parent)->getOwningModule() : nullptr;
+ return new (Buffer) Module*(ParentModule) + 1;
}
return ::operator new(Size + Extra, Ctx);
}
@@ -94,7 +96,7 @@ Module *Decl::getOwningModuleSlow() const {
}
bool Decl::hasLocalOwningModuleStorage() const {
- return getASTContext().getLangOpts().ModulesLocalVisibility;
+ return getASTContext().getLangOpts().trackLocalOwningModule();
}
const char *Decl::getDeclKindName() const {
@@ -273,6 +275,8 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
getMultipleDC()->LexicalDC = DC;
}
Hidden = cast<Decl>(DC)->Hidden;
+ if (Hidden && !isFromASTFile() && hasLocalOwningModuleStorage())
+ setLocalOwningModule(cast<Decl>(DC)->getOwningModule());
}
void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp
index f4d314a6dd0d..24371db64d07 100644
--- a/lib/AST/ODRHash.cpp
+++ b/lib/AST/ODRHash.cpp
@@ -81,7 +81,35 @@ void ODRHash::AddDeclarationName(DeclarationName Name) {
}
}
-void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {}
+void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
+ assert(NNS && "Expecting non-null pointer.");
+ const auto *Prefix = NNS->getPrefix();
+ AddBoolean(Prefix);
+ if (Prefix) {
+ AddNestedNameSpecifier(Prefix);
+ }
+ auto Kind = NNS->getKind();
+ ID.AddInteger(Kind);
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ AddIdentifierInfo(NNS->getAsIdentifier());
+ break;
+ case NestedNameSpecifier::Namespace:
+ AddDecl(NNS->getAsNamespace());
+ break;
+ case NestedNameSpecifier::NamespaceAlias:
+ AddDecl(NNS->getAsNamespaceAlias());
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ AddType(NNS->getAsType());
+ break;
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
+ break;
+ }
+}
+
void ODRHash::AddTemplateName(TemplateName Name) {}
void ODRHash::AddTemplateArgument(TemplateArgument TA) {}
void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {}
@@ -335,6 +363,20 @@ public:
Hash.AddQualType(T);
}
+ void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
+ Hash.AddBoolean(NNS);
+ if (NNS) {
+ Hash.AddNestedNameSpecifier(NNS);
+ }
+ }
+
+ void AddIdentifierInfo(const IdentifierInfo *II) {
+ Hash.AddBoolean(II);
+ if (II) {
+ Hash.AddIdentifierInfo(II);
+ }
+ }
+
void VisitQualifiers(Qualifiers Quals) {
ID.AddInteger(Quals.getAsOpaqueValue());
}
@@ -414,6 +456,42 @@ public:
AddQualType(T->getDecl()->getUnderlyingType().getCanonicalType());
VisitType(T);
}
+
+ void VisitTagType(const TagType *T) {
+ AddDecl(T->getDecl());
+ VisitType(T);
+ }
+
+ void VisitRecordType(const RecordType *T) { VisitTagType(T); }
+ void VisitEnumType(const EnumType *T) { VisitTagType(T); }
+
+ void VisitTypeWithKeyword(const TypeWithKeyword *T) {
+ ID.AddInteger(T->getKeyword());
+ VisitType(T);
+ };
+
+ void VisitDependentNameType(const DependentNameType *T) {
+ AddNestedNameSpecifier(T->getQualifier());
+ AddIdentifierInfo(T->getIdentifier());
+ VisitTypeWithKeyword(T);
+ }
+
+ void VisitDependentTemplateSpecializationType(
+ const DependentTemplateSpecializationType *T) {
+ AddIdentifierInfo(T->getIdentifier());
+ AddNestedNameSpecifier(T->getQualifier());
+ ID.AddInteger(T->getNumArgs());
+ for (const auto &TA : T->template_arguments()) {
+ Hash.AddTemplateArgument(TA);
+ }
+ VisitTypeWithKeyword(T);
+ }
+
+ void VisitElaboratedType(const ElaboratedType *T) {
+ AddNestedNameSpecifier(T->getQualifier());
+ AddQualType(T->getNamedType());
+ VisitTypeWithKeyword(T);
+ }
};
void ODRHash::AddType(const Type *T) {
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 9d77c61bd52c..bf178dd7fd80 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -2860,7 +2860,7 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
if (DebugKind >= codegenoptions::LimitedDebugInfo) {
if (const NamespaceDecl *NSDecl =
- dyn_cast_or_null<NamespaceDecl>(FD->getLexicalDeclContext()))
+ dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNamespace(NSDecl);
else if (const RecordDecl *RDecl =
dyn_cast_or_null<RecordDecl>(FD->getDeclContext())) {
diff --git a/lib/Driver/ToolChains/MSVC.cpp b/lib/Driver/ToolChains/MSVC.cpp
index a09304814ca6..6f5f54165b3b 100644
--- a/lib/Driver/ToolChains/MSVC.cpp
+++ b/lib/Driver/ToolChains/MSVC.cpp
@@ -125,8 +125,15 @@ static bool findVCToolChainViaEnvironment(std::string &Path,
continue;
// whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
- if (llvm::sys::path::filename(PathEntry) == "bin") {
- llvm::StringRef ParentPath = llvm::sys::path::parent_path(PathEntry);
+ llvm::StringRef TestPath = PathEntry;
+ bool IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin");
+ if (!IsBin) {
+ // Strip any architecture subdir like "amd64".
+ TestPath = llvm::sys::path::parent_path(TestPath);
+ IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin");
+ }
+ if (IsBin) {
+ llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath);
if (llvm::sys::path::filename(ParentPath) == "VC") {
Path = ParentPath;
IsVS2017OrNewer = false;
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 32ee9d3e9961..6ee211c2de67 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -84,13 +84,6 @@ namespace {
/// \brief The file in which the precompiled preamble is stored.
std::string PreambleFile;
- /// \brief Temporary files that should be removed when the ASTUnit is
- /// destroyed.
- SmallVector<std::string, 4> TemporaryFiles;
-
- /// \brief Erase temporary files.
- void CleanTemporaryFiles();
-
/// \brief Erase the preamble file.
void CleanPreambleFile();
@@ -163,12 +156,6 @@ static const std::string &getPreambleFile(const ASTUnit *AU) {
return getOnDiskData(AU).PreambleFile;
}
-void OnDiskData::CleanTemporaryFiles() {
- for (StringRef File : TemporaryFiles)
- llvm::sys::fs::remove(File);
- TemporaryFiles.clear();
-}
-
void OnDiskData::CleanPreambleFile() {
if (!PreambleFile.empty()) {
llvm::sys::fs::remove(PreambleFile);
@@ -177,7 +164,6 @@ void OnDiskData::CleanPreambleFile() {
}
void OnDiskData::Cleanup() {
- CleanTemporaryFiles();
CleanPreambleFile();
}
@@ -194,14 +180,6 @@ void ASTUnit::clearFileLevelDecls() {
llvm::DeleteContainerSeconds(FileDecls);
}
-void ASTUnit::CleanTemporaryFiles() {
- getOnDiskData(this).CleanTemporaryFiles();
-}
-
-void ASTUnit::addTemporaryFile(StringRef TempFile) {
- getOnDiskData(this).TemporaryFiles.push_back(TempFile);
-}
-
/// \brief After failing to build a precompiled preamble (due to
/// errors in the source that occurs in the preamble), the number of
/// reparses during which we'll skip even trying to precompile the
@@ -1100,7 +1078,6 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// Clear out old caches and data.
TopLevelDecls.clear();
clearFileLevelDecls();
- CleanTemporaryFiles();
if (!OverrideMainBuffer) {
checkAndRemoveNonDriverDiags(StoredDiagnostics);
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 9773acb840a5..5a1c572ce614 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -2133,7 +2133,7 @@ void _mm_sfence(void);
/// \headerfile <x86intrin.h>
///
/// \code
-/// void _mm_extract_pi(__m64 a, int n);
+/// int _mm_extract_pi16(__m64 a, int n);
/// \endcode
///
/// This intrinsic corresponds to the <c> VPEXTRW / PEXTRW </c> instruction.
@@ -2157,7 +2157,7 @@ void _mm_sfence(void);
/// \headerfile <x86intrin.h>
///
/// \code
-/// void _mm_insert_pi(__m64 a, int d, int n);
+/// __m64 _mm_insert_pi16(__m64 a, int d, int n);
/// \endcode
///
/// This intrinsic corresponds to the <c> VPINSRW / PINSRW </c> instruction.
@@ -2680,8 +2680,7 @@ _mm_movelh_ps(__m128 __a, __m128 __b)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [4 x i16]. The elements of the destination are copied
@@ -2711,8 +2710,7 @@ _mm_cvtpi16_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of 16-bit unsigned integer values. The elements of the
@@ -2741,8 +2739,7 @@ _mm_cvtpu16_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [8 x i8]. The elements of the destination are copied
@@ -2766,8 +2763,7 @@ _mm_cvtpi8_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of unsigned 8-bit integer values. The elements of the
@@ -2791,8 +2787,7 @@ _mm_cvtpu8_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [2 x i32]. The lower elements of the destination are
@@ -2826,8 +2821,7 @@ _mm_cvtpi32x2_ps(__m64 __a, __m64 __b)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPS2PI + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPS2PI + COMPOSITE </c> instruction.
///
/// \param __a
/// A 128-bit floating-point vector of [4 x float].
@@ -2857,8 +2851,7 @@ _mm_cvtps_pi16(__m128 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPS2PI + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPS2PI + COMPOSITE </c> instruction.
///
/// \param __a
/// 128-bit floating-point vector of [4 x float].
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 3d6fe91115a9..92942fd09a0c 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -43,6 +43,8 @@ using namespace clang;
/// isObjCAtKeyword - Return true if we have an ObjC keyword identifier.
bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
+ if (isAnnotation())
+ return false;
if (IdentifierInfo *II = getIdentifierInfo())
return II->getObjCKeywordID() == objcKey;
return false;
@@ -50,6 +52,8 @@ bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
/// getObjCKeywordID - Return the ObjC keyword kind.
tok::ObjCKeywordKind Token::getObjCKeywordID() const {
+ if (isAnnotation())
+ return tok::objc_not_keyword;
IdentifierInfo *specId = getIdentifierInfo();
return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword;
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index ca1d27e9505f..e7b0914641ff 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -93,11 +93,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false),
- TUKind(TUKind), NumSFINAEErrors(0), CachedFakeTopLevelModule(nullptr),
- AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
- NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
- TyposCorrected(0), AnalysisWarnings(*this),
+ TUKind(TUKind), NumSFINAEErrors(0), AccessCheckingSFINAE(false),
+ InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
+ ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr),
+ DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
TUScope = nullptr;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2e069a9defaa..dca51b0e8c8e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -16047,6 +16047,14 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
VisibleModules.setVisible(Mod, DirectiveLoc);
+
+ // The enclosing context is now part of this module.
+ // FIXME: Consider creating a child DeclContext to hold the entities
+ // lexically within the module.
+ if (getLangOpts().trackLocalOwningModule()) {
+ cast<Decl>(CurContext)->setHidden(true);
+ cast<Decl>(CurContext)->setLocalOwningModule(Mod);
+ }
}
void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
@@ -16075,6 +16083,13 @@ void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
DirectiveLoc = EomLoc;
}
BuildModuleInclude(DirectiveLoc, Mod);
+
+ // Any further declarations are in whatever module we returned to.
+ if (getLangOpts().trackLocalOwningModule()) {
+ cast<Decl>(CurContext)->setLocalOwningModule(getCurrentModule());
+ if (!getCurrentModule())
+ cast<Decl>(CurContext)->setHidden(false);
+ }
}
void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index c5b579a4b2e9..04350831c681 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -1326,62 +1326,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return !R.empty();
}
-Module *Sema::getOwningModule(Decl *Entity) {
- // If it's imported, grab its owning module.
- Module *M = Entity->getImportedOwningModule();
- if (M || !isa<NamedDecl>(Entity) || !cast<NamedDecl>(Entity)->isHidden())
- return M;
- assert(!Entity->isFromASTFile() &&
- "hidden entity from AST file has no owning module");
-
- if (!getLangOpts().ModulesLocalVisibility) {
- // If we're not tracking visibility locally, the only way a declaration
- // can be hidden and local is if it's hidden because it's parent is (for
- // instance, maybe this is a lazily-declared special member of an imported
- // class).
- auto *Parent = cast<NamedDecl>(Entity->getDeclContext());
- assert(Parent->isHidden() && "unexpectedly hidden decl");
- return getOwningModule(Parent);
- }
-
- // It's local and hidden; grab or compute its owning module.
- M = Entity->getLocalOwningModule();
- if (M)
- return M;
-
- if (auto *Containing =
- PP.getModuleContainingLocation(Entity->getLocation())) {
- M = Containing;
- } else if (Entity->isInvalidDecl() || Entity->getLocation().isInvalid()) {
- // Don't bother tracking visibility for invalid declarations with broken
- // locations.
- cast<NamedDecl>(Entity)->setHidden(false);
- } else {
- // We need to assign a module to an entity that exists outside of any
- // module, so that we can hide it from modules that we textually enter.
- // Invent a fake module for all such entities.
- if (!CachedFakeTopLevelModule) {
- CachedFakeTopLevelModule =
- PP.getHeaderSearchInfo().getModuleMap().findOrCreateModule(
- "<top-level>", nullptr, false, false).first;
-
- auto &SrcMgr = PP.getSourceManager();
- SourceLocation StartLoc =
- SrcMgr.getLocForStartOfFile(SrcMgr.getMainFileID());
- auto &TopLevel = ModuleScopes.empty()
- ? VisibleModules
- : ModuleScopes[0].OuterVisibleModules;
- TopLevel.setVisible(CachedFakeTopLevelModule, StartLoc);
- }
-
- M = CachedFakeTopLevelModule;
- }
-
- if (M)
- Entity->setLocalOwningModule(M);
- return M;
-}
-
void Sema::makeMergedDefinitionVisible(NamedDecl *ND) {
if (auto *M = getCurrentModule())
Context.mergeDefinitionIntoModule(ND, M);
@@ -1520,7 +1464,6 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
if (SemaRef.getLangOpts().ModulesLocalVisibility) {
DeclModule = SemaRef.getOwningModule(D);
if (!DeclModule) {
- // getOwningModule() may have decided the declaration should not be hidden.
assert(!D->isHidden() && "hidden decl not from a module");
return true;
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index ef8481488302..5cabd0e6740d 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -9348,12 +9348,6 @@ void ASTReader::diagnoseOdrViolations() {
return Hash.CalculateHash();
};
- auto ComputeDeclNameODRHash = [&Hash](const DeclarationName Name) {
- Hash.clear();
- Hash.AddDeclarationName(Name);
- return Hash.CalculateHash();
- };
-
auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
Hash.clear();
Hash.AddQualType(Ty);
@@ -9446,11 +9440,8 @@ void ASTReader::diagnoseOdrViolations() {
QualType FirstType = FirstField->getType();
QualType SecondType = SecondField->getType();
- const TypedefType *FirstTypedef = dyn_cast<TypedefType>(FirstType);
- const TypedefType *SecondTypedef = dyn_cast<TypedefType>(SecondType);
-
- if ((FirstTypedef && !SecondTypedef) ||
- (!FirstTypedef && SecondTypedef)) {
+ if (ComputeQualTypeODRHash(FirstType) !=
+ ComputeQualTypeODRHash(SecondType)) {
ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
FieldTypeName)
<< FirstII << FirstType;
@@ -9462,24 +9453,6 @@ void ASTReader::diagnoseOdrViolations() {
break;
}
- if (FirstTypedef && SecondTypedef) {
- unsigned FirstHash = ComputeDeclNameODRHash(
- FirstTypedef->getDecl()->getDeclName());
- unsigned SecondHash = ComputeDeclNameODRHash(
- SecondTypedef->getDecl()->getDeclName());
- if (FirstHash != SecondHash) {
- ODRDiagError(FirstField->getLocation(),
- FirstField->getSourceRange(), FieldTypeName)
- << FirstII << FirstType;
- ODRDiagNote(SecondField->getLocation(),
- SecondField->getSourceRange(), FieldTypeName)
- << SecondII << SecondType;
-
- Diagnosed = true;
- break;
- }
- }
-
const bool IsFirstBitField = FirstField->isBitField();
const bool IsSecondBitField = SecondField->isBitField();
if (IsFirstBitField != IsSecondBitField) {
diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp
index 5b81197671e2..95857e339085 100644
--- a/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-namespace.cpp
@@ -60,6 +60,10 @@ void B::func_fwd() {
anonymous = 0;
}
+namespace C {
+ void c();
+}
+void C::c() {}
// This should work even if 'i' and 'func' were declarations & not definitions,
// but it doesn't yet.
@@ -114,6 +118,8 @@ void B::func_fwd() {
// CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]]
// CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 53,{{.*}} isDefinition: true
// CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]]
+// CHECK: distinct !DISubprogram(name: "c",{{.*}}, scope: ![[C:[0-9]+]],{{.*}}, line: 60,{{.*}} isDefinition: true
+// CHECK: ![[C]] = !DINamespace(name: "C",
// CHECK-GMLT: [[CU:![0-9]+]] = distinct !DICompileUnit(
// CHECK-GMLT-SAME: emissionKind: LineTablesOnly,
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index 7416d7008b85..c0fe6c557f22 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -441,3 +441,7 @@ module DebugNestedB {
header "DebugNestedB.h"
export *
}
+
+module objcAtKeywordMissingEnd {
+ header "objcAtKeywordMissingEnd.h"
+}
diff --git a/test/Modules/Inputs/objcAtKeywordMissingEnd.h b/test/Modules/Inputs/objcAtKeywordMissingEnd.h
new file mode 100644
index 000000000000..1196b87eef8e
--- /dev/null
+++ b/test/Modules/Inputs/objcAtKeywordMissingEnd.h
@@ -0,0 +1,3 @@
+@interface MissingEnd // expected-note {{class started here}}
+
+@ // expected-error {{expected an Objective-C directive after '@'}} expected-error {{missing '@end'}}
diff --git a/test/Modules/Inputs/submodule-visibility/b.h b/test/Modules/Inputs/submodule-visibility/b.h
index 67ef6529dbd8..39df6a02cb40 100644
--- a/test/Modules/Inputs/submodule-visibility/b.h
+++ b/test/Modules/Inputs/submodule-visibility/b.h
@@ -4,7 +4,11 @@ int m = n;
#include "c.h"
#if defined(A) && !defined(ALLOW_NAME_LEAKAGE)
-#error A is defined
+#warning A is defined
#endif
#define B
+
+template<typename T> void b_template() {
+ N::C::f(0);
+}
diff --git a/test/Modules/Inputs/submodule-visibility/other.h b/test/Modules/Inputs/submodule-visibility/other.h
index f40c757ca62e..4b68c489153c 100644
--- a/test/Modules/Inputs/submodule-visibility/other.h
+++ b/test/Modules/Inputs/submodule-visibility/other.h
@@ -1 +1,10 @@
#include "c.h"
+
+#ifndef OTHER_H
+#define OTHER_H
+namespace N {
+ struct C {
+ template<typename U> static void f(U) {}
+ };
+}
+#endif
diff --git a/test/Modules/objc-at-keyword.m b/test/Modules/objc-at-keyword.m
new file mode 100644
index 000000000000..0e058a309017
--- /dev/null
+++ b/test/Modules/objc-at-keyword.m
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify -x objective-c -fmodule-name=objcAtKeywordMissingEnd -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c -fmodule-name=Empty -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify -I %S/Inputs %s
+
+@interface X // expected-note {{class started here}}
+#pragma clang module import Empty // expected-error {{missing '@end'}}
diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp
index 58814dd6b3fb..947583bcfd21 100644
--- a/test/Modules/odr_hash.cpp
+++ b/test/Modules/odr_hash.cpp
@@ -634,6 +634,237 @@ S3 s3;
#endif
} // namespace Using
+namespace RecordType {
+#if defined(FIRST)
+struct B1 {};
+struct S1 {
+ B1 x;
+};
+#elif defined(SECOND)
+struct A1 {};
+struct S1 {
+ A1 x;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'RecordType::S1::x' from module 'FirstModule' is not present in definition of 'RecordType::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
+
+namespace DependentType {
+#if defined(FIRST)
+template <class T>
+class S1 {
+ typename T::typeA x;
+};
+#elif defined(SECOND)
+template <class T>
+class S1 {
+ typename T::typeB x;
+};
+#else
+template<class T>
+using U1 = S1<T>;
+// expected-error@first.h:* {{'DependentType::S1::x' from module 'FirstModule' is not present in definition of 'S1<T>' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
+
+namespace ElaboratedType {
+#if defined(FIRST)
+namespace N1 { using type = double; }
+struct S1 {
+ N1::type x;
+};
+#elif defined(SECOND)
+namespace N1 { using type = int; }
+struct S1 {
+ N1::type x;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'ElaboratedType::S1::x' from module 'FirstModule' is not present in definition of 'ElaboratedType::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
+
+namespace Enum {
+#if defined(FIRST)
+enum A1 {};
+struct S1 {
+ A1 x;
+};
+#elif defined(SECOND)
+enum A2 {};
+struct S1 {
+ A2 x;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'Enum::S1::x' from module 'FirstModule' is not present in definition of 'Enum::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
+
+namespace NestedNamespaceSpecifier {
+#if defined(FIRST)
+namespace LevelA1 {
+using Type = int;
+}
+
+struct S1 {
+ LevelA1::Type x;
+};
+# elif defined(SECOND)
+namespace LevelB1 {
+namespace LevelC1 {
+using Type = int;
+}
+}
+
+struct S1 {
+ LevelB1::LevelC1::Type x;
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'LevelB1::LevelC1::Type' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'LevelA1::Type' (aka 'int')}}
+#endif
+
+#if defined(FIRST)
+namespace LevelA2 { using Type = int; }
+struct S2 {
+ LevelA2::Type x;
+};
+# elif defined(SECOND)
+struct S2 {
+ int x;
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'int'}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'LevelA2::Type' (aka 'int')}}
+#endif
+
+namespace LevelA3 { using Type = int; }
+namespace LevelB3 { using Type = int; }
+#if defined(FIRST)
+struct S3 {
+ LevelA3::Type x;
+};
+# elif defined(SECOND)
+struct S3 {
+ LevelB3::Type x;
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'LevelB3::Type' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'LevelA3::Type' (aka 'int')}}
+#endif
+
+#if defined(FIRST)
+struct TA4 { using Type = int; };
+struct S4 {
+ TA4::Type x;
+};
+# elif defined(SECOND)
+struct TB4 { using Type = int; };
+struct S4 {
+ TB4::Type x;
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'TB4::Type' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'TA4::Type' (aka 'int')}}
+#endif
+
+#if defined(FIRST)
+struct T5 { using Type = int; };
+struct S5 {
+ T5::Type x;
+};
+# elif defined(SECOND)
+namespace T5 { using Type = int; };
+struct S5 {
+ T5::Type x;
+};
+#else
+S5 s5;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'T5::Type' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'T5::Type' (aka 'int')}}
+#endif
+
+#if defined(FIRST)
+namespace N6 {using I = int;}
+struct S6 {
+ NestedNamespaceSpecifier::N6::I x;
+};
+# elif defined(SECOND)
+using I = int;
+struct S6 {
+ ::NestedNamespaceSpecifier::I x;
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type '::NestedNamespaceSpecifier::I' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'NestedNamespaceSpecifier::N6::I' (aka 'int')}}
+#endif
+
+#if defined(FIRST)
+template <class T, class U>
+class S7 {
+ typename T::type *x = {};
+ int z = x->T::foo();
+};
+#elif defined(SECOND)
+template <class T, class U>
+class S7 {
+ typename T::type *x = {};
+ int z = x->U::foo();
+};
+#else
+template <class T, class U>
+using U7 = S7<T, U>;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'z' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'z' with a different initializer}}
+#endif
+
+#if defined(FIRST)
+template <class T>
+class S8 {
+ int x = T::template X<int>::value;
+};
+#elif defined(SECOND)
+template <class T>
+class S8 {
+ int x = T::template Y<int>::value;
+};
+#else
+template <class T>
+using U8 = S8<T>;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with a different initializer}}
+#endif
+
+#if defined(FIRST)
+namespace N9 { using I = int; }
+namespace O9 = N9;
+struct S9 {
+ O9::I x;
+};
+#elif defined(SECOND)
+namespace N9 { using I = int; }
+namespace P9 = N9;
+struct S9 {
+ P9::I x;
+};
+#else
+S9 s9;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'P9::I' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'O9::I' (aka 'int')}}
+#endif
+}
// Interesting cases that should not cause errors. struct S should not error
// while struct T should error at the access specifier mismatch at the end.
diff --git a/test/Modules/submodule-visibility.cpp b/test/Modules/submodule-visibility.cpp
index 345ae155bb32..4c066e6ab9b0 100644
--- a/test/Modules/submodule-visibility.cpp
+++ b/test/Modules/submodule-visibility.cpp
@@ -3,6 +3,11 @@
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -I%S/Inputs/submodule-visibility -verify %s -DIMPORT
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -fmodule-name=x -I%S/Inputs/submodule-visibility -verify %s
// RUN: %clang_cc1 -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -I%S/Inputs/submodule-visibility -verify %s
+//
+// Explicit module builds.
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -emit-module -x c++-module-map %S/Inputs/submodule-visibility/module.modulemap -fmodule-name=other -o %t/other.pcm
+// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/submodule-visibility/module.modulemap -fmodules-local-submodule-visibility -fmodule-file=%t/other.pcm -verify -fmodule-name=x -I%S/Inputs/submodule-visibility %s
+// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/submodule-visibility/module.modulemap -fmodule-file=%t/other.pcm -verify -fmodule-name=x -I%S/Inputs/submodule-visibility %s -DALLOW_TEXTUAL_NAME_LEAKAGE
#include "a.h"
#include "b.h"
@@ -11,6 +16,8 @@
// expected-no-diagnostics
#elif IMPORT
// expected-error@-6 {{could not build module 'x'}}
+#elif ALLOW_TEXTUAL_NAME_LEAKAGE
+// expected-warning@b.h:7 {{A is defined}}
#else
// The use of -fmodule-name=x causes us to textually include the above headers.
// The submodule visibility rules are still applied in this case.
@@ -35,3 +42,5 @@ typedef struct {
int p;
void (*f)(int p);
} name_for_linkage;
+
+void g() { b_template<int>(); }