From 30e450b379194302f797d7d3083e61b6a67bf002 Mon Sep 17 00:00:00 2001 From: Sean Callanan Date: Sat, 14 May 2016 05:20:31 +0000 Subject: [PATCH] Added support to the ASTImporter for C++ constructor initializers. Thanks to Aleksei Sidorin for review and advice. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@269546 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTImporter.h | 9 +++ lib/AST/ASTImporter.cpp | 82 +++++++++++++++++++++ test/ASTMerge/Inputs/init-ctors-classes.cpp | 17 +++++ test/ASTMerge/init-ctors.cpp | 10 +++ 4 files changed, 118 insertions(+) create mode 100644 test/ASTMerge/Inputs/init-ctors-classes.cpp create mode 100644 test/ASTMerge/init-ctors.cpp diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h index ee48955ca6..e116abaef7 100644 --- a/include/clang/AST/ASTImporter.h +++ b/include/clang/AST/ASTImporter.h @@ -23,6 +23,7 @@ namespace clang { class ASTContext; + class CXXCtorInitializer; class Decl; class DeclContext; class DiagnosticsEngine; @@ -204,6 +205,14 @@ namespace clang { /// \returns the equivalent file ID in the source manager of the "to" /// context. FileID Import(FileID); + + /// \brief Import the given C++ constructor initializer from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent initializer in the "to" context. + CXXCtorInitializer *Import(CXXCtorInitializer *FromInit); + + /// \brief Import the definition of the given declaration, including all of /// the declarations it contains. diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index ec6655391e..3598dccf0a 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -3020,6 +3020,22 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()); + if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) { + SmallVector CtorInitializers; + for (CXXCtorInitializer *I : FromConstructor->inits()) { + CXXCtorInitializer *ToI = + cast_or_null(Importer.Import(I)); + if (!ToI && I) + return nullptr; + CtorInitializers.push_back(ToI); + } + CXXCtorInitializer **Memory = + new (Importer.getToContext()) CXXCtorInitializer *[NumInitializers]; + std::copy(CtorInitializers.begin(), CtorInitializers.end(), Memory); + CXXConstructorDecl *ToCtor = llvm::cast(ToFunction); + ToCtor->setCtorInitializers(Memory); + ToCtor->setNumCtorInitializers(NumInitializers); + } } else if (isa(D)) { ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), cast(DC), @@ -6351,6 +6367,72 @@ FileID ASTImporter::Import(FileID FromID) { return ToID; } +CXXCtorInitializer *ASTImporter::Import(CXXCtorInitializer *From) { + Expr *ToExpr = Import(From->getInit()); + if (!ToExpr && From->getInit()) + return nullptr; + + if (From->isBaseInitializer()) { + TypeSourceInfo *ToTInfo = Import(From->getTypeSourceInfo()); + if (!ToTInfo && From->getTypeSourceInfo()) + return nullptr; + + return new (ToContext) CXXCtorInitializer( + ToContext, ToTInfo, From->isBaseVirtual(), Import(From->getLParenLoc()), + ToExpr, Import(From->getRParenLoc()), + From->isPackExpansion() ? Import(From->getEllipsisLoc()) + : SourceLocation()); + } else if (From->isMemberInitializer()) { + FieldDecl *ToField = + llvm::cast_or_null(Import(From->getMember())); + if (!ToField && From->getMember()) + return nullptr; + + return new (ToContext) CXXCtorInitializer( + ToContext, ToField, Import(From->getMemberLocation()), + Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc())); + } else if (From->isIndirectMemberInitializer()) { + IndirectFieldDecl *ToIField = llvm::cast_or_null( + Import(From->getIndirectMember())); + if (!ToIField && From->getIndirectMember()) + return nullptr; + + return new (ToContext) CXXCtorInitializer( + ToContext, ToIField, Import(From->getMemberLocation()), + Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc())); + } else if (From->isDelegatingInitializer()) { + TypeSourceInfo *ToTInfo = Import(From->getTypeSourceInfo()); + if (!ToTInfo && From->getTypeSourceInfo()) + return nullptr; + + return new (ToContext) + CXXCtorInitializer(ToContext, ToTInfo, Import(From->getLParenLoc()), + ToExpr, Import(From->getRParenLoc())); + } else if (unsigned NumArrayIndices = From->getNumArrayIndices()) { + FieldDecl *ToField = + llvm::cast_or_null(Import(From->getMember())); + if (!ToField && From->getMember()) + return nullptr; + + SmallVector ToAIs(NumArrayIndices); + + for (unsigned AII = 0; AII < NumArrayIndices; ++AII) { + VarDecl *ToArrayIndex = + dyn_cast_or_null(Import(From->getArrayIndex(AII))); + if (!ToArrayIndex && From->getArrayIndex(AII)) + return nullptr; + } + + return CXXCtorInitializer::Create( + ToContext, ToField, Import(From->getMemberLocation()), + Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc()), + ToAIs.data(), NumArrayIndices); + } else { + return nullptr; + } +} + + void ASTImporter::ImportDefinition(Decl *From) { Decl *To = Import(From); if (!To) diff --git a/test/ASTMerge/Inputs/init-ctors-classes.cpp b/test/ASTMerge/Inputs/init-ctors-classes.cpp new file mode 100644 index 0000000000..616e5dfebc --- /dev/null +++ b/test/ASTMerge/Inputs/init-ctors-classes.cpp @@ -0,0 +1,17 @@ +class A_base +{ +public: + int x; + A_base(int _x) : x(_x) { + } +}; + +class A : public A_base +{ +public: + int y; + struct { int z; }; + int array[2]; + A(int _x) : A_base(_x), y(0), z(1), array{{2},{3}} { + } +}; diff --git a/test/ASTMerge/init-ctors.cpp b/test/ASTMerge/init-ctors.cpp new file mode 100644 index 0000000000..5f0ba4decd --- /dev/null +++ b/test/ASTMerge/init-ctors.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/init-ctors-classes.cpp +// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -ast-merge %t.1.ast -fsyntax-only -verify %s +// expected-no-diagnostics + +class B { + int method_1() { + A a(0); + return a.x; + } +}; -- 2.40.0