Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4521,6 +4521,23 @@ class RecordDecl : public TagDecl {
return field_begin() == field_end();
}

/// noload_fields - Iterate over the fields stored in this record
/// that are currently loaded; don't attempt to retrieve anything
/// from an external source.
field_range noload_fields() const {
return field_range(noload_field_begin(), noload_field_end());
}

field_iterator noload_field_begin() const;
field_iterator noload_field_end() const {
return field_iterator(decl_iterator());
}

// Whether there are any fields (non-static data members) in this record.
bool noload_field_empty() const {
return noload_field_begin() == noload_field_end();
}

/// Note that the definition of this type is now complete.
virtual void completeDefinition();

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5161,6 +5161,10 @@ RecordDecl::field_iterator RecordDecl::field_begin() const {
return field_iterator(decl_iterator(FirstDecl));
}

RecordDecl::field_iterator RecordDecl::noload_field_begin() const {
return field_iterator(decl_iterator(getDefinitionOrSelf()->FirstDecl));
}

/// completeDefinition - Notes that the definition of this type is now
/// complete.
void RecordDecl::completeDefinition() {
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3432,7 +3432,19 @@ NamedDecl *ASTDeclReader::getAnonymousDeclForMerging(ASTReader &Reader,
// If this is the first time, but we have parsed a declaration of the context,
// build the anonymous declaration list from the parsed declaration.
auto *PrimaryDC = getPrimaryDCForAnonymousDecl(DC);
if (PrimaryDC && !cast<Decl>(PrimaryDC)->isFromASTFile()) {
auto needToNumberAnonymousDeclsWithin = [](Decl *D) {
if (!D->isFromASTFile())
return true;
// If this is a class template specialization from an AST file, has at least
// one field, but none of the fields have been loaded from external storage,
// this is a situation where the class template specialization decl
// was imported but the definition was instantiated within the source.
// In such a case, we still need to number the anonymous decls.
auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D);
return CTSD && !CTSD->noload_field_empty() &&
!CTSD->hasLoadedFieldsFromExternalStorage();
};
if (PrimaryDC && needToNumberAnonymousDeclsWithin(cast<Decl>(PrimaryDC))) {
numberAnonymousDeclsWithin(PrimaryDC, [&](NamedDecl *ND, unsigned Number) {
if (Previous.size() == Number)
Previous.push_back(cast<NamedDecl>(ND->getCanonicalDecl()));
Expand Down
47 changes: 47 additions & 0 deletions clang/test/Modules/merge-anon-in-template-2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t

// RUN: %clang_cc1 -std=c++20 -fmodule-name=hu-01 -emit-header-unit -xc++-user-header %t/hu-01.h \
// RUN: -o %t/hu-01.pcm

// RUN: %clang_cc1 -std=c++20 -fmodule-name=hu-02 -emit-header-unit -xc++-user-header %t/hu-02.h \
// RUN: -Wno-experimental-header-units \
// RUN: -fmodule-map-file=%t/hu-01.map -fmodule-file=hu-01=%t/hu-01.pcm \
// RUN: -o %t/hu-02.pcm

// RUN: %clang_cc1 -std=c++20 -emit-obj %t/main.cpp \
// RUN: -Wno-experimental-header-units \
// RUN: -fmodule-map-file=%t/hu-01.map -fmodule-file=hu-01=%t/hu-01.pcm \
// RUN: -fmodule-map-file=%t/hu-02.map -fmodule-file=hu-02=%t/hu-02.pcm

//--- hu-01.map
module "hu-01" {
header "hu-01.h"
export *
}

//--- hu-02.map
module "hu-02" {
header "hu-02.h"
export *
}

//--- hu-01.h
template <typename T>
struct S { union { T x; }; };

using SI = S<int>;

//--- hu-02.h
template <typename T>
struct S { union { T x; }; };

inline void f(S<int> s = {}) { s.x; }

//--- main.cpp
import "hu-01.h";
void g(S<int>) {}

import "hu-02.h";
void h() { f(); }
45 changes: 45 additions & 0 deletions clang/test/Modules/merge-anon-in-template-3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t

// RUN: %clang_cc1 -std=c++20 -fmodule-name=hu-01 -emit-header-unit -xc++-user-header %t/hu-01.h \
// RUN: -o %t/hu-01.pcm

// RUN: %clang_cc1 -std=c++20 -fmodule-name=hu-02 -emit-header-unit -xc++-user-header %t/hu-02.h \
// RUN: -Wno-experimental-header-units \
// RUN: -fmodule-map-file=%t/hu-01.map -fmodule-file=hu-01=%t/hu-01.pcm \
// RUN: -o %t/hu-02.pcm

// RUN: %clang_cc1 -std=c++20 -emit-obj %t/main.cpp \
// RUN: -Wno-experimental-header-units \
// RUN: -fmodule-map-file=%t/hu-01.map -fmodule-file=hu-01=%t/hu-01.pcm \
// RUN: -fmodule-map-file=%t/hu-02.map -fmodule-file=hu-02=%t/hu-02.pcm

//--- hu-01.map
module "hu-01" {
header "hu-01.h"
export *
}

//--- hu-02.map
module "hu-02" {
header "hu-02.h"
export *
}

//--- hu-01.h
template <typename T>
struct S { union { T x; }; };

using SI = S<int>;

//--- hu-02.h
import "hu-01.h";
inline void f(S<int> s = {}) { s.x; }

//--- main.cpp
import "hu-01.h";
void g(S<int>) {}

import "hu-02.h";
void h() { f(); }
Loading