diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
commit | 2298981669bf3bd63335a4be179bc0f96823a8f4 (patch) | |
tree | 1cbe2eb27f030d2d70b80ee5ca3c86bee7326a9f /lib/AST/ASTImporter.cpp | |
parent | 9a83721404652cea39e9f02ae3e3b5c964602a5c (diff) |
Notes
Diffstat (limited to 'lib/AST/ASTImporter.cpp')
-rw-r--r-- | lib/AST/ASTImporter.cpp | 1888 |
1 files changed, 1055 insertions, 833 deletions
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 44832557e97be..9d5dd84161dec 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -1,9 +1,8 @@ //===- ASTImporter.cpp - Importing ASTs from other Contexts ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -13,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTImporter.h" -#include "clang/AST/ASTImporterLookupTable.h" +#include "clang/AST/ASTImporterSharedState.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTStructuralEquivalence.h" @@ -58,6 +57,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" @@ -135,25 +135,6 @@ namespace clang { To->setIsUsed(); } - // FIXME: Temporary until every import returns Expected. - template <> - LLVM_NODISCARD Error - ASTImporter::importInto(SourceLocation &To, const SourceLocation &From) { - To = Import(From); - if (From.isValid() && To.isInvalid()) - return llvm::make_error<ImportError>(); - return Error::success(); - } - // FIXME: Temporary until every import returns Expected. - template <> - LLVM_NODISCARD Error - ASTImporter::importInto(QualType &To, const QualType &From) { - To = Import(From); - if (!From.isNull() && To.isNull()) - return llvm::make_error<ImportError>(); - return Error::success(); - } - class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, ExpectedType>, public DeclVisitor<ASTNodeImporter, ExpectedDecl>, public StmtVisitor<ASTNodeImporter, ExpectedStmt> { @@ -168,32 +149,20 @@ namespace clang { // Use this to import pointers of specific type. template <typename ImportT> LLVM_NODISCARD Error importInto(ImportT *&To, ImportT *From) { - auto ToI = Importer.Import(From); - if (!ToI && From) - return make_error<ImportError>(); - To = cast_or_null<ImportT>(ToI); - return Error::success(); - // FIXME: This should be the final code. - //auto ToOrErr = Importer.Import(From); - //if (ToOrErr) { - // To = cast_or_null<ImportT>(*ToOrErr); - //} - //return ToOrErr.takeError(); + auto ToOrErr = Importer.Import(From); + if (ToOrErr) + To = cast_or_null<ImportT>(*ToOrErr); + return ToOrErr.takeError(); } // Call the import function of ASTImporter for a baseclass of type `T` and // cast the return value to `T`. template <typename T> Expected<T *> import(T *From) { - auto *To = Importer.Import(From); - if (!To && From) - return make_error<ImportError>(); - return cast_or_null<T>(To); - // FIXME: This should be the final code. - //auto ToOrErr = Importer.Import(From); - //if (!ToOrErr) - // return ToOrErr.takeError(); - //return cast_or_null<T>(*ToOrErr); + auto ToOrErr = Importer.Import(From); + if (!ToOrErr) + return ToOrErr.takeError(); + return cast_or_null<T>(*ToOrErr); } template <typename T> @@ -204,13 +173,15 @@ namespace clang { // Call the import function of ASTImporter for type `T`. template <typename T> Expected<T> import(const T &From) { - T To = Importer.Import(From); - T DefaultT; - if (To == DefaultT && !(From == DefaultT)) - return make_error<ImportError>(); - return To; - // FIXME: This should be the final code. - //return Importer.Import(From); + return Importer.Import(From); + } + + // Import an Optional<T> by importing the contained T, if any. + template<typename T> + Expected<Optional<T>> import(Optional<T> From) { + if (!From) + return Optional<T>(); + return import(*From); } template <class T> @@ -283,18 +254,16 @@ namespace clang { LLVM_NODISCARD bool GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun, FromDeclT *FromD, Args &&... args) { - // FIXME: This code is needed later. - //if (Importer.getImportDeclErrorIfAny(FromD)) { - // ToD = nullptr; - // return true; // Already imported but with error. - //} + if (Importer.getImportDeclErrorIfAny(FromD)) { + ToD = nullptr; + return true; // Already imported but with error. + } ToD = cast_or_null<ToDeclT>(Importer.GetAlreadyImportedOrNull(FromD)); if (ToD) return true; // Already imported. ToD = CreateFun(std::forward<Args>(args)...); // Keep track of imported Decls. - Importer.MapImported(FromD, ToD); - Importer.AddToLookupTable(ToD); + Importer.RegisterImportedDecl(FromD, ToD); InitializeImportedDecl(FromD, ToD); return false; // A new Decl is created. } @@ -302,14 +271,31 @@ namespace clang { void InitializeImportedDecl(Decl *FromD, Decl *ToD) { ToD->IdentifierNamespace = FromD->IdentifierNamespace; if (FromD->hasAttrs()) - for (const Attr *FromAttr : FromD->getAttrs()) - ToD->addAttr(Importer.Import(FromAttr)); + for (const Attr *FromAttr : FromD->getAttrs()) { + // FIXME: Return of the error here is not possible until store of + // import errors is implemented. + auto ToAttrOrErr = import(FromAttr); + if (ToAttrOrErr) + ToD->addAttr(*ToAttrOrErr); + else + llvm::consumeError(ToAttrOrErr.takeError()); + } if (FromD->isUsed()) ToD->setIsUsed(); if (FromD->isImplicit()) ToD->setImplicit(); } + // Check if we have found an existing definition. Returns with that + // definition if yes, otherwise returns null. + Decl *FindAndMapDefinition(FunctionDecl *D, FunctionDecl *FoundFunction) { + const FunctionDecl *Definition = nullptr; + if (D->doesThisDeclarationHaveABody() && + FoundFunction->hasBody(Definition)) + return Importer.MapImported(D, const_cast<FunctionDecl *>(Definition)); + return nullptr; + } + public: explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {} @@ -412,8 +398,6 @@ namespace clang { Error ImportDefinition( ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind = IDK_Default); - Expected<TemplateParameterList *> ImportTemplateParameterList( - TemplateParameterList *Params); Error ImportTemplateArguments( const TemplateArgument *FromArgs, unsigned NumFromArgs, SmallVectorImpl<TemplateArgument> &ToArgs); @@ -435,9 +419,16 @@ namespace clang { Expected<FunctionTemplateAndArgsTy> ImportFunctionTemplateWithTemplateArgsFromSpecialization( FunctionDecl *FromFD); + Error ImportTemplateParameterLists(const DeclaratorDecl *FromD, + DeclaratorDecl *ToD); Error ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD); + Error ImportFunctionDeclBody(FunctionDecl *FromFD, FunctionDecl *ToFD); + + template <typename T> + bool hasSameVisibilityContext(T *Found, T *From); + bool IsStructuralMatch(Decl *From, Decl *To, bool Complain); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); @@ -548,6 +539,7 @@ namespace clang { // Importing expressions ExpectedStmt VisitExpr(Expr *E); ExpectedStmt VisitVAArgExpr(VAArgExpr *E); + ExpectedStmt VisitChooseExpr(ChooseExpr *E); ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E); ExpectedStmt VisitPredefinedExpr(PredefinedExpr *E); ExpectedStmt VisitDeclRefExpr(DeclRefExpr *E); @@ -649,15 +641,6 @@ namespace clang { FunctionDecl *FromFD); }; -// FIXME: Temporary until every import returns Expected. -template <> -Expected<TemplateName> ASTNodeImporter::import(const TemplateName &From) { - TemplateName To = Importer.Import(From); - if (To.isNull() && !From.isNull()) - return make_error<ImportError>(); - return To; -} - template <typename InContainerTy> Error ASTNodeImporter::ImportTemplateArgumentListInfo( SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc, @@ -1649,16 +1632,32 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { auto ToDCOrErr = Importer.ImportContext(FromDC); return ToDCOrErr.takeError(); } + + // We use strict error handling in case of records and enums, but not + // with e.g. namespaces. + // + // FIXME Clients of the ASTImporter should be able to choose an + // appropriate error handling strategy for their needs. For instance, + // they may not want to mark an entire namespace as erroneous merely + // because there is an ODR error with two typedefs. As another example, + // the client may allow EnumConstantDecls with same names but with + // different values in two distinct translation units. + bool AccumulateChildErrors = isa<TagDecl>(FromDC); + + Error ChildErrors = Error::success(); llvm::SmallVector<Decl *, 8> ImportedDecls; for (auto *From : FromDC->decls()) { ExpectedDecl ImportedOrErr = import(From); - if (!ImportedOrErr) - // Ignore the error, continue with next Decl. - // FIXME: Handle this case somehow better. - consumeError(ImportedOrErr.takeError()); + if (!ImportedOrErr) { + if (AccumulateChildErrors) + ChildErrors = + joinErrors(std::move(ChildErrors), ImportedOrErr.takeError()); + else + consumeError(ImportedOrErr.takeError()); + } } - return Error::success(); + return ChildErrors; } Error ASTNodeImporter::ImportDeclContext( @@ -1698,29 +1697,50 @@ Error ASTNodeImporter::ImportImplicitMethods( static Error setTypedefNameForAnonDecl(TagDecl *From, TagDecl *To, ASTImporter &Importer) { if (TypedefNameDecl *FromTypedef = From->getTypedefNameForAnonDecl()) { - Decl *ToTypedef = Importer.Import(FromTypedef); - if (!ToTypedef) - return make_error<ImportError>(); - To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(ToTypedef)); - // FIXME: This should be the final code. - //if (Expected<Decl *> ToTypedefOrErr = Importer.Import(FromTypedef)) - // To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(*ToTypedefOrErr)); - //else - // return ToTypedefOrErr.takeError(); + if (ExpectedDecl ToTypedefOrErr = Importer.Import(FromTypedef)) + To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(*ToTypedefOrErr)); + else + return ToTypedefOrErr.takeError(); } return Error::success(); } Error ASTNodeImporter::ImportDefinition( RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind) { + auto DefinitionCompleter = [To]() { + // There are cases in LLDB when we first import a class without its + // members. The class will have DefinitionData, but no members. Then, + // importDefinition is called from LLDB, which tries to get the members, so + // when we get here, the class already has the DefinitionData set, so we + // must unset the CompleteDefinition here to be able to complete again the + // definition. + To->setCompleteDefinition(false); + To->completeDefinition(); + }; + if (To->getDefinition() || To->isBeingDefined()) { - if (Kind == IDK_Everything) - return ImportDeclContext(From, /*ForceImport=*/true); + if (Kind == IDK_Everything || + // In case of lambdas, the class already has a definition ptr set, but + // the contained decls are not imported yet. Also, isBeingDefined was + // set in CXXRecordDecl::CreateLambda. We must import the contained + // decls here and finish the definition. + (To->isLambda() && shouldForceImportDeclContext(Kind))) { + Error Result = ImportDeclContext(From, /*ForceImport=*/true); + // Finish the definition of the lambda, set isBeingDefined to false. + if (To->isLambda()) + DefinitionCompleter(); + return Result; + } return Error::success(); } To->startDefinition(); + // Complete the definition even if error is returned. + // The RecordDecl may be already part of the AST so it is better to + // have it in complete state even if something is wrong with it. + auto DefinitionCompleterScopeExit = + llvm::make_scope_exit(DefinitionCompleter); if (Error Err = setTypedefNameForAnonDecl(From, To, Importer)) return Err; @@ -1798,6 +1818,9 @@ Error ASTNodeImporter::ImportDefinition( ToData.HasDeclaredCopyAssignmentWithConstParam = FromData.HasDeclaredCopyAssignmentWithConstParam; + // Copy over the data stored in RecordDeclBits + ToCXX->setArgPassingRestrictions(FromCXX->getArgPassingRestrictions()); + SmallVector<CXXBaseSpecifier *, 4> Bases; for (const auto &Base1 : FromCXX->bases()) { ExpectedType TyOrErr = import(Base1.getType()); @@ -1842,7 +1865,6 @@ Error ASTNodeImporter::ImportDefinition( if (Error Err = ImportDeclContext(From, /*ForceImport=*/true)) return Err; - To->completeDefinition(); return Error::success(); } @@ -1903,40 +1925,6 @@ Error ASTNodeImporter::ImportDefinition( return Error::success(); } -// FIXME: Remove this, use `import` instead. -Expected<TemplateParameterList *> ASTNodeImporter::ImportTemplateParameterList( - TemplateParameterList *Params) { - SmallVector<NamedDecl *, 4> ToParams(Params->size()); - if (Error Err = ImportContainerChecked(*Params, ToParams)) - return std::move(Err); - - Expr *ToRequiresClause; - if (Expr *const R = Params->getRequiresClause()) { - if (Error Err = importInto(ToRequiresClause, R)) - return std::move(Err); - } else { - ToRequiresClause = nullptr; - } - - auto ToTemplateLocOrErr = import(Params->getTemplateLoc()); - if (!ToTemplateLocOrErr) - return ToTemplateLocOrErr.takeError(); - auto ToLAngleLocOrErr = import(Params->getLAngleLoc()); - if (!ToLAngleLocOrErr) - return ToLAngleLocOrErr.takeError(); - auto ToRAngleLocOrErr = import(Params->getRAngleLoc()); - if (!ToRAngleLocOrErr) - return ToRAngleLocOrErr.takeError(); - - return TemplateParameterList::Create( - Importer.getToContext(), - *ToTemplateLocOrErr, - *ToLAngleLocOrErr, - ToParams, - *ToRAngleLocOrErr, - ToRequiresClause); -} - Error ASTNodeImporter::ImportTemplateArguments( const TemplateArgument *FromArgs, unsigned NumFromArgs, SmallVectorImpl<TemplateArgument> &ToArgs) { @@ -2011,6 +1999,12 @@ bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, } bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { + // Eliminate a potential failure point where we attempt to re-import + // something we're trying to import while completing ToEnum. + if (Decl *ToOrigin = Importer.GetOriginalDecl(ToEnum)) + if (auto *ToOriginEnum = dyn_cast<EnumDecl>(ToOrigin)) + ToEnum = ToOriginEnum; + StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer)); @@ -2303,7 +2297,8 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType()) return Importer.MapImported(D, FoundTypedef); } - // FIXME Handle redecl chain. + // FIXME Handle redecl chain. When you do that make consistent changes + // in ASTImporterLookupTable too. break; } @@ -2492,6 +2487,8 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { } if (auto *FoundEnum = dyn_cast<EnumDecl>(FoundDecl)) { + if (!hasSameVisibilityContext(FoundEnum, D)) + continue; if (IsStructuralMatch(D, FoundEnum)) return Importer.MapImported(D, FoundEnum); } @@ -2500,7 +2497,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { } if (!ConflictingDecls.empty()) { - Name = Importer.HandleNameConflict(Name, DC, IDNS, + Name = Importer.HandleNameConflict(SearchName, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (!Name) @@ -2548,26 +2545,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Decl::FOK_None; } - // If this record has a definition in the translation unit we're coming from, - // but this particular declaration is not that definition, import the - // definition and map to that. - TagDecl *Definition = D->getDefinition(); - if (Definition && Definition != D && - // Friend template declaration must be imported on its own. - !IsFriendTemplate && - // In contrast to a normal CXXRecordDecl, the implicit - // CXXRecordDecl of ClassTemplateSpecializationDecl is its redeclaration. - // The definition of the implicit CXXRecordDecl in this case is the - // ClassTemplateSpecializationDecl itself. Thus, we start with an extra - // condition in order to be able to import the implict Decl. - !D->isImplicit()) { - ExpectedDecl ImportedDefOrErr = import(Definition); - if (!ImportedDefOrErr) - return ImportedDefOrErr.takeError(); - - return Importer.MapImported(D, *ImportedDefOrErr); - } - // Import the major distinguishing characteristics of this record. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -2596,7 +2573,8 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { auto FoundDecls = Importer.findDeclsInToCtx(DC, SearchName); if (!FoundDecls.empty()) { - // We're going to have to compare D against potentially conflicting Decls, so complete it. + // We're going to have to compare D against potentially conflicting Decls, + // so complete it. if (D->hasExternalLexicalStorage() && !D->isCompleteDefinition()) D->getASTContext().getExternalSource()->CompleteType(D); } @@ -2625,6 +2603,9 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { if (!IsStructuralMatch(D, FoundRecord, false)) continue; + if (!hasSameVisibilityContext(FoundRecord, D)) + continue; + if (IsStructuralMatch(D, FoundRecord)) { RecordDecl *FoundDef = FoundRecord->getDefinition(); if (D->isThisDeclarationADefinition() && FoundDef) { @@ -2651,7 +2632,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } // for if (!ConflictingDecls.empty() && SearchName) { - Name = Importer.HandleNameConflict(Name, DC, IDNS, + Name = Importer.HandleNameConflict(SearchName, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (!Name) @@ -2848,6 +2829,22 @@ ExpectedDecl ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { return ToEnumerator; } +Error ASTNodeImporter::ImportTemplateParameterLists(const DeclaratorDecl *FromD, + DeclaratorDecl *ToD) { + unsigned int Num = FromD->getNumTemplateParameterLists(); + if (Num == 0) + return Error::success(); + SmallVector<TemplateParameterList *, 2> ToTPLists(Num); + for (unsigned int I = 0; I < Num; ++I) + if (Expected<TemplateParameterList *> ToTPListOrErr = + import(FromD->getTemplateParameterList(I))) + ToTPLists[I] = *ToTPListOrErr; + else + return ToTPListOrErr.takeError(); + ToD->setTemplateParameterListsInfo(Importer.ToContext, ToTPLists); + return Error::success(); +} + Error ASTNodeImporter::ImportTemplateInformation( FunctionDecl *FromFD, FunctionDecl *ToFD) { switch (FromFD->getTemplatedKind()) { @@ -2894,6 +2891,9 @@ Error ASTNodeImporter::ImportTemplateInformation( if (!POIOrErr) return POIOrErr.takeError(); + if (Error Err = ImportTemplateParameterLists(FromFD, ToFD)) + return Err; + TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind(); ToFD->setFunctionTemplateSpecialization( std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr, @@ -2945,6 +2945,30 @@ ASTNodeImporter::FindFunctionTemplateSpecialization(FunctionDecl *FromFD) { return FoundSpec; } +Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD, + FunctionDecl *ToFD) { + if (Stmt *FromBody = FromFD->getBody()) { + if (ExpectedStmt ToBodyOrErr = import(FromBody)) + ToFD->setBody(*ToBodyOrErr); + else + return ToBodyOrErr.takeError(); + } + return Error::success(); +} + +template <typename T> +bool ASTNodeImporter::hasSameVisibilityContext(T *Found, T *From) { + if (From->hasExternalFormalLinkage()) + return Found->hasExternalFormalLinkage(); + if (Importer.GetFromTU(Found) != From->getTranslationUnitDecl()) + return false; + if (From->isInAnonymousNamespace()) + return Found->isInAnonymousNamespace(); + else + return !Found->isInAnonymousNamespace() && + !Found->hasExternalFormalLinkage(); +} + ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D); @@ -2968,7 +2992,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (ToD) return ToD; - const FunctionDecl *FoundByLookup = nullptr; + FunctionDecl *FoundByLookup = nullptr; FunctionTemplateDecl *FromFT = D->getDescribedFunctionTemplate(); // If this is a function template specialization, then try to find the same @@ -2982,8 +3006,8 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (!FoundFunctionOrErr) return FoundFunctionOrErr.takeError(); if (FunctionDecl *FoundFunction = *FoundFunctionOrErr) { - if (D->doesThisDeclarationHaveABody() && FoundFunction->hasBody()) - return Importer.MapImported(D, FoundFunction); + if (Decl *Def = FindAndMapDefinition(D, FoundFunction)) + return Def; FoundByLookup = FoundFunction; } } @@ -2998,33 +3022,27 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { continue; if (auto *FoundFunction = dyn_cast<FunctionDecl>(FoundDecl)) { - if (FoundFunction->hasExternalFormalLinkage() && - D->hasExternalFormalLinkage()) { - if (IsStructuralMatch(D, FoundFunction)) { - const FunctionDecl *Definition = nullptr; - if (D->doesThisDeclarationHaveABody() && - FoundFunction->hasBody(Definition)) { - return Importer.MapImported( - D, const_cast<FunctionDecl *>(Definition)); - } - FoundByLookup = FoundFunction; - break; - } + if (!hasSameVisibilityContext(FoundFunction, D)) + continue; - // FIXME: Check for overloading more carefully, e.g., by boosting - // Sema::IsOverload out to the AST library. + if (IsStructuralMatch(D, FoundFunction)) { + if (Decl *Def = FindAndMapDefinition(D, FoundFunction)) + return Def; + FoundByLookup = FoundFunction; + break; + } + // FIXME: Check for overloading more carefully, e.g., by boosting + // Sema::IsOverload out to the AST library. - // Function overloading is okay in C++. - if (Importer.getToContext().getLangOpts().CPlusPlus) - continue; + // Function overloading is okay in C++. + if (Importer.getToContext().getLangOpts().CPlusPlus) + continue; - // Complain about inconsistent function types. - Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent) + // Complain about inconsistent function types. + Importer.ToDiag(Loc, diag::warn_odr_function_type_inconsistent) << Name << D->getType() << FoundFunction->getType(); - Importer.ToDiag(FoundFunction->getLocation(), - diag::note_odr_value_here) + Importer.ToDiag(FoundFunction->getLocation(), diag::note_odr_value_here) << FoundFunction->getType(); - } } ConflictingDecls.push_back(FoundDecl); @@ -3039,6 +3057,25 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } } + // We do not allow more than one in-class declaration of a function. This is + // because AST clients like VTableBuilder asserts on this. VTableBuilder + // assumes there is only one in-class declaration. Building a redecl + // chain would result in more than one in-class declaration for + // overrides (even if they are part of the same redecl chain inside the + // derived class.) + if (FoundByLookup) { + if (isa<CXXMethodDecl>(FoundByLookup)) { + if (D->getLexicalDeclContext() == D->getDeclContext()) { + if (!D->doesThisDeclarationHaveABody()) + return Importer.MapImported(D, FoundByLookup); + else { + // Let's continue and build up the redecl chain in this case. + // FIXME Merge the functions into one decl. + } + } + } + } + DeclarationNameInfo NameInfo(Name, Loc); // Import additional name location/type info. if (Error Err = ImportDeclarationNameLoc(D->getNameInfo(), NameInfo)) @@ -3086,36 +3123,71 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Create the imported function. FunctionDecl *ToFunction = nullptr; if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) { + Expr *ExplicitExpr = nullptr; + if (FromConstructor->getExplicitSpecifier().getExpr()) { + auto Imp = importSeq(FromConstructor->getExplicitSpecifier().getExpr()); + if (!Imp) + return Imp.takeError(); + std::tie(ExplicitExpr) = *Imp; + } if (GetImportedOrCreateDecl<CXXConstructorDecl>( - ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), - ToInnerLocStart, NameInfo, T, TInfo, - FromConstructor->isExplicit(), - D->isInlineSpecified(), D->isImplicit(), D->isConstexpr())) + ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), + ToInnerLocStart, NameInfo, T, TInfo, + ExplicitSpecifier( + ExplicitExpr, + FromConstructor->getExplicitSpecifier().getKind()), + D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind())) return ToFunction; - } else if (isa<CXXDestructorDecl>(D)) { + } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) { + + auto Imp = + importSeq(const_cast<FunctionDecl *>(FromDtor->getOperatorDelete()), + FromDtor->getOperatorDeleteThisArg()); + + if (!Imp) + return Imp.takeError(); + + FunctionDecl *ToOperatorDelete; + Expr *ToThisArg; + std::tie(ToOperatorDelete, ToThisArg) = *Imp; + if (GetImportedOrCreateDecl<CXXDestructorDecl>( ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), D->isImplicit())) return ToFunction; + + CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction); + + ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg); } else if (CXXConversionDecl *FromConversion = dyn_cast<CXXConversionDecl>(D)) { + Expr *ExplicitExpr = nullptr; + if (FromConversion->getExplicitSpecifier().getExpr()) { + auto Imp = importSeq(FromConversion->getExplicitSpecifier().getExpr()); + if (!Imp) + return Imp.takeError(); + std::tie(ExplicitExpr) = *Imp; + } if (GetImportedOrCreateDecl<CXXConversionDecl>( ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), - FromConversion->isExplicit(), D->isConstexpr(), SourceLocation())) + ExplicitSpecifier(ExplicitExpr, + FromConversion->getExplicitSpecifier().getKind()), + D->getConstexprKind(), SourceLocation())) return ToFunction; } else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) { if (GetImportedOrCreateDecl<CXXMethodDecl>( ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(), - Method->isInlineSpecified(), D->isConstexpr(), SourceLocation())) + Method->isInlineSpecified(), D->getConstexprKind(), + SourceLocation())) return ToFunction; } else { - if (GetImportedOrCreateDecl(ToFunction, D, Importer.getToContext(), DC, - ToInnerLocStart, NameInfo, T, TInfo, - D->getStorageClass(), D->isInlineSpecified(), - D->hasWrittenPrototype(), D->isConstexpr())) + if (GetImportedOrCreateDecl( + ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, + NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(), + D->hasWrittenPrototype(), D->getConstexprKind())) return ToFunction; } @@ -3124,6 +3196,11 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { auto *Recent = const_cast<FunctionDecl *>( FoundByLookup->getMostRecentDecl()); ToFunction->setPreviousDecl(Recent); + // FIXME Probably we should merge exception specifications. E.g. In the + // "To" context the existing function may have exception specification with + // noexcept-unevaluated, while the newly imported function may have an + // evaluated noexcept. A call to adjustExceptionSpec() on the imported + // decl and its redeclarations may be required. } // Import Ctor initializers. @@ -3184,12 +3261,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } if (D->doesThisDeclarationHaveABody()) { - if (Stmt *FromBody = D->getBody()) { - if (ExpectedStmt ToBodyOrErr = import(FromBody)) - ToFunction->setBody(*ToBodyOrErr); - else - return ToBodyOrErr.takeError(); - } + Error Err = ImportFunctionDeclBody(D, ToFunction); + + if (Err) + return std::move(Err); } // FIXME: Other bits to merge? @@ -3292,7 +3367,7 @@ ExpectedDecl ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { } // FIXME: Why is this case not handled with calling HandleNameConflict? - Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) << FoundField->getType(); @@ -3363,7 +3438,7 @@ ExpectedDecl ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { continue; // FIXME: Why is this case not handled with calling HandleNameConflict? - Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) << FoundField->getType(); @@ -3394,9 +3469,6 @@ ExpectedDecl ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { // FIXME here we leak `NamedChain` which is allocated before return ToIndirectField; - for (const auto *Attr : D->attrs()) - ToIndirectField->addAttr(Importer.Import(Attr)); - ToIndirectField->setAccess(D->getAccess()); ToIndirectField->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToIndirectField); @@ -3451,7 +3523,7 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) { SmallVector<TemplateParameterList *, 1> ToTPLists(D->NumTPLists); auto **FromTPLists = D->getTrailingObjects<TemplateParameterList *>(); for (unsigned I = 0; I < D->NumTPLists; I++) { - if (auto ListOrErr = ImportTemplateParameterList(FromTPLists[I])) + if (auto ListOrErr = import(FromTPLists[I])) ToTPLists[I] = *ListOrErr; else return ListOrErr.takeError(); @@ -3497,7 +3569,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { return FoundIvar; } - Importer.ToDiag(Loc, diag::err_odr_ivar_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_ivar_type_inconsistent) << Name << D->getType() << FoundIvar->getType(); Importer.ToDiag(FoundIvar->getLocation(), diag::note_odr_value_here) << FoundIvar->getType(); @@ -3564,58 +3636,56 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { continue; if (auto *FoundVar = dyn_cast<VarDecl>(FoundDecl)) { - // We have found a variable that we may need to merge with. Check it. - if (FoundVar->hasExternalFormalLinkage() && - D->hasExternalFormalLinkage()) { - if (Importer.IsStructurallyEquivalent(D->getType(), - FoundVar->getType())) { - - // The VarDecl in the "From" context has a definition, but in the - // "To" context we already have a definition. - VarDecl *FoundDef = FoundVar->getDefinition(); - if (D->isThisDeclarationADefinition() && FoundDef) - // FIXME Check for ODR error if the two definitions have - // different initializers? - return Importer.MapImported(D, FoundDef); - - // The VarDecl in the "From" context has an initializer, but in the - // "To" context we already have an initializer. - const VarDecl *FoundDInit = nullptr; - if (D->getInit() && FoundVar->getAnyInitializer(FoundDInit)) - // FIXME Diagnose ODR error if the two initializers are different? - return Importer.MapImported(D, const_cast<VarDecl*>(FoundDInit)); + if (!hasSameVisibilityContext(FoundVar, D)) + continue; + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundVar->getType())) { + + // The VarDecl in the "From" context has a definition, but in the + // "To" context we already have a definition. + VarDecl *FoundDef = FoundVar->getDefinition(); + if (D->isThisDeclarationADefinition() && FoundDef) + // FIXME Check for ODR error if the two definitions have + // different initializers? + return Importer.MapImported(D, FoundDef); + + // The VarDecl in the "From" context has an initializer, but in the + // "To" context we already have an initializer. + const VarDecl *FoundDInit = nullptr; + if (D->getInit() && FoundVar->getAnyInitializer(FoundDInit)) + // FIXME Diagnose ODR error if the two initializers are different? + return Importer.MapImported(D, const_cast<VarDecl*>(FoundDInit)); + + FoundByLookup = FoundVar; + break; + } + + const ArrayType *FoundArray + = Importer.getToContext().getAsArrayType(FoundVar->getType()); + const ArrayType *TArray + = Importer.getToContext().getAsArrayType(D->getType()); + if (FoundArray && TArray) { + if (isa<IncompleteArrayType>(FoundArray) && + isa<ConstantArrayType>(TArray)) { + // Import the type. + if (auto TyOrErr = import(D->getType())) + FoundVar->setType(*TyOrErr); + else + return TyOrErr.takeError(); FoundByLookup = FoundVar; break; + } else if (isa<IncompleteArrayType>(TArray) && + isa<ConstantArrayType>(FoundArray)) { + FoundByLookup = FoundVar; + break; } - - const ArrayType *FoundArray - = Importer.getToContext().getAsArrayType(FoundVar->getType()); - const ArrayType *TArray - = Importer.getToContext().getAsArrayType(D->getType()); - if (FoundArray && TArray) { - if (isa<IncompleteArrayType>(FoundArray) && - isa<ConstantArrayType>(TArray)) { - // Import the type. - if (auto TyOrErr = import(D->getType())) - FoundVar->setType(*TyOrErr); - else - return TyOrErr.takeError(); - - FoundByLookup = FoundVar; - break; - } else if (isa<IncompleteArrayType>(TArray) && - isa<ConstantArrayType>(FoundArray)) { - FoundByLookup = FoundVar; - break; - } - } - - Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent) - << Name << D->getType() << FoundVar->getType(); - Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here) - << FoundVar->getType(); } + + Importer.ToDiag(Loc, diag::warn_odr_variable_type_inconsistent) + << Name << D->getType() << FoundVar->getType(); + Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here) + << FoundVar->getType(); } ConflictingDecls.push_back(FoundDecl); @@ -3777,7 +3847,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // Check return types. if (!Importer.IsStructurallyEquivalent(D->getReturnType(), FoundMethod->getReturnType())) { - Importer.ToDiag(Loc, diag::err_odr_objc_method_result_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_objc_method_result_type_inconsistent) << D->isInstanceMethod() << Name << D->getReturnType() << FoundMethod->getReturnType(); Importer.ToDiag(FoundMethod->getLocation(), @@ -3789,7 +3859,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // Check the number of parameters. if (D->param_size() != FoundMethod->param_size()) { - Importer.ToDiag(Loc, diag::err_odr_objc_method_num_params_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_objc_method_num_params_inconsistent) << D->isInstanceMethod() << Name << D->param_size() << FoundMethod->param_size(); Importer.ToDiag(FoundMethod->getLocation(), @@ -3806,7 +3876,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { if (!Importer.IsStructurallyEquivalent((*P)->getType(), (*FoundP)->getType())) { Importer.FromDiag((*P)->getLocation(), - diag::err_odr_objc_method_param_type_inconsistent) + diag::warn_odr_objc_method_param_type_inconsistent) << D->isInstanceMethod() << Name << (*P)->getType() << (*FoundP)->getType(); Importer.ToDiag((*FoundP)->getLocation(), diag::note_odr_value_here) @@ -3819,7 +3889,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // Check variadic/non-variadic. // Check the number of parameters. if (D->isVariadic() != FoundMethod->isVariadic()) { - Importer.ToDiag(Loc, diag::err_odr_objc_method_variadic_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_objc_method_variadic_inconsistent) << D->isInstanceMethod() << Name; Importer.ToDiag(FoundMethod->getLocation(), diag::note_odr_objc_method_here) @@ -4364,7 +4434,7 @@ Error ASTNodeImporter::ImportDefinition( if ((bool)FromSuper != (bool)ToSuper || (FromSuper && !declaresSameEntity(FromSuper, ToSuper))) { Importer.ToDiag(To->getLocation(), - diag::err_odr_objc_superclass_inconsistent) + diag::warn_odr_objc_superclass_inconsistent) << To->getDeclName(); if (ToSuper) Importer.ToDiag(To->getSuperClassLoc(), diag::note_odr_objc_superclass) @@ -4633,7 +4703,7 @@ ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { !declaresSameEntity(Super->getCanonicalDecl(), Impl->getSuperClass()))) { Importer.ToDiag(Impl->getLocation(), - diag::err_odr_objc_superclass_inconsistent) + diag::warn_odr_objc_superclass_inconsistent) << Iface->getDeclName(); // FIXME: It would be nice to have the location of the superclass // below. @@ -4681,7 +4751,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // Check property types. if (!Importer.IsStructurallyEquivalent(D->getType(), FoundProp->getType())) { - Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_objc_property_type_inconsistent) << Name << D->getType() << FoundProp->getType(); Importer.ToDiag(FoundProp->getLocation(), diag::note_odr_value_here) << FoundProp->getType(); @@ -4788,7 +4858,7 @@ ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { // vs. @dynamic). if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) { Importer.ToDiag(ToImpl->getLocation(), - diag::err_odr_objc_property_impl_kind_inconsistent) + diag::warn_odr_objc_property_impl_kind_inconsistent) << Property->getDeclName() << (ToImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); @@ -4804,7 +4874,7 @@ ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize && Ivar != ToImpl->getPropertyIvarDecl()) { Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(), - diag::err_odr_objc_synthesize_ivar_inconsistent) + diag::warn_odr_objc_synthesize_ivar_inconsistent) << Property->getDeclName() << ToImpl->getPropertyIvarDecl()->getDeclName() << Ivar->getDeclName(); @@ -4888,8 +4958,7 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { return LocationOrErr.takeError(); // Import template parameters. - auto TemplateParamsOrErr = ImportTemplateParameterList( - D->getTemplateParameters()); + auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); @@ -4905,31 +4974,20 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { return ToD; } -// Returns the definition for a (forward) declaration of a ClassTemplateDecl, if +// Returns the definition for a (forward) declaration of a TemplateDecl, if // it has any definition in the redecl chain. -static ClassTemplateDecl *getDefinition(ClassTemplateDecl *D) { - CXXRecordDecl *ToTemplatedDef = D->getTemplatedDecl()->getDefinition(); +template <typename T> static auto getTemplateDefinition(T *D) -> T * { + assert(D->getTemplatedDecl() && "Should be called on templates only"); + auto *ToTemplatedDef = D->getTemplatedDecl()->getDefinition(); if (!ToTemplatedDef) return nullptr; - ClassTemplateDecl *TemplateWithDef = - ToTemplatedDef->getDescribedClassTemplate(); - return TemplateWithDef; + auto *TemplateWithDef = ToTemplatedDef->getDescribedTemplate(); + return cast_or_null<T>(TemplateWithDef); } ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { bool IsFriend = D->getFriendObjectKind() != Decl::FOK_None; - // If this template has a definition in the translation unit we're coming - // from, but this particular declaration is not that definition, import the - // definition and map to that. - ClassTemplateDecl *Definition = getDefinition(D); - if (Definition && Definition != D && !IsFriend) { - if (ExpectedDecl ImportedDefOrErr = import(Definition)) - return Importer.MapImported(D, *ImportedDefOrErr); - else - return ImportedDefOrErr.takeError(); - } - // Import the major distinguishing characteristics of this class template. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -4956,7 +5014,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (FoundTemplate) { if (IsStructuralMatch(D, FoundTemplate)) { - ClassTemplateDecl *TemplateWithDef = getDefinition(FoundTemplate); + ClassTemplateDecl *TemplateWithDef = + getTemplateDefinition(FoundTemplate); if (D->isThisDeclarationADefinition() && TemplateWithDef) { return Importer.MapImported(D, TemplateWithDef); } @@ -4986,8 +5045,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { return std::move(Err); // Create the class template declaration itself. - auto TemplateParamsOrErr = ImportTemplateParameterList( - D->getTemplateParameters()); + auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); @@ -5019,6 +5077,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // and this time the lookup finds the previous fwd friend class template. // In this case we must set up the previous decl for the templated decl. if (!ToTemplated->getPreviousDecl()) { + assert(FoundByLookup->getTemplatedDecl() && + "Found decl must have its templated decl set"); CXXRecordDecl *PrevTemplated = FoundByLookup->getTemplatedDecl()->getMostRecentDecl(); if (ToTemplated != PrevTemplated) @@ -5041,17 +5101,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { - // If this record has a definition in the translation unit we're coming from, - // but this particular declaration is not that definition, import the - // definition and map to that. - TagDecl *Definition = D->getDefinition(); - if (Definition && Definition != D) { - if (ExpectedDecl ImportedDefOrErr = import(Definition)) - return Importer.MapImported(D, *ImportedDefOrErr); - else - return ImportedDefOrErr.takeError(); - } - ClassTemplateDecl *ClassTemplate; if (Error Err = importInto(ClassTemplate, D->getSpecializedTemplate())) return std::move(Err); @@ -5069,154 +5118,146 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Try to find an existing specialization with these template arguments. void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *D2 = nullptr; + ClassTemplateSpecializationDecl *PrevDecl = nullptr; ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>(D); if (PartialSpec) - D2 = ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos); + PrevDecl = + ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos); else - D2 = ClassTemplate->findSpecialization(TemplateArgs, InsertPos); - ClassTemplateSpecializationDecl * const PrevDecl = D2; - RecordDecl *FoundDef = D2 ? D2->getDefinition() : nullptr; - if (FoundDef) { - if (!D->isCompleteDefinition()) { - // The "From" translation unit only had a forward declaration; call it - // the same declaration. - // TODO Handle the redecl chain properly! - return Importer.MapImported(D, FoundDef); - } - - if (IsStructuralMatch(D, FoundDef)) { + PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos); + + if (PrevDecl) { + if (IsStructuralMatch(D, PrevDecl)) { + if (D->isThisDeclarationADefinition() && PrevDecl->getDefinition()) { + Importer.MapImported(D, PrevDecl->getDefinition()); + // Import those default field initializers which have been + // instantiated in the "From" context, but not in the "To" context. + for (auto *FromField : D->fields()) { + auto ToOrErr = import(FromField); + if (!ToOrErr) + return ToOrErr.takeError(); + } - Importer.MapImported(D, FoundDef); + // Import those methods which have been instantiated in the + // "From" context, but not in the "To" context. + for (CXXMethodDecl *FromM : D->methods()) { + auto ToOrErr = import(FromM); + if (!ToOrErr) + return ToOrErr.takeError(); + } - // Import those those default field initializers which have been - // instantiated in the "From" context, but not in the "To" context. - for (auto *FromField : D->fields()) { - auto ToOrErr = import(FromField); - if (!ToOrErr) - // FIXME: return the error? - consumeError(ToOrErr.takeError()); + // TODO Import instantiated default arguments. + // TODO Import instantiated exception specifications. + // + // Generally, ASTCommon.h/DeclUpdateKind enum gives a very good hint + // what else could be fused during an AST merge. + return PrevDecl; } + } else { // ODR violation. + // FIXME HandleNameConflict + return make_error<ImportError>(ImportError::NameConflict); + } + } - // Import those methods which have been instantiated in the - // "From" context, but not in the "To" context. - for (CXXMethodDecl *FromM : D->methods()) { - auto ToOrErr = import(FromM); - if (!ToOrErr) - // FIXME: return the error? - consumeError(ToOrErr.takeError()); - } + // Import the location of this declaration. + ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); + if (!BeginLocOrErr) + return BeginLocOrErr.takeError(); + ExpectedSLoc IdLocOrErr = import(D->getLocation()); + if (!IdLocOrErr) + return IdLocOrErr.takeError(); - // TODO Import instantiated default arguments. - // TODO Import instantiated exception specifications. - // - // Generally, ASTCommon.h/DeclUpdateKind enum gives a very good hint what - // else could be fused during an AST merge. + // Create the specialization. + ClassTemplateSpecializationDecl *D2 = nullptr; + if (PartialSpec) { + // Import TemplateArgumentListInfo. + TemplateArgumentListInfo ToTAInfo; + const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); + if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo)) + return std::move(Err); - return FoundDef; - } - } else { // We either couldn't find any previous specialization in the "To" - // context, or we found one but without definition. Let's create a - // new specialization and register that at the class template. + QualType CanonInjType; + if (Error Err = importInto( + CanonInjType, PartialSpec->getInjectedSpecializationType())) + return std::move(Err); + CanonInjType = CanonInjType.getCanonicalType(); + + auto ToTPListOrErr = import(PartialSpec->getTemplateParameters()); + if (!ToTPListOrErr) + return ToTPListOrErr.takeError(); + + if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>( + D2, D, Importer.getToContext(), D->getTagKind(), DC, + *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate, + llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), + ToTAInfo, CanonInjType, + cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl))) + return D2; - // Import the location of this declaration. - ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); - if (!BeginLocOrErr) - return BeginLocOrErr.takeError(); - ExpectedSLoc IdLocOrErr = import(D->getLocation()); - if (!IdLocOrErr) - return IdLocOrErr.takeError(); - - if (PartialSpec) { - // Import TemplateArgumentListInfo. - TemplateArgumentListInfo ToTAInfo; - const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); - if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo)) - return std::move(Err); + // Update InsertPos, because preceding import calls may have invalidated + // it by adding new specializations. + if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos)) + // Add this partial specialization to the class template. + ClassTemplate->AddPartialSpecialization( + cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos); - QualType CanonInjType; - if (Error Err = importInto( - CanonInjType, PartialSpec->getInjectedSpecializationType())) - return std::move(Err); - CanonInjType = CanonInjType.getCanonicalType(); + } else { // Not a partial specialization. + if (GetImportedOrCreateDecl( + D2, D, Importer.getToContext(), D->getTagKind(), DC, + *BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs, + PrevDecl)) + return D2; - auto ToTPListOrErr = ImportTemplateParameterList( - PartialSpec->getTemplateParameters()); - if (!ToTPListOrErr) - return ToTPListOrErr.takeError(); + // Update InsertPos, because preceding import calls may have invalidated + // it by adding new specializations. + if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos)) + // Add this specialization to the class template. + ClassTemplate->AddSpecialization(D2, InsertPos); + } - if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>( - D2, D, Importer.getToContext(), D->getTagKind(), DC, - *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate, - llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), - ToTAInfo, CanonInjType, - cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl))) - return D2; + D2->setSpecializationKind(D->getSpecializationKind()); - // Update InsertPos, because preceding import calls may have invalidated - // it by adding new specializations. - if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos)) - // Add this partial specialization to the class template. - ClassTemplate->AddPartialSpecialization( - cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos); + // Set the context of this specialization/instantiation. + D2->setLexicalDeclContext(LexicalDC); - } else { // Not a partial specialization. - if (GetImportedOrCreateDecl( - D2, D, Importer.getToContext(), D->getTagKind(), DC, - *BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs, - PrevDecl)) - return D2; + // Add to the DC only if it was an explicit specialization/instantiation. + if (D2->isExplicitInstantiationOrSpecialization()) { + LexicalDC->addDeclInternal(D2); + } - // Update InsertPos, because preceding import calls may have invalidated - // it by adding new specializations. - if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos)) - // Add this specialization to the class template. - ClassTemplate->AddSpecialization(D2, InsertPos); - } + // Import the qualifier, if any. + if (auto LocOrErr = import(D->getQualifierLoc())) + D2->setQualifierInfo(*LocOrErr); + else + return LocOrErr.takeError(); - D2->setSpecializationKind(D->getSpecializationKind()); + if (auto *TSI = D->getTypeAsWritten()) { + if (auto TInfoOrErr = import(TSI)) + D2->setTypeAsWritten(*TInfoOrErr); + else + return TInfoOrErr.takeError(); - // Import the qualifier, if any. - if (auto LocOrErr = import(D->getQualifierLoc())) - D2->setQualifierInfo(*LocOrErr); + if (auto LocOrErr = import(D->getTemplateKeywordLoc())) + D2->setTemplateKeywordLoc(*LocOrErr); else return LocOrErr.takeError(); - if (auto *TSI = D->getTypeAsWritten()) { - if (auto TInfoOrErr = import(TSI)) - D2->setTypeAsWritten(*TInfoOrErr); - else - return TInfoOrErr.takeError(); - - if (auto LocOrErr = import(D->getTemplateKeywordLoc())) - D2->setTemplateKeywordLoc(*LocOrErr); - else - return LocOrErr.takeError(); - - if (auto LocOrErr = import(D->getExternLoc())) - D2->setExternLoc(*LocOrErr); - else - return LocOrErr.takeError(); - } - - if (D->getPointOfInstantiation().isValid()) { - if (auto POIOrErr = import(D->getPointOfInstantiation())) - D2->setPointOfInstantiation(*POIOrErr); - else - return POIOrErr.takeError(); - } + if (auto LocOrErr = import(D->getExternLoc())) + D2->setExternLoc(*LocOrErr); + else + return LocOrErr.takeError(); + } - D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind()); + if (D->getPointOfInstantiation().isValid()) { + if (auto POIOrErr = import(D->getPointOfInstantiation())) + D2->setPointOfInstantiation(*POIOrErr); + else + return POIOrErr.takeError(); + } - // Set the context of this specialization/instantiation. - D2->setLexicalDeclContext(LexicalDC); + D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind()); - // Add to the DC only if it was an explicit specialization/instantiation. - if (D2->isExplicitInstantiationOrSpecialization()) { - LexicalDC->addDeclInternal(D2); - } - } if (D->isCompleteDefinition()) if (Error Err = ImportDefinition(D, D2)) return std::move(Err); @@ -5296,8 +5337,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { return std::move(Err); // Create the variable template declaration itself. - auto TemplateParamsOrErr = ImportTemplateParameterList( - D->getTemplateParameters()); + auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); @@ -5333,7 +5373,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( return ImportedDefOrErr.takeError(); } - VarTemplateDecl *VarTemplate; + VarTemplateDecl *VarTemplate = nullptr; if (Error Err = importInto(VarTemplate, D->getSpecializedTemplate())) return std::move(Err); @@ -5402,8 +5442,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( *FromTAArgsAsWritten, ArgInfos)) return std::move(Err); - auto ToTPListOrErr = ImportTemplateParameterList( - FromPartial->getTemplateParameters()); + auto ToTPListOrErr = import(FromPartial->getTemplateParameters()); if (!ToTPListOrErr) return ToTPListOrErr.takeError(); @@ -5481,32 +5520,37 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ToD) return ToD; + const FunctionTemplateDecl *FoundByLookup = nullptr; + // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. + // FIXME Split this into a separate function. if (!LexicalDC->isFunctionOrMethod()) { - unsigned IDNS = Decl::IDNS_Ordinary; + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - if (auto *FoundFunction = - dyn_cast<FunctionTemplateDecl>(FoundDecl)) { - if (FoundFunction->hasExternalFormalLinkage() && + if (auto *FoundTemplate = dyn_cast<FunctionTemplateDecl>(FoundDecl)) { + if (FoundTemplate->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { - if (IsStructuralMatch(D, FoundFunction)) { - Importer.MapImported(D, FoundFunction); - // FIXME: Actually try to merge the body and other attributes. - return FoundFunction; + if (IsStructuralMatch(D, FoundTemplate)) { + FunctionTemplateDecl *TemplateWithDef = + getTemplateDefinition(FoundTemplate); + if (D->isThisDeclarationADefinition() && TemplateWithDef) { + return Importer.MapImported(D, TemplateWithDef); + } + FoundByLookup = FoundTemplate; + break; } + // TODO: handle conflicting names } } - // TODO: handle conflicting names } } - auto ParamsOrErr = ImportTemplateParameterList( - D->getTemplateParameters()); + auto ParamsOrErr = import(D->getTemplateParameters()); if (!ParamsOrErr) return ParamsOrErr.takeError(); @@ -5520,10 +5564,25 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { return ToFunc; TemplatedFD->setDescribedFunctionTemplate(ToFunc); + ToFunc->setAccess(D->getAccess()); ToFunc->setLexicalDeclContext(LexicalDC); - LexicalDC->addDeclInternal(ToFunc); + + if (FoundByLookup) { + auto *Recent = + const_cast<FunctionTemplateDecl *>(FoundByLookup->getMostRecentDecl()); + if (!TemplatedFD->getPreviousDecl()) { + assert(FoundByLookup->getTemplatedDecl() && + "Found decl must have its templated decl set"); + auto *PrevTemplated = + FoundByLookup->getTemplatedDecl()->getMostRecentDecl(); + if (TemplatedFD != PrevTemplated) + TemplatedFD->setPreviousDecl(PrevTemplated); + } + ToFunc->setPreviousDecl(Recent); + } + return ToFunc; } @@ -5539,6 +5598,8 @@ ExpectedStmt ASTNodeImporter::VisitStmt(Stmt *S) { ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { + if (Importer.returnWithErrorInTest()) + return make_error<ImportError>(ImportError::UnsupportedConstruct); SmallVector<IdentifierInfo *, 4> Names; for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) { IdentifierInfo *ToII = Importer.Import(S->getOutputIdentifier(I)); @@ -5578,12 +5639,17 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { return InputOrErr.takeError(); } - SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs()); + SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs() + + S->getNumLabels()); if (Error Err = ImportContainerChecked(S->outputs(), Exprs)) return std::move(Err); + if (Error Err = + ImportArrayChecked(S->inputs(), Exprs.begin() + S->getNumOutputs())) + return std::move(Err); + if (Error Err = ImportArrayChecked( - S->inputs(), Exprs.begin() + S->getNumOutputs())) + S->labels(), Exprs.begin() + S->getNumOutputs() + S->getNumInputs())) return std::move(Err); ExpectedSLoc AsmLocOrErr = import(S->getAsmLoc()); @@ -5609,6 +5675,7 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { *AsmStrOrErr, S->getNumClobbers(), Clobbers.data(), + S->getNumLabels(), *RParenLocOrErr); } @@ -6079,6 +6146,33 @@ ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) { E->isMicrosoftABI()); } +ExpectedStmt ASTNodeImporter::VisitChooseExpr(ChooseExpr *E) { + auto Imp = importSeq(E->getCond(), E->getLHS(), E->getRHS(), + E->getBuiltinLoc(), E->getRParenLoc(), E->getType()); + if (!Imp) + return Imp.takeError(); + + Expr *ToCond; + Expr *ToLHS; + Expr *ToRHS; + SourceLocation ToBuiltinLoc, ToRParenLoc; + QualType ToType; + std::tie(ToCond, ToLHS, ToRHS, ToBuiltinLoc, ToRParenLoc, ToType) = *Imp; + + ExprValueKind VK = E->getValueKind(); + ExprObjectKind OK = E->getObjectKind(); + + bool TypeDependent = ToCond->isTypeDependent(); + bool ValueDependent = ToCond->isValueDependent(); + + // The value of CondIsTrue only matters if the value is not + // condition-dependent. + bool CondIsTrue = !E->isConditionDependent() && E->isConditionTrue(); + + return new (Importer.getToContext()) + ChooseExpr(ToBuiltinLoc, ToCond, ToLHS, ToRHS, ToType, VK, OK, + ToRParenLoc, CondIsTrue, TypeDependent, ValueDependent); +} ExpectedStmt ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) { ExpectedType TypeOrErr = import(E->getType()); @@ -6141,7 +6235,7 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { auto *ToE = DeclRefExpr::Create( Importer.getToContext(), ToQualifierLoc, ToTemplateKeywordLoc, ToDecl, E->refersToEnclosingVariableOrCapture(), ToLocation, ToType, - E->getValueKind(), ToFoundD, ToResInfo); + E->getValueKind(), ToFoundD, ToResInfo, E->isNonOdrUse()); if (E->hadMultipleCandidates()) ToE->setHadMultipleCandidates(true); return ToE; @@ -6327,6 +6421,13 @@ ExpectedStmt ASTNodeImporter::VisitConstantExpr(ConstantExpr *E) { Expr *ToSubExpr; std::tie(ToSubExpr) = *Imp; + // TODO : Handle APValue::ValueKind that require importing. + APValue::ValueKind Kind = E->getResultAPValueKind(); + if (Kind == APValue::Int || Kind == APValue::Float || + Kind == APValue::FixedPoint || Kind == APValue::ComplexFloat || + Kind == APValue::ComplexInt) + return ConstantExpr::Create(Importer.getToContext(), ToSubExpr, + E->getAPValueResult()); return ConstantExpr::Create(Importer.getToContext(), ToSubExpr); } @@ -6763,8 +6864,12 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { if (!ToParamOrErr) return ToParamOrErr.takeError(); + auto UsedContextOrErr = Importer.ImportContext(E->getUsedContext()); + if (!UsedContextOrErr) + return UsedContextOrErr.takeError(); + return CXXDefaultArgExpr::Create( - Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr); + Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr, *UsedContextOrErr); } ExpectedStmt @@ -6898,7 +7003,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *E) { FunctionDecl *ToOperatorNew, *ToOperatorDelete; SourceRange ToTypeIdParens, ToSourceRange, ToDirectInitRange; - Expr *ToArraySize, *ToInitializer; + Optional<Expr *> ToArraySize; + Expr *ToInitializer; QualType ToType; TypeSourceInfo *ToAllocatedTypeSourceInfo; std::tie( @@ -7051,15 +7157,20 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) { DeclarationNameInfo ToMemberNameInfo(ToName, ToLoc); + TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { - // FIXME: handle template arguments - return make_error<ImportError>(ImportError::UnsupportedConstruct); + if (Error Err = + ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments(), ToTAInfo)) + return std::move(Err); + ResInfo = &ToTAInfo; } - return MemberExpr::Create( - Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc, - ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToFoundDecl, - ToMemberNameInfo, nullptr, ToType, E->getValueKind(), E->getObjectKind()); + return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(), + ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, + ToMemberDecl, ToFoundDecl, ToMemberNameInfo, + ResInfo, ToType, E->getValueKind(), + E->getObjectKind(), E->isNonOdrUse()); } ExpectedStmt @@ -7334,23 +7445,10 @@ ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) { return ToClassOrErr.takeError(); CXXRecordDecl *ToClass = *ToClassOrErr; - // NOTE: lambda classes are created with BeingDefined flag set up. - // It means that ImportDefinition doesn't work for them and we should fill it - // manually. - if (ToClass->isBeingDefined()) { - for (auto FromField : FromClass->fields()) { - auto ToFieldOrErr = import(FromField); - if (!ToFieldOrErr) - return ToFieldOrErr.takeError(); - } - } - auto ToCallOpOrErr = import(E->getCallOperator()); if (!ToCallOpOrErr) return ToCallOpOrErr.takeError(); - ToClass->completeDefinition(); - SmallVector<LambdaCapture, 8> ToCaptures; ToCaptures.reserve(E->capture_size()); for (const auto &FromCapture : E->captures()) { @@ -7486,8 +7584,12 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { if (!ToFieldOrErr) return ToFieldOrErr.takeError(); + auto UsedContextOrErr = Importer.ImportContext(E->getUsedContext()); + if (!UsedContextOrErr) + return UsedContextOrErr.takeError(); + return CXXDefaultInitExpr::Create( - Importer.getToContext(), *ToBeginLocOrErr, *ToFieldOrErr); + Importer.getToContext(), *ToBeginLocOrErr, *ToFieldOrErr, *UsedContextOrErr); } ExpectedStmt ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { @@ -7613,24 +7715,22 @@ void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod, ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport, - ASTImporterLookupTable *LookupTable) - : LookupTable(LookupTable), ToContext(ToContext), FromContext(FromContext), + std::shared_ptr<ASTImporterSharedState> SharedState) + : SharedState(SharedState), ToContext(ToContext), FromContext(FromContext), ToFileManager(ToFileManager), FromFileManager(FromFileManager), Minimal(MinimalImport) { + // Create a default state without the lookup table: LLDB case. + if (!SharedState) { + this->SharedState = std::make_shared<ASTImporterSharedState>(); + } + ImportedDecls[FromContext.getTranslationUnitDecl()] = ToContext.getTranslationUnitDecl(); } ASTImporter::~ASTImporter() = default; -Expected<QualType> ASTImporter::Import_New(QualType FromT) { - QualType ToT = Import(FromT); - if (ToT.isNull() && !FromT.isNull()) - return make_error<ImportError>(); - return ToT; -} - Optional<unsigned> ASTImporter::getFieldIndex(Decl *F) { assert(F && (isa<FieldDecl>(*F) || isa<IndirectFieldDecl>(*F)) && "Try to get field index for non-field."); @@ -7663,28 +7763,46 @@ ASTImporter::findDeclsInToCtx(DeclContext *DC, DeclarationName Name) { // then the enum constant 'A' and the variable 'A' violates ODR. // We can diagnose this only if we search in the redecl context. DeclContext *ReDC = DC->getRedeclContext(); - if (LookupTable) { + if (SharedState->getLookupTable()) { ASTImporterLookupTable::LookupResult LookupResult = - LookupTable->lookup(ReDC, Name); + SharedState->getLookupTable()->lookup(ReDC, Name); return FoundDeclsTy(LookupResult.begin(), LookupResult.end()); } else { - // FIXME Can we remove this kind of lookup? - // Or lldb really needs this C/C++ lookup? - FoundDeclsTy Result; - ReDC->localUncachedLookup(Name, Result); + DeclContext::lookup_result NoloadLookupResult = ReDC->noload_lookup(Name); + FoundDeclsTy Result(NoloadLookupResult.begin(), NoloadLookupResult.end()); + // We must search by the slow case of localUncachedLookup because that is + // working even if there is no LookupPtr for the DC. We could use + // DC::buildLookup() to create the LookupPtr, but that would load external + // decls again, we must avoid that case. + // Also, even if we had the LookupPtr, we must find Decls which are not + // in the LookupPtr, so we need the slow case. + // These cases are handled in ASTImporterLookupTable, but we cannot use + // that with LLDB since that traverses through the AST which initiates the + // load of external decls again via DC::decls(). And again, we must avoid + // loading external decls during the import. + if (Result.empty()) + ReDC->localUncachedLookup(Name, Result); return Result; } } void ASTImporter::AddToLookupTable(Decl *ToD) { - if (LookupTable) - if (auto *ToND = dyn_cast<NamedDecl>(ToD)) - LookupTable->add(ToND); + SharedState->addDeclToLookup(ToD); +} + +Expected<Decl *> ASTImporter::ImportImpl(Decl *FromD) { + // Import the decl using ASTNodeImporter. + ASTNodeImporter Importer(*this); + return Importer.Visit(FromD); +} + +void ASTImporter::RegisterImportedDecl(Decl *FromD, Decl *ToD) { + MapImported(FromD, ToD); } -QualType ASTImporter::Import(QualType FromT) { +Expected<QualType> ASTImporter::Import(QualType FromT) { if (FromT.isNull()) - return {}; + return QualType{}; const Type *FromTy = FromT.getTypePtr(); @@ -7697,10 +7815,8 @@ QualType ASTImporter::Import(QualType FromT) { // Import the type ASTNodeImporter Importer(*this); ExpectedType ToTOrErr = Importer.Visit(FromTy); - if (!ToTOrErr) { - llvm::consumeError(ToTOrErr.takeError()); - return {}; - } + if (!ToTOrErr) + return ToTOrErr.takeError(); // Record the imported type. ImportedTypes[FromTy] = (*ToTOrErr).getTypePtr(); @@ -7708,33 +7824,29 @@ QualType ASTImporter::Import(QualType FromT) { return ToContext.getQualifiedType(*ToTOrErr, FromT.getLocalQualifiers()); } -Expected<TypeSourceInfo *> ASTImporter::Import_New(TypeSourceInfo *FromTSI) { - TypeSourceInfo *ToTSI = Import(FromTSI); - if (!ToTSI && FromTSI) - return llvm::make_error<ImportError>(); - return ToTSI; -} -TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { +Expected<TypeSourceInfo *> ASTImporter::Import(TypeSourceInfo *FromTSI) { if (!FromTSI) return FromTSI; // FIXME: For now we just create a "trivial" type source info based // on the type and a single location. Implement a real version of this. - QualType T = Import(FromTSI->getType()); - if (T.isNull()) - return nullptr; + ExpectedType TOrErr = Import(FromTSI->getType()); + if (!TOrErr) + return TOrErr.takeError(); + ExpectedSLoc BeginLocOrErr = Import(FromTSI->getTypeLoc().getBeginLoc()); + if (!BeginLocOrErr) + return BeginLocOrErr.takeError(); - return ToContext.getTrivialTypeSourceInfo( - T, Import(FromTSI->getTypeLoc().getBeginLoc())); + return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr); } -Expected<Attr *> ASTImporter::Import_New(const Attr *FromAttr) { - return Import(FromAttr); -} -Attr *ASTImporter::Import(const Attr *FromAttr) { +Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) { Attr *ToAttr = FromAttr->clone(ToContext); - // NOTE: Import of SourceRange may fail. - ToAttr->setRange(Import(FromAttr->getRange())); + if (auto ToRangeOrErr = Import(FromAttr->getRange())) + ToAttr->setRange(*ToRangeOrErr); + else + return ToRangeOrErr.takeError(); + return ToAttr; } @@ -7746,53 +7858,147 @@ Decl *ASTImporter::GetAlreadyImportedOrNull(const Decl *FromD) const { return nullptr; } -Expected<Decl *> ASTImporter::Import_New(Decl *FromD) { - Decl *ToD = Import(FromD); - if (!ToD && FromD) - return llvm::make_error<ImportError>(); - return ToD; +TranslationUnitDecl *ASTImporter::GetFromTU(Decl *ToD) { + auto FromDPos = ImportedFromDecls.find(ToD); + if (FromDPos == ImportedFromDecls.end()) + return nullptr; + return FromDPos->second->getTranslationUnitDecl(); } -Decl *ASTImporter::Import(Decl *FromD) { + +Expected<Decl *> ASTImporter::Import(Decl *FromD) { if (!FromD) return nullptr; - ASTNodeImporter Importer(*this); + // Push FromD to the stack, and remove that when we return. + ImportPath.push(FromD); + auto ImportPathBuilder = + llvm::make_scope_exit([this]() { ImportPath.pop(); }); + + // Check whether there was a previous failed import. + // If yes return the existing error. + if (auto Error = getImportDeclErrorIfAny(FromD)) + return make_error<ImportError>(*Error); // Check whether we've already imported this declaration. Decl *ToD = GetAlreadyImportedOrNull(FromD); if (ToD) { + // Already imported (possibly from another TU) and with an error. + if (auto Error = SharedState->getImportDeclErrorIfAny(ToD)) { + setImportDeclError(FromD, *Error); + return make_error<ImportError>(*Error); + } + // If FromD has some updated flags after last import, apply it updateFlags(FromD, ToD); + // If we encounter a cycle during an import then we save the relevant part + // of the import path associated to the Decl. + if (ImportPath.hasCycleAtBack()) + SavedImportPaths[FromD].push_back(ImportPath.copyCycleAtBack()); return ToD; } - // Import the type. - ExpectedDecl ToDOrErr = Importer.Visit(FromD); + // Import the declaration. + ExpectedDecl ToDOrErr = ImportImpl(FromD); if (!ToDOrErr) { - llvm::consumeError(ToDOrErr.takeError()); - return nullptr; + // Failed to import. + + auto Pos = ImportedDecls.find(FromD); + if (Pos != ImportedDecls.end()) { + // Import failed after the object was created. + // Remove all references to it. + auto *ToD = Pos->second; + ImportedDecls.erase(Pos); + + // ImportedDecls and ImportedFromDecls are not symmetric. It may happen + // (e.g. with namespaces) that several decls from the 'from' context are + // mapped to the same decl in the 'to' context. If we removed entries + // from the LookupTable here then we may end up removing them multiple + // times. + + // The Lookuptable contains decls only which are in the 'to' context. + // Remove from the Lookuptable only if it is *imported* into the 'to' + // context (and do not remove it if it was added during the initial + // traverse of the 'to' context). + auto PosF = ImportedFromDecls.find(ToD); + if (PosF != ImportedFromDecls.end()) { + SharedState->removeDeclFromLookup(ToD); + ImportedFromDecls.erase(PosF); + } + + // FIXME: AST may contain remaining references to the failed object. + // However, the ImportDeclErrors in the shared state contains all the + // failed objects together with their error. + } + + // Error encountered for the first time. + // After takeError the error is not usable any more in ToDOrErr. + // Get a copy of the error object (any more simple solution for this?). + ImportError ErrOut; + handleAllErrors(ToDOrErr.takeError(), + [&ErrOut](const ImportError &E) { ErrOut = E; }); + setImportDeclError(FromD, ErrOut); + // Set the error for the mapped to Decl, which is in the "to" context. + if (Pos != ImportedDecls.end()) + SharedState->setImportDeclError(Pos->second, ErrOut); + + // Set the error for all nodes which have been created before we + // recognized the error. + for (const auto &Path : SavedImportPaths[FromD]) + for (Decl *FromDi : Path) { + setImportDeclError(FromDi, ErrOut); + //FIXME Should we remove these Decls from ImportedDecls? + // Set the error for the mapped to Decl, which is in the "to" context. + auto Ii = ImportedDecls.find(FromDi); + if (Ii != ImportedDecls.end()) + SharedState->setImportDeclError(Ii->second, ErrOut); + // FIXME Should we remove these Decls from the LookupTable, + // and from ImportedFromDecls? + } + SavedImportPaths[FromD].clear(); + + // Do not return ToDOrErr, error was taken out of it. + return make_error<ImportError>(ErrOut); } + ToD = *ToDOrErr; - // Once the decl is connected to the existing declarations, i.e. when the - // redecl chain is properly set then we populate the lookup again. - // This way the primary context will be able to find all decls. - AddToLookupTable(ToD); + // FIXME: Handle the "already imported with error" case. We can get here + // nullptr only if GetImportedOrCreateDecl returned nullptr (after a + // previously failed create was requested). + // Later GetImportedOrCreateDecl can be updated to return the error. + if (!ToD) { + auto Err = getImportDeclErrorIfAny(FromD); + assert(Err); + return make_error<ImportError>(*Err); + } + + // We could import from the current TU without error. But previously we + // already had imported a Decl as `ToD` from another TU (with another + // ASTImporter object) and with an error. + if (auto Error = SharedState->getImportDeclErrorIfAny(ToD)) { + setImportDeclError(FromD, *Error); + return make_error<ImportError>(*Error); + } + + // Make sure that ImportImpl registered the imported decl. + assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?"); // Notify subclasses. Imported(FromD, ToD); updateFlags(FromD, ToD); - return ToD; + SavedImportPaths[FromD].clear(); + return ToDOrErr; } Expected<DeclContext *> ASTImporter::ImportContext(DeclContext *FromDC) { if (!FromDC) return FromDC; - auto *ToDC = cast_or_null<DeclContext>(Import(cast<Decl>(FromDC))); - if (!ToDC) - return nullptr; + ExpectedDecl ToDCOrErr = Import(cast<Decl>(FromDC)); + if (!ToDCOrErr) + return ToDCOrErr.takeError(); + auto *ToDC = cast<DeclContext>(*ToDCOrErr); // When we're using a record/enum/Objective-C class/protocol as a context, we // need it to have a definition. @@ -7845,30 +8051,18 @@ Expected<DeclContext *> ASTImporter::ImportContext(DeclContext *FromDC) { return ToDC; } -Expected<Expr *> ASTImporter::Import_New(Expr *FromE) { - Expr *ToE = Import(FromE); - if (!ToE && FromE) - return llvm::make_error<ImportError>(); - return ToE; -} -Expr *ASTImporter::Import(Expr *FromE) { - if (!FromE) - return nullptr; - - return cast_or_null<Expr>(Import(cast<Stmt>(FromE))); +Expected<Expr *> ASTImporter::Import(Expr *FromE) { + if (ExpectedStmt ToSOrErr = Import(cast_or_null<Stmt>(FromE))) + return cast_or_null<Expr>(*ToSOrErr); + else + return ToSOrErr.takeError(); } -Expected<Stmt *> ASTImporter::Import_New(Stmt *FromS) { - Stmt *ToS = Import(FromS); - if (!ToS && FromS) - return llvm::make_error<ImportError>(); - return ToS; -} -Stmt *ASTImporter::Import(Stmt *FromS) { +Expected<Stmt *> ASTImporter::Import(Stmt *FromS) { if (!FromS) return nullptr; - // Check whether we've already imported this declaration. + // Check whether we've already imported this statement. llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS); if (Pos != ImportedStmts.end()) return Pos->second; @@ -7876,10 +8070,8 @@ Stmt *ASTImporter::Import(Stmt *FromS) { // Import the statement. ASTNodeImporter Importer(*this); ExpectedStmt ToSOrErr = Importer.Visit(FromS); - if (!ToSOrErr) { - llvm::consumeError(ToSOrErr.takeError()); - return nullptr; - } + if (!ToSOrErr) + return ToSOrErr; if (auto *ToE = dyn_cast<Expr>(*ToSOrErr)) { auto *FromE = cast<Expr>(FromS); @@ -7894,77 +8086,68 @@ Stmt *ASTImporter::Import(Stmt *FromS) { FromE->containsUnexpandedParameterPack()); } - // Record the imported declaration. + // Record the imported statement object. ImportedStmts[FromS] = *ToSOrErr; - return *ToSOrErr; + return ToSOrErr; } Expected<NestedNameSpecifier *> -ASTImporter::Import_New(NestedNameSpecifier *FromNNS) { - NestedNameSpecifier *ToNNS = Import(FromNNS); - if (!ToNNS && FromNNS) - return llvm::make_error<ImportError>(); - return ToNNS; -} -NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { +ASTImporter::Import(NestedNameSpecifier *FromNNS) { if (!FromNNS) return nullptr; - NestedNameSpecifier *prefix = Import(FromNNS->getPrefix()); + NestedNameSpecifier *Prefix = nullptr; + if (Error Err = importInto(Prefix, FromNNS->getPrefix())) + return std::move(Err); switch (FromNNS->getKind()) { case NestedNameSpecifier::Identifier: - if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) { - return NestedNameSpecifier::Create(ToContext, prefix, II); - } - return nullptr; + assert(FromNNS->getAsIdentifier() && "NNS should contain identifier."); + return NestedNameSpecifier::Create(ToContext, Prefix, + Import(FromNNS->getAsIdentifier())); case NestedNameSpecifier::Namespace: - if (auto *NS = - cast_or_null<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) { - return NestedNameSpecifier::Create(ToContext, prefix, NS); - } - return nullptr; + if (ExpectedDecl NSOrErr = Import(FromNNS->getAsNamespace())) { + return NestedNameSpecifier::Create(ToContext, Prefix, + cast<NamespaceDecl>(*NSOrErr)); + } else + return NSOrErr.takeError(); case NestedNameSpecifier::NamespaceAlias: - if (auto *NSAD = - cast_or_null<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) { - return NestedNameSpecifier::Create(ToContext, prefix, NSAD); - } - return nullptr; + if (ExpectedDecl NSADOrErr = Import(FromNNS->getAsNamespaceAlias())) + return NestedNameSpecifier::Create(ToContext, Prefix, + cast<NamespaceAliasDecl>(*NSADOrErr)); + else + return NSADOrErr.takeError(); case NestedNameSpecifier::Global: return NestedNameSpecifier::GlobalSpecifier(ToContext); case NestedNameSpecifier::Super: - if (auto *RD = - cast_or_null<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) { - return NestedNameSpecifier::SuperSpecifier(ToContext, RD); - } - return nullptr; + if (ExpectedDecl RDOrErr = Import(FromNNS->getAsRecordDecl())) + return NestedNameSpecifier::SuperSpecifier(ToContext, + cast<CXXRecordDecl>(*RDOrErr)); + else + return RDOrErr.takeError(); case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: { - QualType T = Import(QualType(FromNNS->getAsType(), 0u)); - if (!T.isNull()) { - bool bTemplate = FromNNS->getKind() == - NestedNameSpecifier::TypeSpecWithTemplate; - return NestedNameSpecifier::Create(ToContext, prefix, - bTemplate, T.getTypePtr()); - } + case NestedNameSpecifier::TypeSpecWithTemplate: + if (Expected<QualType> TyOrErr = + Import(QualType(FromNNS->getAsType(), 0u))) { + bool TSTemplate = + FromNNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate; + return NestedNameSpecifier::Create(ToContext, Prefix, TSTemplate, + TyOrErr->getTypePtr()); + } else { + return TyOrErr.takeError(); } - return nullptr; } llvm_unreachable("Invalid nested name specifier kind"); } Expected<NestedNameSpecifierLoc> -ASTImporter::Import_New(NestedNameSpecifierLoc FromNNS) { - NestedNameSpecifierLoc ToNNS = Import(FromNNS); - return ToNNS; -} -NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { +ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { // Copied from NestedNameSpecifier mostly. SmallVector<NestedNameSpecifierLoc , 8> NestedNames; NestedNameSpecifierLoc NNS = FromNNS; @@ -7980,54 +8163,62 @@ NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { while (!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); - NestedNameSpecifier *Spec = Import(NNS.getNestedNameSpecifier()); - if (!Spec) - return NestedNameSpecifierLoc(); + NestedNameSpecifier *Spec = nullptr; + if (Error Err = importInto(Spec, NNS.getNestedNameSpecifier())) + return std::move(Err); NestedNameSpecifier::SpecifierKind Kind = Spec->getKind(); + + SourceLocation ToLocalBeginLoc, ToLocalEndLoc; + if (Kind != NestedNameSpecifier::Super) { + if (Error Err = importInto(ToLocalBeginLoc, NNS.getLocalBeginLoc())) + return std::move(Err); + + if (Kind != NestedNameSpecifier::Global) + if (Error Err = importInto(ToLocalEndLoc, NNS.getLocalEndLoc())) + return std::move(Err); + } + switch (Kind) { case NestedNameSpecifier::Identifier: - Builder.Extend(getToContext(), - Spec->getAsIdentifier(), - Import(NNS.getLocalBeginLoc()), - Import(NNS.getLocalEndLoc())); + Builder.Extend(getToContext(), Spec->getAsIdentifier(), ToLocalBeginLoc, + ToLocalEndLoc); break; case NestedNameSpecifier::Namespace: - Builder.Extend(getToContext(), - Spec->getAsNamespace(), - Import(NNS.getLocalBeginLoc()), - Import(NNS.getLocalEndLoc())); + Builder.Extend(getToContext(), Spec->getAsNamespace(), ToLocalBeginLoc, + ToLocalEndLoc); break; case NestedNameSpecifier::NamespaceAlias: - Builder.Extend(getToContext(), - Spec->getAsNamespaceAlias(), - Import(NNS.getLocalBeginLoc()), - Import(NNS.getLocalEndLoc())); + Builder.Extend(getToContext(), Spec->getAsNamespaceAlias(), + ToLocalBeginLoc, ToLocalEndLoc); break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { + SourceLocation ToTLoc; + if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc())) + return std::move(Err); TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo( - QualType(Spec->getAsType(), 0)); - Builder.Extend(getToContext(), - Import(NNS.getLocalBeginLoc()), - TSI->getTypeLoc(), - Import(NNS.getLocalEndLoc())); + QualType(Spec->getAsType(), 0), ToTLoc); + Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(), + ToLocalEndLoc); break; } case NestedNameSpecifier::Global: - Builder.MakeGlobal(getToContext(), Import(NNS.getLocalBeginLoc())); + Builder.MakeGlobal(getToContext(), ToLocalBeginLoc); break; case NestedNameSpecifier::Super: { - SourceRange ToRange = Import(NNS.getSourceRange()); - Builder.MakeSuper(getToContext(), - Spec->getAsRecordDecl(), - ToRange.getBegin(), - ToRange.getEnd()); + auto ToSourceRangeOrErr = Import(NNS.getSourceRange()); + if (!ToSourceRangeOrErr) + return ToSourceRangeOrErr.takeError(); + + Builder.MakeSuper(getToContext(), Spec->getAsRecordDecl(), + ToSourceRangeOrErr->getBegin(), + ToSourceRangeOrErr->getEnd()); } } } @@ -8035,137 +8226,126 @@ NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { return Builder.getWithLocInContext(getToContext()); } -Expected<TemplateName> ASTImporter::Import_New(TemplateName From) { - TemplateName To = Import(From); - if (To.isNull() && !From.isNull()) - return llvm::make_error<ImportError>(); - return To; -} -TemplateName ASTImporter::Import(TemplateName From) { +Expected<TemplateName> ASTImporter::Import(TemplateName From) { switch (From.getKind()) { case TemplateName::Template: - if (auto *ToTemplate = - cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) - return TemplateName(ToTemplate); - - return {}; + if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) + return TemplateName(cast<TemplateDecl>(*ToTemplateOrErr)); + else + return ToTemplateOrErr.takeError(); case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate(); UnresolvedSet<2> ToTemplates; for (auto *I : *FromStorage) { - if (auto *To = cast_or_null<NamedDecl>(Import(I))) - ToTemplates.addDecl(To); + if (auto ToOrErr = Import(I)) + ToTemplates.addDecl(cast<NamedDecl>(*ToOrErr)); else - return {}; + return ToOrErr.takeError(); } return ToContext.getOverloadedTemplateName(ToTemplates.begin(), ToTemplates.end()); } + case TemplateName::AssumedTemplate: { + AssumedTemplateStorage *FromStorage = From.getAsAssumedTemplateName(); + auto DeclNameOrErr = Import(FromStorage->getDeclName()); + if (!DeclNameOrErr) + return DeclNameOrErr.takeError(); + return ToContext.getAssumedTemplateName(*DeclNameOrErr); + } + case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName(); - NestedNameSpecifier *Qualifier = Import(QTN->getQualifier()); - if (!Qualifier) - return {}; - - if (auto *ToTemplate = - cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) - return ToContext.getQualifiedTemplateName(Qualifier, - QTN->hasTemplateKeyword(), - ToTemplate); - - return {}; + auto QualifierOrErr = Import(QTN->getQualifier()); + if (!QualifierOrErr) + return QualifierOrErr.takeError(); + + if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) + return ToContext.getQualifiedTemplateName( + *QualifierOrErr, QTN->hasTemplateKeyword(), + cast<TemplateDecl>(*ToTemplateOrErr)); + else + return ToTemplateOrErr.takeError(); } case TemplateName::DependentTemplate: { DependentTemplateName *DTN = From.getAsDependentTemplateName(); - NestedNameSpecifier *Qualifier = Import(DTN->getQualifier()); - if (!Qualifier) - return {}; + auto QualifierOrErr = Import(DTN->getQualifier()); + if (!QualifierOrErr) + return QualifierOrErr.takeError(); if (DTN->isIdentifier()) { - return ToContext.getDependentTemplateName(Qualifier, + return ToContext.getDependentTemplateName(*QualifierOrErr, Import(DTN->getIdentifier())); } - return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator()); + return ToContext.getDependentTemplateName(*QualifierOrErr, + DTN->getOperator()); } case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *subst - = From.getAsSubstTemplateTemplateParm(); - auto *param = - cast_or_null<TemplateTemplateParmDecl>(Import(subst->getParameter())); - if (!param) - return {}; + SubstTemplateTemplateParmStorage *Subst = + From.getAsSubstTemplateTemplateParm(); + ExpectedDecl ParamOrErr = Import(Subst->getParameter()); + if (!ParamOrErr) + return ParamOrErr.takeError(); - TemplateName replacement = Import(subst->getReplacement()); - if (replacement.isNull()) - return {}; + auto ReplacementOrErr = Import(Subst->getReplacement()); + if (!ReplacementOrErr) + return ReplacementOrErr.takeError(); - return ToContext.getSubstTemplateTemplateParm(param, replacement); + return ToContext.getSubstTemplateTemplateParm( + cast<TemplateTemplateParmDecl>(*ParamOrErr), *ReplacementOrErr); } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack = From.getAsSubstTemplateTemplateParmPack(); - auto *Param = - cast_or_null<TemplateTemplateParmDecl>( - Import(SubstPack->getParameterPack())); - if (!Param) - return {}; + ExpectedDecl ParamOrErr = Import(SubstPack->getParameterPack()); + if (!ParamOrErr) + return ParamOrErr.takeError(); ASTNodeImporter Importer(*this); - Expected<TemplateArgument> ArgPack - = Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); - if (!ArgPack) { - llvm::consumeError(ArgPack.takeError()); - return {}; - } + auto ArgPackOrErr = + Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); + if (!ArgPackOrErr) + return ArgPackOrErr.takeError(); - return ToContext.getSubstTemplateTemplateParmPack(Param, *ArgPack); + return ToContext.getSubstTemplateTemplateParmPack( + cast<TemplateTemplateParmDecl>(*ParamOrErr), *ArgPackOrErr); } } llvm_unreachable("Invalid template name kind"); } -Expected<SourceLocation> ASTImporter::Import_New(SourceLocation FromLoc) { - SourceLocation ToLoc = Import(FromLoc); - if (ToLoc.isInvalid() && !FromLoc.isInvalid()) - return llvm::make_error<ImportError>(); - return ToLoc; -} -SourceLocation ASTImporter::Import(SourceLocation FromLoc) { +Expected<SourceLocation> ASTImporter::Import(SourceLocation FromLoc) { if (FromLoc.isInvalid()) - return {}; + return SourceLocation{}; SourceManager &FromSM = FromContext.getSourceManager(); + bool IsBuiltin = FromSM.isWrittenInBuiltinFile(FromLoc); std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc); - FileID ToFileID = Import(Decomposed.first); - if (ToFileID.isInvalid()) - return {}; + Expected<FileID> ToFileIDOrErr = Import(Decomposed.first, IsBuiltin); + if (!ToFileIDOrErr) + return ToFileIDOrErr.takeError(); SourceManager &ToSM = ToContext.getSourceManager(); - return ToSM.getComposedLoc(ToFileID, Decomposed.second); + return ToSM.getComposedLoc(*ToFileIDOrErr, Decomposed.second); } -Expected<SourceRange> ASTImporter::Import_New(SourceRange FromRange) { - SourceRange ToRange = Import(FromRange); - return ToRange; -} -SourceRange ASTImporter::Import(SourceRange FromRange) { - return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd())); -} +Expected<SourceRange> ASTImporter::Import(SourceRange FromRange) { + SourceLocation ToBegin, ToEnd; + if (Error Err = importInto(ToBegin, FromRange.getBegin())) + return std::move(Err); + if (Error Err = importInto(ToEnd, FromRange.getEnd())) + return std::move(Err); -Expected<FileID> ASTImporter::Import_New(FileID FromID) { - FileID ToID = Import(FromID); - if (ToID.isInvalid() && FromID.isValid()) - return llvm::make_error<ImportError>(); - return ToID; + return SourceRange(ToBegin, ToEnd); } -FileID ASTImporter::Import(FileID FromID) { + +Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) { llvm::DenseMap<FileID, FileID>::iterator Pos = ImportedFileIDs.find(FromID); if (Pos != ImportedFileIDs.end()) return Pos->second; @@ -8178,38 +8358,58 @@ FileID ASTImporter::Import(FileID FromID) { FileID ToID; if (FromSLoc.isExpansion()) { const SrcMgr::ExpansionInfo &FromEx = FromSLoc.getExpansion(); - SourceLocation ToSpLoc = Import(FromEx.getSpellingLoc()); - SourceLocation ToExLocS = Import(FromEx.getExpansionLocStart()); + ExpectedSLoc ToSpLoc = Import(FromEx.getSpellingLoc()); + if (!ToSpLoc) + return ToSpLoc.takeError(); + ExpectedSLoc ToExLocS = Import(FromEx.getExpansionLocStart()); + if (!ToExLocS) + return ToExLocS.takeError(); unsigned TokenLen = FromSM.getFileIDSize(FromID); SourceLocation MLoc; if (FromEx.isMacroArgExpansion()) { - MLoc = ToSM.createMacroArgExpansionLoc(ToSpLoc, ToExLocS, TokenLen); + MLoc = ToSM.createMacroArgExpansionLoc(*ToSpLoc, *ToExLocS, TokenLen); } else { - SourceLocation ToExLocE = Import(FromEx.getExpansionLocEnd()); - MLoc = ToSM.createExpansionLoc(ToSpLoc, ToExLocS, ToExLocE, TokenLen, - FromEx.isExpansionTokenRange()); + if (ExpectedSLoc ToExLocE = Import(FromEx.getExpansionLocEnd())) + MLoc = ToSM.createExpansionLoc(*ToSpLoc, *ToExLocS, *ToExLocE, TokenLen, + FromEx.isExpansionTokenRange()); + else + return ToExLocE.takeError(); } ToID = ToSM.getFileID(MLoc); } else { - // Include location of this file. - SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); - const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); - if (Cache->OrigEntry && Cache->OrigEntry->getDir()) { - // FIXME: We probably want to use getVirtualFile(), so we don't hit the - // disk again - // FIXME: We definitely want to re-use the existing MemoryBuffer, rather - // than mmap the files several times. - const FileEntry *Entry = - ToFileManager.getFile(Cache->OrigEntry->getName()); - if (!Entry) - return {}; - ToID = ToSM.createFileID(Entry, ToIncludeLoc, - FromSLoc.getFile().getFileCharacteristic()); - } else { + + if (!IsBuiltin) { + // Include location of this file. + ExpectedSLoc ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); + if (!ToIncludeLoc) + return ToIncludeLoc.takeError(); + + if (Cache->OrigEntry && Cache->OrigEntry->getDir()) { + // FIXME: We probably want to use getVirtualFile(), so we don't hit the + // disk again + // FIXME: We definitely want to re-use the existing MemoryBuffer, rather + // than mmap the files several times. + const FileEntry *Entry = + ToFileManager.getFile(Cache->OrigEntry->getName()); + // FIXME: The filename may be a virtual name that does probably not + // point to a valid file and we get no Entry here. In this case try with + // the memory buffer below. + if (Entry) + ToID = ToSM.createFileID(Entry, *ToIncludeLoc, + FromSLoc.getFile().getFileCharacteristic()); + } + } + + if (ToID.isInvalid() || IsBuiltin) { // FIXME: We want to re-use the existing MemoryBuffer! - const llvm::MemoryBuffer *FromBuf = - Cache->getBuffer(FromContext.getDiagnostics(), FromSM); + bool Invalid = true; + const llvm::MemoryBuffer *FromBuf = Cache->getBuffer( + FromContext.getDiagnostics(), FromSM, SourceLocation{}, &Invalid); + if (!FromBuf || Invalid) + // FIXME: Use a new error kind? + return llvm::make_error<ImportError>(ImportError::Unknown); + std::unique_ptr<llvm::MemoryBuffer> ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); @@ -8218,186 +8418,187 @@ FileID ASTImporter::Import(FileID FromID) { } } + assert(ToID.isValid() && "Unexpected invalid fileID was created."); + ImportedFileIDs[FromID] = ToID; return ToID; } -Expected<CXXCtorInitializer *> -ASTImporter::Import_New(CXXCtorInitializer *From) { - CXXCtorInitializer *To = Import(From); - if (!To && From) - return llvm::make_error<ImportError>(); - return To; -} -CXXCtorInitializer *ASTImporter::Import(CXXCtorInitializer *From) { - Expr *ToExpr = Import(From->getInit()); - if (!ToExpr && From->getInit()) - return nullptr; +Expected<CXXCtorInitializer *> ASTImporter::Import(CXXCtorInitializer *From) { + ExpectedExpr ToExprOrErr = Import(From->getInit()); + if (!ToExprOrErr) + return ToExprOrErr.takeError(); + + auto LParenLocOrErr = Import(From->getLParenLoc()); + if (!LParenLocOrErr) + return LParenLocOrErr.takeError(); + + auto RParenLocOrErr = Import(From->getRParenLoc()); + if (!RParenLocOrErr) + return RParenLocOrErr.takeError(); if (From->isBaseInitializer()) { - TypeSourceInfo *ToTInfo = Import(From->getTypeSourceInfo()); - if (!ToTInfo && From->getTypeSourceInfo()) - return nullptr; + auto ToTInfoOrErr = Import(From->getTypeSourceInfo()); + if (!ToTInfoOrErr) + return ToTInfoOrErr.takeError(); + + SourceLocation EllipsisLoc; + if (From->isPackExpansion()) + if (Error Err = importInto(EllipsisLoc, From->getEllipsisLoc())) + return std::move(Err); return new (ToContext) CXXCtorInitializer( - ToContext, ToTInfo, From->isBaseVirtual(), Import(From->getLParenLoc()), - ToExpr, Import(From->getRParenLoc()), - From->isPackExpansion() ? Import(From->getEllipsisLoc()) - : SourceLocation()); + ToContext, *ToTInfoOrErr, From->isBaseVirtual(), *LParenLocOrErr, + *ToExprOrErr, *RParenLocOrErr, EllipsisLoc); } else if (From->isMemberInitializer()) { - auto *ToField = cast_or_null<FieldDecl>(Import(From->getMember())); - if (!ToField && From->getMember()) - return nullptr; + ExpectedDecl ToFieldOrErr = Import(From->getMember()); + if (!ToFieldOrErr) + return ToFieldOrErr.takeError(); + + auto MemberLocOrErr = Import(From->getMemberLocation()); + if (!MemberLocOrErr) + return MemberLocOrErr.takeError(); return new (ToContext) CXXCtorInitializer( - ToContext, ToField, Import(From->getMemberLocation()), - Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc())); + ToContext, cast_or_null<FieldDecl>(*ToFieldOrErr), *MemberLocOrErr, + *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr); } else if (From->isIndirectMemberInitializer()) { - auto *ToIField = cast_or_null<IndirectFieldDecl>( - Import(From->getIndirectMember())); - if (!ToIField && From->getIndirectMember()) - return nullptr; + ExpectedDecl ToIFieldOrErr = Import(From->getIndirectMember()); + if (!ToIFieldOrErr) + return ToIFieldOrErr.takeError(); + + auto MemberLocOrErr = Import(From->getMemberLocation()); + if (!MemberLocOrErr) + return MemberLocOrErr.takeError(); return new (ToContext) CXXCtorInitializer( - ToContext, ToIField, Import(From->getMemberLocation()), - Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc())); + ToContext, cast_or_null<IndirectFieldDecl>(*ToIFieldOrErr), + *MemberLocOrErr, *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr); } else if (From->isDelegatingInitializer()) { - TypeSourceInfo *ToTInfo = Import(From->getTypeSourceInfo()); - if (!ToTInfo && From->getTypeSourceInfo()) - return nullptr; + auto ToTInfoOrErr = Import(From->getTypeSourceInfo()); + if (!ToTInfoOrErr) + return ToTInfoOrErr.takeError(); return new (ToContext) - CXXCtorInitializer(ToContext, ToTInfo, Import(From->getLParenLoc()), - ToExpr, Import(From->getRParenLoc())); + CXXCtorInitializer(ToContext, *ToTInfoOrErr, *LParenLocOrErr, + *ToExprOrErr, *RParenLocOrErr); } else { - return nullptr; + // FIXME: assert? + return make_error<ImportError>(); } } Expected<CXXBaseSpecifier *> -ASTImporter::Import_New(const CXXBaseSpecifier *From) { - CXXBaseSpecifier *To = Import(From); - if (!To && From) - return llvm::make_error<ImportError>(); - return To; -} -CXXBaseSpecifier *ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) { +ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) { auto Pos = ImportedCXXBaseSpecifiers.find(BaseSpec); if (Pos != ImportedCXXBaseSpecifiers.end()) return Pos->second; + Expected<SourceRange> ToSourceRange = Import(BaseSpec->getSourceRange()); + if (!ToSourceRange) + return ToSourceRange.takeError(); + Expected<TypeSourceInfo *> ToTSI = Import(BaseSpec->getTypeSourceInfo()); + if (!ToTSI) + return ToTSI.takeError(); + ExpectedSLoc ToEllipsisLoc = Import(BaseSpec->getEllipsisLoc()); + if (!ToEllipsisLoc) + return ToEllipsisLoc.takeError(); CXXBaseSpecifier *Imported = new (ToContext) CXXBaseSpecifier( - Import(BaseSpec->getSourceRange()), - BaseSpec->isVirtual(), BaseSpec->isBaseOfClass(), - BaseSpec->getAccessSpecifierAsWritten(), - Import(BaseSpec->getTypeSourceInfo()), - Import(BaseSpec->getEllipsisLoc())); + *ToSourceRange, BaseSpec->isVirtual(), BaseSpec->isBaseOfClass(), + BaseSpec->getAccessSpecifierAsWritten(), *ToTSI, *ToEllipsisLoc); ImportedCXXBaseSpecifiers[BaseSpec] = Imported; return Imported; } -Error ASTImporter::ImportDefinition_New(Decl *From) { - Decl *To = Import(From); - if (!To) - return llvm::make_error<ImportError>(); +Error ASTImporter::ImportDefinition(Decl *From) { + ExpectedDecl ToOrErr = Import(From); + if (!ToOrErr) + return ToOrErr.takeError(); + Decl *To = *ToOrErr; - if (auto *FromDC = cast<DeclContext>(From)) { - ASTNodeImporter Importer(*this); + auto *FromDC = cast<DeclContext>(From); + ASTNodeImporter Importer(*this); - if (auto *ToRecord = dyn_cast<RecordDecl>(To)) { - if (!ToRecord->getDefinition()) { - return Importer.ImportDefinition( - cast<RecordDecl>(FromDC), ToRecord, - ASTNodeImporter::IDK_Everything); - } + if (auto *ToRecord = dyn_cast<RecordDecl>(To)) { + if (!ToRecord->getDefinition()) { + return Importer.ImportDefinition( + cast<RecordDecl>(FromDC), ToRecord, + ASTNodeImporter::IDK_Everything); } + } - if (auto *ToEnum = dyn_cast<EnumDecl>(To)) { - if (!ToEnum->getDefinition()) { - return Importer.ImportDefinition( - cast<EnumDecl>(FromDC), ToEnum, ASTNodeImporter::IDK_Everything); - } + if (auto *ToEnum = dyn_cast<EnumDecl>(To)) { + if (!ToEnum->getDefinition()) { + return Importer.ImportDefinition( + cast<EnumDecl>(FromDC), ToEnum, ASTNodeImporter::IDK_Everything); } + } - if (auto *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) { - if (!ToIFace->getDefinition()) { - return Importer.ImportDefinition( - cast<ObjCInterfaceDecl>(FromDC), ToIFace, - ASTNodeImporter::IDK_Everything); - } + if (auto *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) { + if (!ToIFace->getDefinition()) { + return Importer.ImportDefinition( + cast<ObjCInterfaceDecl>(FromDC), ToIFace, + ASTNodeImporter::IDK_Everything); } + } - if (auto *ToProto = dyn_cast<ObjCProtocolDecl>(To)) { - if (!ToProto->getDefinition()) { - return Importer.ImportDefinition( - cast<ObjCProtocolDecl>(FromDC), ToProto, - ASTNodeImporter::IDK_Everything); - } + if (auto *ToProto = dyn_cast<ObjCProtocolDecl>(To)) { + if (!ToProto->getDefinition()) { + return Importer.ImportDefinition( + cast<ObjCProtocolDecl>(FromDC), ToProto, + ASTNodeImporter::IDK_Everything); } - - return Importer.ImportDeclContext(FromDC, true); } - return Error::success(); + return Importer.ImportDeclContext(FromDC, true); } -void ASTImporter::ImportDefinition(Decl *From) { - Error Err = ImportDefinition_New(From); - llvm::consumeError(std::move(Err)); -} - -Expected<DeclarationName> ASTImporter::Import_New(DeclarationName FromName) { - DeclarationName ToName = Import(FromName); - if (!ToName && FromName) - return llvm::make_error<ImportError>(); - return ToName; -} -DeclarationName ASTImporter::Import(DeclarationName FromName) { +Expected<DeclarationName> ASTImporter::Import(DeclarationName FromName) { if (!FromName) - return {}; + return DeclarationName{}; switch (FromName.getNameKind()) { case DeclarationName::Identifier: - return Import(FromName.getAsIdentifierInfo()); + return DeclarationName(Import(FromName.getAsIdentifierInfo())); case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - return Import(FromName.getObjCSelector()); + if (auto ToSelOrErr = Import(FromName.getObjCSelector())) + return DeclarationName(*ToSelOrErr); + else + return ToSelOrErr.takeError(); case DeclarationName::CXXConstructorName: { - QualType T = Import(FromName.getCXXNameType()); - if (T.isNull()) - return {}; - - return ToContext.DeclarationNames.getCXXConstructorName( - ToContext.getCanonicalType(T)); + if (auto ToTyOrErr = Import(FromName.getCXXNameType())) + return ToContext.DeclarationNames.getCXXConstructorName( + ToContext.getCanonicalType(*ToTyOrErr)); + else + return ToTyOrErr.takeError(); } case DeclarationName::CXXDestructorName: { - QualType T = Import(FromName.getCXXNameType()); - if (T.isNull()) - return {}; - - return ToContext.DeclarationNames.getCXXDestructorName( - ToContext.getCanonicalType(T)); + if (auto ToTyOrErr = Import(FromName.getCXXNameType())) + return ToContext.DeclarationNames.getCXXDestructorName( + ToContext.getCanonicalType(*ToTyOrErr)); + else + return ToTyOrErr.takeError(); } case DeclarationName::CXXDeductionGuideName: { - auto *Template = cast_or_null<TemplateDecl>( - Import(FromName.getCXXDeductionGuideTemplate())); - if (!Template) - return {}; - return ToContext.DeclarationNames.getCXXDeductionGuideName(Template); + if (auto ToTemplateOrErr = Import(FromName.getCXXDeductionGuideTemplate())) + return ToContext.DeclarationNames.getCXXDeductionGuideName( + cast<TemplateDecl>(*ToTemplateOrErr)); + else + return ToTemplateOrErr.takeError(); } case DeclarationName::CXXConversionFunctionName: { - QualType T = Import(FromName.getCXXNameType()); - if (T.isNull()) - return {}; - - return ToContext.DeclarationNames.getCXXConversionFunctionName( - ToContext.getCanonicalType(T)); + if (auto ToTyOrErr = Import(FromName.getCXXNameType())) + return ToContext.DeclarationNames.getCXXConversionFunctionName( + ToContext.getCanonicalType(*ToTyOrErr)); + else + return ToTyOrErr.takeError(); } case DeclarationName::CXXOperatorName: @@ -8406,7 +8607,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) { case DeclarationName::CXXLiteralOperatorName: return ToContext.DeclarationNames.getCXXLiteralOperatorName( - Import(FromName.getCXXLiteralIdentifier())); + Import(FromName.getCXXLiteralIdentifier())); case DeclarationName::CXXUsingDirective: // FIXME: STATICS! @@ -8428,15 +8629,9 @@ IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) { return ToId; } -Expected<Selector> ASTImporter::Import_New(Selector FromSel) { - Selector ToSel = Import(FromSel); - if (ToSel.isNull() && !FromSel.isNull()) - return llvm::make_error<ImportError>(); - return ToSel; -} -Selector ASTImporter::Import(Selector FromSel) { +Expected<Selector> ASTImporter::Import(Selector FromSel) { if (FromSel.isNull()) - return {}; + return Selector{}; SmallVector<IdentifierInfo *, 4> Idents; Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0))); @@ -8496,15 +8691,42 @@ Decl *ASTImporter::MapImported(Decl *From, Decl *To) { if (Pos != ImportedDecls.end()) return Pos->second; ImportedDecls[From] = To; + // This mapping should be maintained only in this function. Therefore do not + // check for additional consistency. + ImportedFromDecls[To] = From; + AddToLookupTable(To); return To; } +llvm::Optional<ImportError> +ASTImporter::getImportDeclErrorIfAny(Decl *FromD) const { + auto Pos = ImportDeclErrors.find(FromD); + if (Pos != ImportDeclErrors.end()) + return Pos->second; + else + return Optional<ImportError>(); +} + +void ASTImporter::setImportDeclError(Decl *From, ImportError Error) { + auto InsertRes = ImportDeclErrors.insert({From, Error}); + (void)InsertRes; + // Either we set the error for the first time, or we already had set one and + // now we want to set the same error. + assert(InsertRes.second || InsertRes.first->second.Error == Error.Error); +} + bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, bool Complain) { - llvm::DenseMap<const Type *, const Type *>::iterator Pos - = ImportedTypes.find(From.getTypePtr()); - if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) - return true; + llvm::DenseMap<const Type *, const Type *>::iterator Pos = + ImportedTypes.find(From.getTypePtr()); + if (Pos != ImportedTypes.end()) { + if (ExpectedType ToFromOrErr = Import(From)) { + if (ToContext.hasSameType(*ToFromOrErr, To)) + return true; + } else { + llvm::consumeError(ToFromOrErr.takeError()); + } + } StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls, getStructuralEquivalenceKind(*this), false, |