@@ -138,6 +138,46 @@ namespace clang {
138
138
To->setIsUsed ();
139
139
}
140
140
141
+ // / How to handle import errors that occur when import of a child declaration
142
+ // / of a DeclContext fails.
143
+ class ChildErrorHandlingStrategy {
144
+ // / This context is imported (in the 'from' domain).
145
+ // / It is nullptr if a non-DeclContext is imported.
146
+ const DeclContext *const FromDC;
147
+ // / Ignore import errors of the children.
148
+ // / If true, the context can be imported successfully if a child
149
+ // / of it failed to import. Otherwise the import errors of the child nodes
150
+ // / are accumulated (joined) into the import error object of the parent.
151
+ // / (Import of a parent can fail in other ways.)
152
+ bool const IgnoreChildErrors;
153
+
154
+ public:
155
+ ChildErrorHandlingStrategy (const DeclContext *FromDC)
156
+ : FromDC(FromDC), IgnoreChildErrors(!isa<TagDecl>(FromDC)) {}
157
+ ChildErrorHandlingStrategy (const Decl *FromD)
158
+ : FromDC(dyn_cast<DeclContext>(FromD)),
159
+ IgnoreChildErrors (!isa<TagDecl>(FromD)) {}
160
+
161
+ // / Process the import result of a child (of the current declaration).
162
+ // / \param ResultErr The import error that can be used as result of
163
+ // / importing the parent. This may be changed by the function.
164
+ // / \param ChildErr Result of importing a child. Can be success or error.
165
+ void handleChildImportResult (Error &ResultErr, Error &&ChildErr) {
166
+ if (ChildErr && !IgnoreChildErrors)
167
+ ResultErr = joinErrors (std::move (ResultErr), std::move (ChildErr));
168
+ else
169
+ consumeError (std::move (ChildErr));
170
+ }
171
+
172
+ // / Determine if import failure of a child does not cause import failure of
173
+ // / its parent.
174
+ bool ignoreChildErrorOnParent (Decl *FromChildD) const {
175
+ if (!IgnoreChildErrors || !FromDC)
176
+ return false ;
177
+ return FromDC->containsDecl (FromChildD);
178
+ }
179
+ };
180
+
141
181
class ASTNodeImporter : public TypeVisitor <ASTNodeImporter, ExpectedType>,
142
182
public DeclVisitor<ASTNodeImporter, ExpectedDecl>,
143
183
public StmtVisitor<ASTNodeImporter, ExpectedStmt> {
@@ -1809,7 +1849,7 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
1809
1849
// because there is an ODR error with two typedefs. As another example,
1810
1850
// the client may allow EnumConstantDecls with same names but with
1811
1851
// different values in two distinct translation units.
1812
- bool AccumulateChildErrors = isa<TagDecl> (FromDC);
1852
+ ChildErrorHandlingStrategy HandleChildErrors (FromDC);
1813
1853
1814
1854
Error ChildErrors = Error::success ();
1815
1855
for (auto *From : FromDC->decls ()) {
@@ -1849,20 +1889,14 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
1849
1889
if (FromRecordDecl->isCompleteDefinition () &&
1850
1890
!ToRecordDecl->isCompleteDefinition ()) {
1851
1891
Error Err = ImportDefinition (FromRecordDecl, ToRecordDecl);
1852
-
1853
- if (Err && AccumulateChildErrors)
1854
- ChildErrors = joinErrors (std::move (ChildErrors), std::move (Err));
1855
- else
1856
- consumeError (std::move (Err));
1892
+ HandleChildErrors.handleChildImportResult (ChildErrors,
1893
+ std::move (Err));
1857
1894
}
1858
1895
}
1859
1896
}
1860
1897
} else {
1861
- if (AccumulateChildErrors)
1862
- ChildErrors =
1863
- joinErrors (std::move (ChildErrors), ImportedOrErr.takeError ());
1864
- else
1865
- consumeError (ImportedOrErr.takeError ());
1898
+ HandleChildErrors.handleChildImportResult (ChildErrors,
1899
+ ImportedOrErr.takeError ());
1866
1900
}
1867
1901
}
1868
1902
@@ -8799,8 +8833,20 @@ Expected<Decl *> ASTImporter::Import(Decl *FromD) {
8799
8833
8800
8834
// Set the error for all nodes which have been created before we
8801
8835
// recognized the error.
8802
- for (const auto &Path : SavedImportPaths[FromD])
8836
+ for (const auto &Path : SavedImportPaths[FromD]) {
8837
+ // The import path contains import-dependency nodes first.
8838
+ // Save the node that was imported as dependency of the current node.
8839
+ Decl *PrevFromDi = FromD;
8803
8840
for (Decl *FromDi : Path) {
8841
+ // Begin and end of the path equals 'FromD', skip it.
8842
+ if (FromDi == FromD)
8843
+ continue ;
8844
+ // We should not set import error on a node and all following nodes in
8845
+ // the path if child import errors are ignored.
8846
+ if (ChildErrorHandlingStrategy (FromDi).ignoreChildErrorOnParent (
8847
+ PrevFromDi))
8848
+ break ;
8849
+ PrevFromDi = FromDi;
8804
8850
setImportDeclError (FromDi, ErrOut);
8805
8851
// FIXME Should we remove these Decls from ImportedDecls?
8806
8852
// Set the error for the mapped to Decl, which is in the "to" context.
@@ -8810,6 +8856,7 @@ Expected<Decl *> ASTImporter::Import(Decl *FromD) {
8810
8856
// FIXME Should we remove these Decls from the LookupTable,
8811
8857
// and from ImportedFromDecls?
8812
8858
}
8859
+ }
8813
8860
SavedImportPaths.erase (FromD);
8814
8861
8815
8862
// Do not return ToDOrErr, error was taken out of it.
0 commit comments