r323519 - [ASTImporter] Support LambdaExprs and improve template support
Aleksei Sidorin via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 26 03:36:55 PST 2018
Author: a.sidorin
Date: Fri Jan 26 03:36:54 2018
New Revision: 323519
URL: http://llvm.org/viewvc/llvm-project?rev=323519&view=rev
Log:
[ASTImporter] Support LambdaExprs and improve template support
Also, a number of style and bug fixes was done:
* ASTImporterTest: added sanity check for source node
* ExternalASTMerger: better lookup for template specializations
* ASTImporter: don't add templated declarations into DeclContext
* ASTImporter: introduce a helper, ImportTemplateArgumentListInfo getting SourceLocations
* ASTImporter: proper set ParmVarDecls for imported FunctionProtoTypeLoc
Differential Revision: https://reviews.llvm.org/D42301
Added:
cfe/trunk/test/ASTMerge/function-cpp/
cfe/trunk/test/ASTMerge/function-cpp/Inputs/
cfe/trunk/test/ASTMerge/function-cpp/Inputs/function-1.cpp
cfe/trunk/test/ASTMerge/function-cpp/test.cpp
Modified:
cfe/trunk/lib/AST/ASTImporter.cpp
cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
cfe/trunk/lib/AST/ExternalASTMerger.cpp
cfe/trunk/test/ASTMerge/class-template/Inputs/class-template1.cpp
cfe/trunk/test/ASTMerge/class-template/Inputs/class-template2.cpp
cfe/trunk/test/ASTMerge/class-template/test.cpp
cfe/trunk/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp
cfe/trunk/test/ASTMerge/exprs-cpp/test.cpp
cfe/trunk/test/Import/template-specialization/Inputs/T.cpp
cfe/trunk/test/Import/template-specialization/test.cpp
cfe/trunk/unittests/AST/ASTImporterTest.cpp
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Fri Jan 26 03:36:54 2018
@@ -97,6 +97,8 @@ namespace clang {
typedef DesignatedInitExpr::Designator Designator;
Designator ImportDesignator(const Designator &D);
+ Optional<LambdaCapture> ImportLambdaCapture(const LambdaCapture &From);
+
/// \brief What we should import from the definition.
enum ImportDefinitionKind {
@@ -127,16 +129,26 @@ namespace clang {
bool ImportDefinition(ObjCProtocolDecl *From, ObjCProtocolDecl *To,
ImportDefinitionKind Kind = IDK_Default);
TemplateParameterList *ImportTemplateParameterList(
- TemplateParameterList *Params);
+ TemplateParameterList *Params);
TemplateArgument ImportTemplateArgument(const TemplateArgument &From);
Optional<TemplateArgumentLoc> ImportTemplateArgumentLoc(
const TemplateArgumentLoc &TALoc);
bool ImportTemplateArguments(const TemplateArgument *FromArgs,
unsigned NumFromArgs,
- SmallVectorImpl<TemplateArgument> &ToArgs);
+ SmallVectorImpl<TemplateArgument> &ToArgs);
+
template <typename InContainerTy>
bool ImportTemplateArgumentListInfo(const InContainerTy &Container,
TemplateArgumentListInfo &ToTAInfo);
+
+ template<typename InContainerTy>
+ bool ImportTemplateArgumentListInfo(SourceLocation FromLAngleLoc,
+ SourceLocation FromRAngleLoc,
+ const InContainerTy &Container,
+ TemplateArgumentListInfo &Result);
+
+ bool ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD);
+
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
@@ -295,6 +307,7 @@ namespace clang {
Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
Expr *VisitMemberExpr(MemberExpr *E);
Expr *VisitCallExpr(CallExpr *E);
+ Expr *VisitLambdaExpr(LambdaExpr *LE);
Expr *VisitInitListExpr(InitListExpr *E);
Expr *VisitArrayInitLoopExpr(ArrayInitLoopExpr *E);
Expr *VisitArrayInitIndexExpr(ArrayInitIndexExpr *E);
@@ -1045,7 +1058,6 @@ bool ASTNodeImporter::ImportDefinition(R
= FromData.HasDeclaredCopyConstructorWithConstParam;
ToData.HasDeclaredCopyAssignmentWithConstParam
= FromData.HasDeclaredCopyAssignmentWithConstParam;
- ToData.IsLambda = FromData.IsLambda;
SmallVector<CXXBaseSpecifier *, 4> Bases;
for (const auto &Base1 : FromCXX->bases()) {
@@ -1256,6 +1268,9 @@ bool ASTNodeImporter::ImportTemplateArgu
return false;
}
+// We cannot use Optional<> pattern here and below because
+// TemplateArgumentListInfo's operator new is declared as deleted so it cannot
+// be stored in Optional.
template <typename InContainerTy>
bool ASTNodeImporter::ImportTemplateArgumentListInfo(
const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo) {
@@ -1268,6 +1283,18 @@ bool ASTNodeImporter::ImportTemplateArgu
return false;
}
+template <typename InContainerTy>
+bool ASTNodeImporter::ImportTemplateArgumentListInfo(
+ SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc,
+ const InContainerTy &Container, TemplateArgumentListInfo &Result) {
+ TemplateArgumentListInfo ToTAInfo(Importer.Import(FromLAngleLoc),
+ Importer.Import(FromRAngleLoc));
+ if (ImportTemplateArgumentListInfo(Container, ToTAInfo))
+ return true;
+ Result = ToTAInfo;
+ return false;
+}
+
bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
RecordDecl *ToRecord, bool Complain) {
// Eliminate a potential failure point where we attempt to re-import
@@ -1918,16 +1945,16 @@ Decl *ASTNodeImporter::VisitRecordDecl(R
if (DCXX->getLambdaContextDecl() && !CDecl)
return nullptr;
D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), CDecl);
- } else if (DCXX->isInjectedClassName()) {
- // We have to be careful to do a similar dance to the one in
- // Sema::ActOnStartCXXMemberDeclarations
- CXXRecordDecl *const PrevDecl = nullptr;
- const bool DelayTypeCreation = true;
- D2CXX = CXXRecordDecl::Create(
- Importer.getToContext(), D->getTagKind(), DC, StartLoc, Loc,
- Name.getAsIdentifierInfo(), PrevDecl, DelayTypeCreation);
- Importer.getToContext().getTypeDeclType(
- D2CXX, llvm::dyn_cast<CXXRecordDecl>(DC));
+ } else if (DCXX->isInjectedClassName()) {
+ // We have to be careful to do a similar dance to the one in
+ // Sema::ActOnStartCXXMemberDeclarations
+ CXXRecordDecl *const PrevDecl = nullptr;
+ const bool DelayTypeCreation = true;
+ D2CXX = CXXRecordDecl::Create(
+ Importer.getToContext(), D->getTagKind(), DC, StartLoc, Loc,
+ Name.getAsIdentifierInfo(), PrevDecl, DelayTypeCreation);
+ Importer.getToContext().getTypeDeclType(
+ D2CXX, llvm::dyn_cast<CXXRecordDecl>(DC));
} else {
D2CXX = CXXRecordDecl::Create(Importer.getToContext(),
D->getTagKind(),
@@ -1936,6 +1963,9 @@ Decl *ASTNodeImporter::VisitRecordDecl(R
}
D2 = D2CXX;
D2->setAccess(D->getAccess());
+ D2->setLexicalDeclContext(LexicalDC);
+ if (!DCXX->getDescribedClassTemplate())
+ LexicalDC->addDeclInternal(D2);
Importer.Imported(D, D2);
@@ -1964,11 +1994,11 @@ Decl *ASTNodeImporter::VisitRecordDecl(R
} else {
D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(),
DC, StartLoc, Loc, Name.getAsIdentifierInfo());
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
}
D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
- D2->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDeclInternal(D2);
if (D->isAnonymousStructOrUnion())
D2->setAnonymousStructOrUnion(true);
if (PrevDecl) {
@@ -2044,6 +2074,94 @@ Decl *ASTNodeImporter::VisitEnumConstant
return ToEnumerator;
}
+bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD,
+ FunctionDecl *ToFD) {
+ switch (FromFD->getTemplatedKind()) {
+ case FunctionDecl::TK_NonTemplate:
+ case FunctionDecl::TK_FunctionTemplate:
+ break;
+
+ case FunctionDecl::TK_MemberSpecialization: {
+ auto *InstFD = cast_or_null<FunctionDecl>(
+ Importer.Import(FromFD->getInstantiatedFromMemberFunction()));
+ if (!InstFD)
+ return true;
+
+ TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind();
+ SourceLocation POI = Importer.Import(
+ FromFD->getMemberSpecializationInfo()->getPointOfInstantiation());
+ ToFD->setInstantiationOfMemberFunction(InstFD, TSK);
+ ToFD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ break;
+ }
+
+ case FunctionDecl::TK_FunctionTemplateSpecialization: {
+ auto *FTSInfo = FromFD->getTemplateSpecializationInfo();
+ auto *Template = cast_or_null<FunctionTemplateDecl>(
+ Importer.Import(FTSInfo->getTemplate()));
+ if (!Template)
+ return true;
+ TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
+
+ // Import template arguments.
+ auto TemplArgs = FTSInfo->TemplateArguments->asArray();
+ SmallVector<TemplateArgument, 8> ToTemplArgs;
+ if (ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(),
+ ToTemplArgs))
+ return true;
+
+ TemplateArgumentList *ToTAList = TemplateArgumentList::CreateCopy(
+ Importer.getToContext(), ToTemplArgs);
+
+ TemplateArgumentListInfo ToTAInfo;
+ const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten;
+ if (FromTAArgsAsWritten) {
+ if (ImportTemplateArgumentListInfo(
+ FromTAArgsAsWritten->LAngleLoc, FromTAArgsAsWritten->RAngleLoc,
+ FromTAArgsAsWritten->arguments(), ToTAInfo))
+ return true;
+ }
+
+ SourceLocation POI = Importer.Import(FTSInfo->getPointOfInstantiation());
+
+ ToFD->setFunctionTemplateSpecialization(
+ Template, ToTAList, /* InsertPos= */ nullptr,
+ TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, POI);
+ break;
+ }
+
+ case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
+ auto *FromInfo = FromFD->getDependentSpecializationInfo();
+ UnresolvedSet<8> TemplDecls;
+ unsigned NumTemplates = FromInfo->getNumTemplates();
+ for (unsigned I = 0; I < NumTemplates; I++) {
+ if (auto *ToFTD = cast_or_null<FunctionTemplateDecl>(
+ Importer.Import(FromInfo->getTemplate(I))))
+ TemplDecls.addDecl(ToFTD);
+ else
+ return true;
+ }
+
+ // Import TemplateArgumentListInfo.
+ TemplateArgumentListInfo ToTAInfo;
+ if (ImportTemplateArgumentListInfo(
+ FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(),
+ llvm::makeArrayRef(FromInfo->getTemplateArgs(),
+ FromInfo->getNumTemplateArgs()),
+ ToTAInfo))
+ return true;
+
+ ToFD->setDependentTemplateSpecialization(Importer.getToContext(),
+ TemplDecls, ToTAInfo);
+ break;
+ }
+ default:
+ llvm_unreachable("All cases should be covered!");
+ }
+
+ return false;
+}
+
Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import the major distinguishing characteristics of this function.
DeclContext *DC, *LexicalDC;
@@ -2151,15 +2269,18 @@ Decl *ASTNodeImporter::VisitFunctionDecl
Parameters.push_back(ToP);
}
- // Create the imported function.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ if (D->getTypeSourceInfo() && !TInfo)
+ return nullptr;
+
+ // Create the imported function.
FunctionDecl *ToFunction = nullptr;
SourceLocation InnerLocStart = Importer.Import(D->getInnerLocStart());
if (CXXConstructorDecl *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
ToFunction = CXXConstructorDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
InnerLocStart,
- NameInfo, T, TInfo,
+ NameInfo, T, TInfo,
FromConstructor->isExplicit(),
D->isInlineSpecified(),
D->isImplicit(),
@@ -2225,9 +2346,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl
Importer.Imported(D, ToFunction);
// Set the parameters.
- for (unsigned I = 0, N = Parameters.size(); I != N; ++I) {
- Parameters[I]->setOwningFunction(ToFunction);
- ToFunction->addDeclInternal(Parameters[I]);
+ for (ParmVarDecl *Param : Parameters) {
+ Param->setOwningFunction(ToFunction);
+ ToFunction->addDeclInternal(Param);
}
ToFunction->setParams(Parameters);
@@ -2237,6 +2358,16 @@ Decl *ASTNodeImporter::VisitFunctionDecl
ToFunction->setPreviousDecl(Recent);
}
+ // We need to complete creation of FunctionProtoTypeLoc manually with setting
+ // params it refers to.
+ if (TInfo) {
+ if (auto ProtoLoc =
+ TInfo->getTypeLoc().IgnoreParens().getAs<FunctionProtoTypeLoc>()) {
+ for (unsigned I = 0, N = Parameters.size(); I != N; ++I)
+ ProtoLoc.setParam(I, Parameters[I]);
+ }
+ }
+
if (usedDifferentExceptionSpec) {
// Update FunctionProtoType::ExtProtoInfo.
QualType T = Importer.Import(D->getType());
@@ -2254,8 +2385,17 @@ Decl *ASTNodeImporter::VisitFunctionDecl
// FIXME: Other bits to merge?
+ // If it is a template, import all related things.
+ if (ImportTemplateInformation(D, ToFunction))
+ return nullptr;
+
// Add this function to the lexical context.
- LexicalDC->addDeclInternal(ToFunction);
+ // NOTE: If the function is templated declaration, it should be not added into
+ // LexicalDC. But described template is imported during import of
+ // FunctionTemplateDecl (it happens later). So, we use source declaration
+ // to determine if we should add the result function.
+ if (!D->getDescribedFunctionTemplate())
+ LexicalDC->addDeclInternal(ToFunction);
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
@@ -2749,6 +2889,14 @@ Decl *ASTNodeImporter::VisitParmVarDecl(
if (FromDefArg && !ToDefArg)
return nullptr;
+ if (D->isObjCMethodParameter()) {
+ ToParm->setObjCMethodScopeInfo(D->getFunctionScopeIndex());
+ ToParm->setObjCDeclQualifier(D->getObjCDeclQualifier());
+ } else {
+ ToParm->setScopeInfo(D->getFunctionScopeDepth(),
+ D->getFunctionScopeIndex());
+ }
+
if (D->isUsed())
ToParm->setIsUsed();
@@ -3850,12 +3998,12 @@ Decl *ASTNodeImporter::VisitClassTemplat
return nullptr;
}
- CXXRecordDecl *DTemplated = D->getTemplatedDecl();
-
+ CXXRecordDecl *FromTemplated = D->getTemplatedDecl();
+
// Create the declaration that is being templated.
- CXXRecordDecl *D2Templated = cast_or_null<CXXRecordDecl>(
- Importer.Import(DTemplated));
- if (!D2Templated)
+ CXXRecordDecl *ToTemplated = cast_or_null<CXXRecordDecl>(
+ Importer.Import(FromTemplated));
+ if (!ToTemplated)
return nullptr;
// Resolve possible cyclic import.
@@ -3863,15 +4011,15 @@ Decl *ASTNodeImporter::VisitClassTemplat
return AlreadyImported;
// Create the class template declaration itself.
- TemplateParameterList *TemplateParams
- = ImportTemplateParameterList(D->getTemplateParameters());
+ TemplateParameterList *TemplateParams =
+ ImportTemplateParameterList(D->getTemplateParameters());
if (!TemplateParams)
return nullptr;
ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC,
Loc, Name, TemplateParams,
- D2Templated);
- D2Templated->setDescribedClassTemplate(D2);
+ ToTemplated);
+ ToTemplated->setDescribedClassTemplate(D2);
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
@@ -3879,10 +4027,10 @@ Decl *ASTNodeImporter::VisitClassTemplat
// Note the relationship between the class templates.
Importer.Imported(D, D2);
- Importer.Imported(DTemplated, D2Templated);
+ Importer.Imported(FromTemplated, ToTemplated);
- if (DTemplated->isCompleteDefinition() &&
- !D2Templated->isCompleteDefinition()) {
+ if (FromTemplated->isCompleteDefinition() &&
+ !ToTemplated->isCompleteDefinition()) {
// FIXME: Import definition!
}
@@ -3958,12 +4106,8 @@ Decl *ASTNodeImporter::VisitClassTemplat
// Import TemplateArgumentListInfo
TemplateArgumentListInfo ToTAInfo;
auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten();
- for (unsigned I = 0, E = ASTTemplateArgs.NumTemplateArgs; I < E; ++I) {
- if (auto ToLoc = ImportTemplateArgumentLoc(ASTTemplateArgs[I]))
- ToTAInfo.addArgument(*ToLoc);
- else
- return nullptr;
- }
+ if (ImportTemplateArgumentListInfo(ASTTemplateArgs.arguments(), ToTAInfo))
+ return nullptr;
QualType CanonInjType = Importer.Import(
PartialSpec->getInjectedSpecializationType());
@@ -4901,12 +5045,8 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(
TemplateArgumentListInfo ToTAInfo;
TemplateArgumentListInfo *ResInfo = nullptr;
if (E->hasExplicitTemplateArgs()) {
- for (const auto &FromLoc : E->template_arguments()) {
- if (auto ToTALoc = ImportTemplateArgumentLoc(FromLoc))
- ToTAInfo.addArgument(*ToTALoc);
- else
- return nullptr;
- }
+ if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+ return nullptr;
ResInfo = &ToTAInfo;
}
@@ -5861,11 +6001,10 @@ Expr *ASTNodeImporter::VisitCXXDependent
if (BaseType.isNull())
return nullptr;
- TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()),
- Importer.Import(E->getRAngleLoc()));
- TemplateArgumentListInfo *ResInfo = nullptr;
+ TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr;
if (E->hasExplicitTemplateArgs()) {
- if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+ if (ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(),
+ E->template_arguments(), ToTAInfo))
return nullptr;
ResInfo = &ToTAInfo;
}
@@ -5926,11 +6065,10 @@ Expr *ASTNodeImporter::VisitUnresolvedLo
return nullptr;
}
- TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()),
- Importer.Import(E->getRAngleLoc()));
- TemplateArgumentListInfo *ResInfo = nullptr;
+ TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr;
if (E->hasExplicitTemplateArgs()) {
- if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+ if (ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(),
+ E->template_arguments(), ToTAInfo))
return nullptr;
ResInfo = &ToTAInfo;
}
@@ -5981,6 +6119,73 @@ Expr *ASTNodeImporter::VisitCallExpr(Cal
Importer.Import(E->getRParenLoc()));
}
+Optional<LambdaCapture>
+ASTNodeImporter::ImportLambdaCapture(const LambdaCapture &From) {
+ VarDecl *Var = nullptr;
+ if (From.capturesVariable()) {
+ Var = cast_or_null<VarDecl>(Importer.Import(From.getCapturedVar()));
+ if (!Var)
+ return None;
+ }
+
+ return LambdaCapture(Importer.Import(From.getLocation()), From.isImplicit(),
+ From.getCaptureKind(), Var,
+ From.isPackExpansion()
+ ? Importer.Import(From.getEllipsisLoc())
+ : SourceLocation());
+}
+
+Expr *ASTNodeImporter::VisitLambdaExpr(LambdaExpr *LE) {
+ CXXRecordDecl *FromClass = LE->getLambdaClass();
+ auto *ToClass = dyn_cast_or_null<CXXRecordDecl>(Importer.Import(FromClass));
+ if (!ToClass)
+ return nullptr;
+
+ // 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 *ToField = cast_or_null<FieldDecl>(Importer.Import(FromField));
+ if (!ToField)
+ return nullptr;
+ }
+ }
+
+ auto *ToCallOp = dyn_cast_or_null<CXXMethodDecl>(
+ Importer.Import(LE->getCallOperator()));
+ if (!ToCallOp)
+ return nullptr;
+
+ ToClass->completeDefinition();
+
+ unsigned NumCaptures = LE->capture_size();
+ SmallVector<LambdaCapture, 8> Captures;
+ Captures.reserve(NumCaptures);
+ for (const auto &FromCapture : LE->captures()) {
+ if (auto ToCapture = ImportLambdaCapture(FromCapture))
+ Captures.push_back(*ToCapture);
+ else
+ return nullptr;
+ }
+
+ SmallVector<Expr *, 8> InitCaptures(NumCaptures);
+ if (ImportContainerChecked(LE->capture_inits(), InitCaptures))
+ return nullptr;
+
+ return LambdaExpr::Create(Importer.getToContext(), ToClass,
+ Importer.Import(LE->getIntroducerRange()),
+ LE->getCaptureDefault(),
+ Importer.Import(LE->getCaptureDefaultLoc()),
+ Captures,
+ LE->hasExplicitParameters(),
+ LE->hasExplicitResultType(),
+ InitCaptures,
+ Importer.Import(LE->getLocEnd()),
+ LE->containsUnexpandedParameterPack());
+}
+
+
Expr *ASTNodeImporter::VisitInitListExpr(InitListExpr *ILE) {
QualType T = Importer.Import(ILE->getType());
if (T.isNull())
Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original)
+++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Fri Jan 26 03:36:54 2018
@@ -1153,12 +1153,22 @@ static bool IsStructurallyEquivalent(Str
D2->getTemplateParameters());
}
+static bool IsTemplateDeclCommonStructurallyEquivalent(
+ StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2) {
+ if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier()))
+ return false;
+ if (!D1->getIdentifier()) // Special name
+ if (D1->getNameAsString() != D2->getNameAsString())
+ return false;
+ return IsStructurallyEquivalent(Ctx, D1->getTemplateParameters(),
+ D2->getTemplateParameters());
+}
+
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
ClassTemplateDecl *D1,
ClassTemplateDecl *D2) {
// Check template parameters.
- if (!IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
- D2->getTemplateParameters()))
+ if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
return false;
// Check the templated declaration.
@@ -1166,6 +1176,18 @@ static bool IsStructurallyEquivalent(Str
D2->getTemplatedDecl());
}
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ FunctionTemplateDecl *D1,
+ FunctionTemplateDecl *D2) {
+ // Check template parameters.
+ if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
+ return false;
+
+ // Check the templated declaration.
+ return Context.IsStructurallyEquivalent(D1->getTemplatedDecl()->getType(),
+ D2->getTemplatedDecl()->getType());
+}
+
/// Determine structural equivalence of two declarations.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Decl *D1, Decl *D2) {
@@ -1293,6 +1315,7 @@ bool StructuralEquivalenceContext::Finis
// Record/non-record mismatch.
Equivalent = false;
}
+
} else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
// Check for equivalent enum names.
@@ -1309,6 +1332,7 @@ bool StructuralEquivalenceContext::Finis
// Enum/non-enum mismatch
Equivalent = false;
}
+
} else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) {
if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) {
if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
@@ -1320,17 +1344,30 @@ bool StructuralEquivalenceContext::Finis
// Typedef/non-typedef mismatch.
Equivalent = false;
}
+
} else if (ClassTemplateDecl *ClassTemplate1 =
dyn_cast<ClassTemplateDecl>(D1)) {
if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) {
- if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(),
- ClassTemplate2->getIdentifier()) ||
- !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2))
+ if (!::IsStructurallyEquivalent(*this, ClassTemplate1,
+ ClassTemplate2))
Equivalent = false;
} else {
// Class template/non-class-template mismatch.
Equivalent = false;
}
+
+ } else if (FunctionTemplateDecl *FunctionTemplate1 =
+ dyn_cast<FunctionTemplateDecl>(D1)) {
+ if (FunctionTemplateDecl *FunctionTemplate2 =
+ dyn_cast<FunctionTemplateDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, FunctionTemplate1,
+ FunctionTemplate2))
+ Equivalent = false;
+ } else {
+ // Class template/non-class-template mismatch.
+ Equivalent = false;
+ }
+
} else if (TemplateTypeParmDecl *TTP1 =
dyn_cast<TemplateTypeParmDecl>(D1)) {
if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
@@ -1350,6 +1387,7 @@ bool StructuralEquivalenceContext::Finis
// Kind mismatch.
Equivalent = false;
}
+
} else if (TemplateTemplateParmDecl *TTP1 =
dyn_cast<TemplateTemplateParmDecl>(D1)) {
if (TemplateTemplateParmDecl *TTP2 =
Modified: cfe/trunk/lib/AST/ExternalASTMerger.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExternalASTMerger.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExternalASTMerger.cpp (original)
+++ cfe/trunk/lib/AST/ExternalASTMerger.cpp Fri Jan 26 03:36:54 2018
@@ -16,6 +16,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExternalASTMerger.h"
using namespace clang;
@@ -351,6 +352,27 @@ void ExternalASTMerger::RemoveSources(ll
}
}
+template <typename DeclTy>
+static bool importSpecializations(DeclTy *D, ASTImporter *Importer) {
+ for (auto *Spec : D->specializations())
+ if (!Importer->Import(Spec))
+ return true;
+ return false;
+}
+
+/// Imports specializations from template declarations that can be specialized.
+static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) {
+ if (!isa<TemplateDecl>(D))
+ return false;
+ if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D))
+ return importSpecializations(FunctionTD, Importer);
+ else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D))
+ return importSpecializations(ClassTD, Importer);
+ else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D))
+ return importSpecializations(VarTD, Importer);
+ return false;
+}
+
bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
llvm::SmallVector<NamedDecl *, 1> Decls;
@@ -376,9 +398,17 @@ bool ExternalASTMerger::FindExternalVisi
Decls.reserve(Candidates.size());
for (const Candidate &C : Candidates) {
- NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get()));
- assert(d);
- Decls.push_back(d);
+ Decl *LookupRes = C.first.get();
+ ASTImporter *Importer = C.second;
+ NamedDecl *ND = cast_or_null<NamedDecl>(Importer->Import(LookupRes));
+ assert(ND);
+ // If we don't import specialization, they are not available via lookup
+ // because the lookup result is imported TemplateDecl and it does not
+ // reference its specializations until they are imported explicitly.
+ bool IsSpecImportFailed =
+ importSpecializationsIfNeeded(LookupRes, Importer);
+ assert(!IsSpecImportFailed);
+ Decls.push_back(ND);
}
SetExternalVisibleDeclsForName(DC, Name, Decls);
return true;
Modified: cfe/trunk/test/ASTMerge/class-template/Inputs/class-template1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/class-template/Inputs/class-template1.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/class-template/Inputs/class-template1.cpp (original)
+++ cfe/trunk/test/ASTMerge/class-template/Inputs/class-template1.cpp Fri Jan 26 03:36:54 2018
@@ -1,5 +1,7 @@
template<typename T>
-struct X0;
+struct X0 {
+ T getValue(T arg) { return arg; }
+};
template<int I>
struct X1;
@@ -26,6 +28,7 @@ extern X0<float> *x0r;
template<>
struct X0<char> {
int member;
+ char getValue(char ch) { return static_cast<char>(member); }
};
template<>
Modified: cfe/trunk/test/ASTMerge/class-template/Inputs/class-template2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/class-template/Inputs/class-template2.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/class-template/Inputs/class-template2.cpp (original)
+++ cfe/trunk/test/ASTMerge/class-template/Inputs/class-template2.cpp Fri Jan 26 03:36:54 2018
@@ -1,5 +1,7 @@
template<class T>
-struct X0;
+struct X0 {
+ T getValue(T arg);
+};
template<int I>
struct X1;
Modified: cfe/trunk/test/ASTMerge/class-template/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/class-template/test.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/class-template/test.cpp (original)
+++ cfe/trunk/test/ASTMerge/class-template/test.cpp Fri Jan 26 03:36:54 2018
@@ -1,24 +1,28 @@
-// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class-template1.cpp
-// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/class-template2.cpp
-// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/class-template1.cpp
+// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.2.ast %S/Inputs/class-template2.cpp
+// RUN: not %clang_cc1 -std=c++1z -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
-// CHECK: class-template1.cpp:7:14: error: non-type template parameter declared with incompatible types in different translation units ('int' vs. 'long')
-// CHECK: class-template2.cpp:7:15: note: declared here with type 'long'
+static_assert(sizeof(X0<char>().getValue(1)) == sizeof(char));
+static_assert(sizeof(X0<int>().getValue(1)) == sizeof(int));
-// CHECK: class-template1.cpp:10:14: error: template parameter has different kinds in different translation units
-// CHECK: class-template2.cpp:10:10: note: template parameter declared here
+// CHECK: class-template1.cpp:9:14: error: non-type template parameter declared with incompatible types in different translation units ('int' vs. 'long')
+// CHECK: class-template2.cpp:9:15: note: declared here with type 'long'
-// CHECK: class-template1.cpp:16:23: error: non-type template parameter declared with incompatible types in different translation units ('long' vs. 'int')
-// CHECK: class-template2.cpp:16:23: note: declared here with type 'int'
+// CHECK: class-template1.cpp:12:14: error: template parameter has different kinds in different translation units
+// CHECK: class-template2.cpp:12:10: note: template parameter declared here
-// CHECK: class-template1.cpp:19:10: error: template parameter has different kinds in different translation units
-// CHECK: class-template2.cpp:19:10: note: template parameter declared here
+// CHECK: class-template1.cpp:18:23: error: non-type template parameter declared with incompatible types in different translation units ('long' vs. 'int')
+// CHECK: class-template2.cpp:18:23: note: declared here with type 'int'
-// CHECK: class-template2.cpp:25:20: error: external variable 'x0r' declared with incompatible types in different translation units ('X0<double> *' vs. 'X0<float> *')
-// CHECK: class-template1.cpp:24:19: note: declared here with type 'X0<float> *'
+// CHECK: class-template1.cpp:21:10: error: template parameter has different kinds in different translation units
+// CHECK: class-template2.cpp:21:10: note: template parameter declared here
-// CHECK: class-template1.cpp:32:8: warning: type 'X0<wchar_t>' has incompatible definitions in different translation units
-// CHECK: class-template1.cpp:33:7: note: field 'member' has type 'int' here
-// CHECK: class-template2.cpp:34:9: note: field 'member' has type 'float' here
+// CHECK: class-template2.cpp:27:20: error: external variable 'x0r' declared with incompatible types in different translation units ('X0<double> *' vs. 'X0<float> *')
+// CHECK: class-template1.cpp:26:19: note: declared here with type 'X0<float> *'
+
+// CHECK: class-template1.cpp:35:8: warning: type 'X0<wchar_t>' has incompatible definitions in different translation units
+// CHECK: class-template1.cpp:36:7: note: field 'member' has type 'int' here
+// CHECK: class-template2.cpp:36:9: note: field 'member' has type 'float' here
// CHECK: 1 warning and 5 errors generated.
+// CHECK-NOT: static_assert
Modified: cfe/trunk/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp (original)
+++ cfe/trunk/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp Fri Jan 26 03:36:54 2018
@@ -122,3 +122,20 @@ void useTemplateType() {
const bool ExpressionTrait = __is_lvalue_expr(1);
const unsigned ArrayRank = __array_rank(int[10][20]);
const unsigned ArrayExtent = __array_extent(int[10][20], 1);
+
+constexpr int testLambdaAdd(int toAdd) {
+ const int Captured1 = 1, Captured2 = 2;
+ constexpr auto LambdaAdd = [Captured1, Captured2](int k) -> int {
+ return Captured1 + Captured2 + k;
+ };
+ return LambdaAdd(toAdd);
+}
+
+template<typename T>
+struct TestLambdaTemplate {
+ T i, j;
+ TestLambdaTemplate(T i, const T &j) : i(i), j(j) {}
+ T testLambda(T k) {
+ return [this](T k) -> decltype(auto) { return i + j + k; }(k);
+ }
+};
Modified: cfe/trunk/test/ASTMerge/exprs-cpp/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/exprs-cpp/test.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/exprs-cpp/test.cpp (original)
+++ cfe/trunk/test/ASTMerge/exprs-cpp/test.cpp Fri Jan 26 03:36:54 2018
@@ -30,6 +30,8 @@ static_assert(ExpressionTrait == false);
static_assert(ArrayRank == 2);
static_assert(ArrayExtent == 20);
+static_assert(testLambdaAdd(3) == 6);
+
void testImport(int *x, const S1 &cs1, S1 &s1) {
testNewThrowDelete();
testArrayElement(nullptr, 12);
@@ -44,4 +46,5 @@ void testImport(int *x, const S1 &cs1, S
testDefaultArg();
testDefaultArgExpr();
useTemplateType();
+ TestLambdaTemplate<int>(1, 2).testLambda(3);
}
Added: cfe/trunk/test/ASTMerge/function-cpp/Inputs/function-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/function-cpp/Inputs/function-1.cpp?rev=323519&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/function-cpp/Inputs/function-1.cpp (added)
+++ cfe/trunk/test/ASTMerge/function-cpp/Inputs/function-1.cpp Fri Jan 26 03:36:54 2018
@@ -0,0 +1,8 @@
+
+template<typename T> constexpr T add(T arg1, T arg2) {
+ return arg1 + arg2;
+}
+
+template<> constexpr int add(int arg1, int arg2) {
+ return arg1 + arg2 + 2;
+}
Added: cfe/trunk/test/ASTMerge/function-cpp/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/function-cpp/test.cpp?rev=323519&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/function-cpp/test.cpp (added)
+++ cfe/trunk/test/ASTMerge/function-cpp/test.cpp Fri Jan 26 03:36:54 2018
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/function-1.cpp
+// RUN: %clang_cc1 -std=c++1z -ast-merge %t.1.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// XFAIL: *
+
+static_assert(add(1, 2) == 5);
+
+// FIXME: support of templated function overload is still not implemented.
+static_assert(add('\1', '\2') == 3);
+
+// CHECK-NOT: static_assert
Modified: cfe/trunk/test/Import/template-specialization/Inputs/T.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/template-specialization/Inputs/T.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/test/Import/template-specialization/Inputs/T.cpp (original)
+++ cfe/trunk/test/Import/template-specialization/Inputs/T.cpp Fri Jan 26 03:36:54 2018
@@ -12,3 +12,7 @@ template <> struct A<bool> {
int g;
};
};
+
+
+template <typename T> constexpr int f() { return 0; }
+template <> constexpr int f<int>() { return 4; }
Modified: cfe/trunk/test/Import/template-specialization/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/template-specialization/test.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/test/Import/template-specialization/test.cpp (original)
+++ cfe/trunk/test/Import/template-specialization/test.cpp Fri Jan 26 03:36:54 2018
@@ -1,7 +1,10 @@
// RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s
-// XFAIL: *
+
void expr() {
A<int>::B b1;
A<bool>::B b2;
b1.f + b2.g;
}
+
+static_assert(f<char>() == 0, "");
+static_assert(f<int>() == 4, "");
Modified: cfe/trunk/unittests/AST/ASTImporterTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterTest.cpp?rev=323519&r1=323518&r2=323519&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/ASTImporterTest.cpp (original)
+++ cfe/trunk/unittests/AST/ASTImporterTest.cpp Fri Jan 26 03:36:54 2018
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
+#include "MatchVerifier.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTImporter.h"
-#include "MatchVerifier.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/Tooling.h"
@@ -99,7 +99,11 @@ testImport(const std::string &FromCode,
if (FoundDecls.size() != 1)
return testing::AssertionFailure() << "Multiple declarations were found!";
- auto Imported = Importer.Import(*FoundDecls.begin());
+ // Sanity check: the node being imported should match in the same way as
+ // the result node.
+ EXPECT_TRUE(Verifier.match(FoundDecls.front(), AMatcher));
+
+ auto Imported = Importer.Import(FoundDecls.front());
if (!Imported)
return testing::AssertionFailure() << "Import failed, nullptr returned!";
@@ -624,7 +628,7 @@ TEST(ImportExpr, ImportCXXPseudoDestruct
TEST(ImportDecl, ImportUsingDecl) {
MatchVerifier<Decl> Verifier;
testImport("namespace foo { int bar; }"
- "int declToImport(){ using foo::bar; }",
+ "void declToImport() { using foo::bar; }",
Lang_CXX, "", Lang_CXX, Verifier,
functionDecl(
has(
@@ -665,13 +669,13 @@ TEST(ImportExpr, ImportUnresolvedLookupE
"}"
"void instantiate() { declToImport<int>(); }",
Lang_CXX, "", Lang_CXX, Verifier,
- functionTemplateDecl(has(functionDecl(has(
- compoundStmt(has(unresolvedLookupExpr())))))));
+ functionTemplateDecl(has(functionDecl(
+ has(compoundStmt(has(unresolvedLookupExpr())))))));
}
TEST(ImportExpr, ImportCXXUnresolvedConstructExpr) {
MatchVerifier<Decl> Verifier;
- testImport("template <typename T> class C { T t; };"
+ testImport("template <typename T> struct C { T t; };"
"template <typename T> void declToImport() {"
" C<T> d;"
" d.t = T();"
@@ -680,7 +684,7 @@ TEST(ImportExpr, ImportCXXUnresolvedCons
Lang_CXX, "", Lang_CXX, Verifier,
functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
binaryOperator(has(cxxUnresolvedConstructExpr())))))))));
- testImport("template <typename T> class C { T t; };"
+ testImport("template <typename T> struct C { T t; };"
"template <typename T> void declToImport() {"
" C<T> d;"
" (&d)->t = T();"
@@ -691,5 +695,22 @@ TEST(ImportExpr, ImportCXXUnresolvedCons
binaryOperator(has(cxxUnresolvedConstructExpr())))))))));
}
+/// Check that function "declToImport()" (which is the templated function
+/// for corresponding FunctionTemplateDecl) is not added into DeclContext.
+/// Same for class template declarations.
+TEST(ImportDecl, ImportTemplatedDeclForTemplate) {
+ MatchVerifier<Decl> Verifier;
+ testImport("template <typename T> void declToImport() { T a = 1; }"
+ "void instantiate() { declToImport<int>(); }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(hasAncestor(translationUnitDecl(
+ unless(has(functionDecl(hasName("declToImport"))))))));
+ testImport("template <typename T> struct declToImport { T t; };"
+ "void instantiate() { declToImport<int>(); }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ classTemplateDecl(hasAncestor(translationUnitDecl(
+ unless(has(cxxRecordDecl(hasName("declToImport"))))))));
+}
+
} // end namespace ast_matchers
} // end namespace clang
More information about the cfe-commits
mailing list