diff options
Diffstat (limited to 'lib')
947 files changed, 65563 insertions, 29717 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index 6da87903a488..568e06f21fba 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -1,9 +1,8 @@ //===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -36,10 +35,10 @@ bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, while (I != List.end()) { FullSourceLoc diagLoc = I->getLocation(); if ((IDs.empty() || // empty means clear all diagnostics in the range. - std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && + llvm::is_contained(IDs, I->getID())) && !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && (diagLoc == range.getEnd() || - diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { + diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { cleared = true; ListTy::iterator eraseS = I++; if (eraseS->getLevel() != DiagnosticsEngine::Note) @@ -65,10 +64,10 @@ bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, while (I != List.end()) { FullSourceLoc diagLoc = I->getLocation(); if ((IDs.empty() || // empty means any diagnostic in the range. - std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && + llvm::find(IDs, I->getID()) != IDs.end()) && !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && (diagLoc == range.getEnd() || - diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { + diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { return true; } @@ -515,7 +514,7 @@ MigrationProcess::MigrationProcess( IntrusiveRefCntPtr<DiagnosticsEngine> Diags( new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient, /*ShouldOwnClient=*/false)); - Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); + Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanged=*/true); } } diff --git a/lib/ARCMigrate/ARCMTActions.cpp b/lib/ARCMigrate/ARCMTActions.cpp index 0a5473ab19ec..d72f53806e37 100644 --- a/lib/ARCMigrate/ARCMTActions.cpp +++ b/lib/ARCMigrate/ARCMTActions.cpp @@ -1,9 +1,8 @@ //===--- ARCMTActions.cpp - ARC Migrate Tool Frontend Actions ---*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp index 225f47119b00..1a4862d09aa6 100644 --- a/lib/ARCMigrate/FileRemapper.cpp +++ b/lib/ARCMigrate/FileRemapper.cpp @@ -1,9 +1,8 @@ //===--- FileRemapper.cpp - File Remapping Helper -------------------------===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h index 1a261c1e31aa..47fc09317500 100644 --- a/lib/ARCMigrate/Internals.h +++ b/lib/ARCMigrate/Internals.h @@ -1,9 +1,8 @@ //===-- Internals.h - Implementation Details---------------------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 6950ce0e12f3..7126a0873ea0 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -1,13 +1,13 @@ //===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===// // -// 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 // //===----------------------------------------------------------------------===// #include "Transforms.h" +#include "clang/Analysis/RetainSummaryManager.h" #include "clang/ARCMigrate/ARCMT.h" #include "clang/ARCMigrate/ARCMTActions.h" #include "clang/AST/ASTConsumer.h" @@ -27,7 +27,6 @@ #include "clang/Lex/PPConditionalDirectiveRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Rewrite/Core/Rewriter.h" -#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Path.h" @@ -65,9 +64,11 @@ class ObjCMigrateASTConsumer : public ASTConsumer { ObjCInstanceTypeFamily OIT_Family = OIT_None); void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl); - void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, + void AddCFAnnotations(ASTContext &Ctx, + const RetainSummary *RS, const FunctionDecl *FuncDecl, bool ResultAnnotated); - void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, + void AddCFAnnotations(ASTContext &Ctx, + const RetainSummary *RS, const ObjCMethodDecl *MethodDecl, bool ResultAnnotated); void AnnotateImplicitBridging(ASTContext &Ctx); @@ -85,6 +86,8 @@ class ObjCMigrateASTConsumer : public ASTConsumer { bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc); + std::unique_ptr<RetainSummaryManager> Summaries; + public: std::string MigrateDir; unsigned ASTMigrateActions; @@ -103,6 +106,14 @@ public: llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates; llvm::StringSet<> WhiteListFilenames; + RetainSummaryManager &getSummaryManager(ASTContext &Ctx) { + if (!Summaries) + Summaries.reset(new RetainSummaryManager(Ctx, + /*TrackNSCFObjects=*/true, + /*trackOSObjects=*/false)); + return *Summaries; + } + ObjCMigrateASTConsumer(StringRef migrateDir, unsigned astMigrateActions, FileRemapper &remapper, @@ -205,7 +216,7 @@ ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(), - /*ignoreIfFilesChanges=*/true); + /*ignoreIfFilesChanged=*/true); CompInst = &CI; CI.getDiagnostics().setIgnoreAllWarnings(true); return true; @@ -1453,12 +1464,12 @@ void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *De } void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, - const CallEffects &CE, + const RetainSummary *RS, const FunctionDecl *FuncDecl, bool ResultAnnotated) { // Annotate function. if (!ResultAnnotated) { - RetEffect Ret = CE.getReturnValue(); + RetEffect Ret = RS->getRetEffect(); const char *AnnotationString = nullptr; if (Ret.getObjKind() == ObjKind::CF) { if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED")) @@ -1478,12 +1489,11 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, Editor->commit(commit); } } - ArrayRef<ArgEffect> AEArgs = CE.getArgs(); unsigned i = 0; for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; - ArgEffect AE = AEArgs[i]; + ArgEffect AE = RS->getArg(i); if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF && !pd->hasAttr<CFConsumedAttr>() && NSAPIObj->isMacroDefined("CF_CONSUMED")) { @@ -1507,7 +1517,8 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND if (FuncDecl->hasBody()) return CF_BRIDGING_NONE; - CallEffects CE = CallEffects::getEffect(FuncDecl); + const RetainSummary *RS = + getSummaryManager(Ctx).getSummary(AnyCall(FuncDecl)); bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() || FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() || FuncDecl->hasAttr<NSReturnsRetainedAttr>() || @@ -1520,7 +1531,7 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND bool ReturnCFAudited = false; if (!FuncIsReturnAnnotated) { - RetEffect Ret = CE.getReturnValue(); + RetEffect Ret = RS->getRetEffect(); if (Ret.getObjKind() == ObjKind::CF && (Ret.isOwned() || Ret.notOwned())) ReturnCFAudited = true; @@ -1529,14 +1540,12 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND } // At this point result type is audited for potential inclusion. - // Now, how about argument types. - ArrayRef<ArgEffect> AEArgs = CE.getArgs(); unsigned i = 0; bool ArgCFAudited = false; for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; - ArgEffect AE = AEArgs[i]; + ArgEffect AE = RS->getArg(i); if ((AE.getKind() == DecRef /*CFConsumed annotated*/ || AE.getKind() == IncRef) && AE.getObjKind() == ObjKind::CF) { if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) @@ -1546,7 +1555,7 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND } else { QualType AT = pd->getType(); if (!AuditedType(AT)) { - AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated); + AddCFAnnotations(Ctx, RS, FuncDecl, FuncIsReturnAnnotated); return CF_BRIDGING_NONE; } } @@ -1568,12 +1577,12 @@ void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx, } void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, - const CallEffects &CE, + const RetainSummary *RS, const ObjCMethodDecl *MethodDecl, bool ResultAnnotated) { // Annotate function. if (!ResultAnnotated) { - RetEffect Ret = CE.getReturnValue(); + RetEffect Ret = RS->getRetEffect(); const char *AnnotationString = nullptr; if (Ret.getObjKind() == ObjKind::CF) { if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED")) @@ -1605,12 +1614,11 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, Editor->commit(commit); } } - ArrayRef<ArgEffect> AEArgs = CE.getArgs(); unsigned i = 0; for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; - ArgEffect AE = AEArgs[i]; + ArgEffect AE = RS->getArg(i); if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF && !pd->hasAttr<CFConsumedAttr>() && @@ -1628,7 +1636,9 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( if (MethodDecl->hasBody() || MethodDecl->isImplicit()) return; - CallEffects CE = CallEffects::getEffect(MethodDecl); + const RetainSummary *RS = + getSummaryManager(Ctx).getSummary(AnyCall(MethodDecl)); + bool MethodIsReturnAnnotated = (MethodDecl->hasAttr<CFReturnsRetainedAttr>() || MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() || @@ -1636,7 +1646,7 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() || MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>()); - if (CE.getReceiver().getKind() == DecRef && + if (RS->getReceiverEffect().getKind() == DecRef && !MethodDecl->hasAttr<NSConsumesSelfAttr>() && MethodDecl->getMethodFamily() != OMF_init && MethodDecl->getMethodFamily() != OMF_release && @@ -1652,27 +1662,25 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( return; if (!MethodIsReturnAnnotated) { - RetEffect Ret = CE.getReturnValue(); + RetEffect Ret = RS->getRetEffect(); if ((Ret.getObjKind() == ObjKind::CF || Ret.getObjKind() == ObjKind::ObjC) && (Ret.isOwned() || Ret.notOwned())) { - AddCFAnnotations(Ctx, CE, MethodDecl, false); + AddCFAnnotations(Ctx, RS, MethodDecl, false); return; } else if (!AuditedType(MethodDecl->getReturnType())) return; } // At this point result type is either annotated or audited. - // Now, how about argument types. - ArrayRef<ArgEffect> AEArgs = CE.getArgs(); unsigned i = 0; for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { const ParmVarDecl *pd = *pi; - ArgEffect AE = AEArgs[i]; + ArgEffect AE = RS->getArg(i); if ((AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) || AE.getKind() == IncRef || !AuditedType(pd->getType())) { - AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated); + AddCFAnnotations(Ctx, RS, MethodDecl, MethodIsReturnAnnotated); return; } } diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp index 9e4cb3f4cd83..6d7fcb053b48 100644 --- a/lib/ARCMigrate/PlistReporter.cpp +++ b/lib/ARCMigrate/PlistReporter.cpp @@ -1,9 +1,8 @@ //===--- PlistReporter.cpp - ARC Migrate Tool Plist Reporter ----*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// @@ -121,5 +120,5 @@ void arcmt::writeARCDiagsToPlist(const std::string &outPath, o << " </array>\n"; // Finish. - o << "</dict>\n</plist>"; + o << "</dict>\n</plist>\n"; } diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp index 6146e07b1d2a..638850dcf9ec 100644 --- a/lib/ARCMigrate/TransAPIUses.cpp +++ b/lib/ARCMigrate/TransAPIUses.cpp @@ -1,9 +1,8 @@ //===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp index d2b4de4891c3..d1d5b9e014b1 100644 --- a/lib/ARCMigrate/TransARCAssign.cpp +++ b/lib/ARCMigrate/TransARCAssign.cpp @@ -1,9 +1,8 @@ //===--- TransARCAssign.cpp - Transformations to ARC mode -----------------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp index 9d20774a89a6..393adcd85a3f 100644 --- a/lib/ARCMigrate/TransAutoreleasePool.cpp +++ b/lib/ARCMigrate/TransAutoreleasePool.cpp @@ -1,9 +1,8 @@ //===--- TransAutoreleasePool.cpp - Transformations to ARC mode -----------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp index 85bdabb50461..1e4db33135b6 100644 --- a/lib/ARCMigrate/TransBlockObjCVariable.cpp +++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp @@ -1,9 +1,8 @@ //===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp index 0327b0def1e6..5d0cfb8a8b9c 100644 --- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp +++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp @@ -1,9 +1,8 @@ -//===--- TransEmptyStatements.cpp - Transformations to ARC mode -----------===// +//===-- TransEmptyStatementsAndDealloc.cpp - Transformations to ARC mode --===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -43,9 +42,8 @@ static bool isEmptyARCMTMacroStatement(NullStmt *S, return false; SourceManager &SM = Ctx.getSourceManager(); - std::vector<SourceLocation>::iterator - I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc, - BeforeThanCompare<SourceLocation>(SM)); + std::vector<SourceLocation>::iterator I = llvm::upper_bound( + MacroLocs, SemiLoc, BeforeThanCompare<SourceLocation>(SM)); --I; SourceLocation AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size()); diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp index 7697d3f048e6..5e3162197ed1 100644 --- a/lib/ARCMigrate/TransGCAttrs.cpp +++ b/lib/ARCMigrate/TransGCAttrs.cpp @@ -1,9 +1,8 @@ //===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -69,6 +68,9 @@ public: if (handleAttr(Attr, D)) break; TL = Attr.getModifiedLoc(); + } else if (MacroQualifiedTypeLoc MDTL = + TL.getAs<MacroQualifiedTypeLoc>()) { + TL = MDTL.getInnerLoc(); } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) { TL = Arr.getElementLoc(); } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) { @@ -267,7 +269,7 @@ static void checkAllAtProps(MigrationContext &MigrateCtx, StringRef toAttr = "strong"; if (hasWeak) { if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(), - /*AllowOnUnkwownClass=*/true)) + /*AllowOnUnknownClass=*/true)) toAttr = "weak"; else toAttr = "unsafe_unretained"; diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp index eff142ba3922..43233e2d0b45 100644 --- a/lib/ARCMigrate/TransGCCalls.cpp +++ b/lib/ARCMigrate/TransGCCalls.cpp @@ -1,9 +1,8 @@ //===--- TransGCCalls.cpp - Transformations to ARC mode -------------------===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp index 912f77aeb789..0675fb0baeb8 100644 --- a/lib/ARCMigrate/TransProperties.cpp +++ b/lib/ARCMigrate/TransProperties.cpp @@ -1,9 +1,8 @@ //===--- TransProperties.cpp - Transformations to ARC mode ----------------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/ARCMigrate/TransProtectedScope.cpp b/lib/ARCMigrate/TransProtectedScope.cpp index bfc542e7497c..9e9e9cb7a96d 100644 --- a/lib/ARCMigrate/TransProtectedScope.cpp +++ b/lib/ARCMigrate/TransProtectedScope.cpp @@ -1,9 +1,8 @@ //===--- TransProtectedScope.cpp - Transformations to ARC mode ------------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index d199bb936547..b76fc65574dd 100644 --- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -1,9 +1,8 @@ //===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -270,8 +269,8 @@ private: if (prevChildS != childE) { prevStmt = *prevChildS; - if (prevStmt) - prevStmt = prevStmt->IgnoreImplicit(); + if (auto *E = dyn_cast_or_null<Expr>(prevStmt)) + prevStmt = E->IgnoreImplicit(); } if (currChildS == childE) @@ -281,8 +280,8 @@ private: return std::make_pair(prevStmt, nextStmt); nextStmt = *currChildS; - if (nextStmt) - nextStmt = nextStmt->IgnoreImplicit(); + if (auto *E = dyn_cast_or_null<Expr>(nextStmt)) + nextStmt = E->IgnoreImplicit(); return std::make_pair(prevStmt, nextStmt); } diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp index 9d46d8c5fcae..e767ad5346c3 100644 --- a/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -1,9 +1,8 @@ //===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp index 70370ecc4e90..bac8dfac9b41 100644 --- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp +++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp @@ -1,9 +1,8 @@ //===--- TransUnusedInitDelegate.cpp - Transformations to ARC mode --------===// // -// 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 // //===----------------------------------------------------------------------===// // Transformations: diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp index 220102ec49ce..d28bd378acc1 100644 --- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp +++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp @@ -1,9 +1,8 @@ //===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp index d1768bc56cfc..2c48e479dce8 100644 --- a/lib/ARCMigrate/TransformActions.cpp +++ b/lib/ARCMigrate/TransformActions.cpp @@ -1,9 +1,8 @@ -//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// +//===-- TransformActions.cpp - Migration to ARC mode ----------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -314,7 +313,9 @@ void TransformActionsImpl::removeStmt(Stmt *S) { assert(IsInTransaction && "Actions only allowed during a transaction"); ActionData data; data.Kind = Act_RemoveStmt; - data.S = S->IgnoreImplicit(); // important for uniquing + if (auto *E = dyn_cast<Expr>(S)) + S = E->IgnoreImplicit(); // important for uniquing + data.S = S; CachedActions.push_back(data); } diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 8bd2b407aee9..59b80a917e56 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -1,9 +1,8 @@ //===--- Transforms.cpp - Transformations to ARC mode ---------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -287,10 +286,11 @@ private: void mark(Stmt *S) { if (!S) return; - while (LabelStmt *Label = dyn_cast<LabelStmt>(S)) + while (auto *Label = dyn_cast<LabelStmt>(S)) S = Label->getSubStmt(); - S = S->IgnoreImplicit(); - if (Expr *E = dyn_cast<Expr>(S)) + if (auto *E = dyn_cast<Expr>(S)) + S = E->IgnoreImplicit(); + if (auto *E = dyn_cast<Expr>(S)) Removables.insert(E); } }; diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index bafe9fc52a27..e087136f0e2c 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -1,9 +1,8 @@ //===-- Transforms.h - Transformations to ARC mode --------------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index c05b160b8e3d..1993bba9bd1a 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -1,9 +1,8 @@ //===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -21,6 +20,61 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +/// The identity of a type_info object depends on the canonical unqualified +/// type only. +TypeInfoLValue::TypeInfoLValue(const Type *T) + : T(T->getCanonicalTypeUnqualified().getTypePtr()) {} + +void TypeInfoLValue::print(llvm::raw_ostream &Out, + const PrintingPolicy &Policy) const { + Out << "typeid("; + QualType(getType(), 0).print(Out, Policy); + Out << ")"; +} + +static_assert( + 1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <= + alignof(Type), + "Type is insufficiently aligned"); + +APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V) + : Ptr(P), Local{I, V} {} +APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V) + : Ptr(P), Local{I, V} {} + +APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV, + QualType TypeInfo) { + LValueBase Base; + Base.Ptr = LV; + Base.TypeInfoType = TypeInfo.getAsOpaquePtr(); + return Base; +} + +unsigned APValue::LValueBase::getCallIndex() const { + return is<TypeInfoLValue>() ? 0 : Local.CallIndex; +} + +unsigned APValue::LValueBase::getVersion() const { + return is<TypeInfoLValue>() ? 0 : Local.Version; +} + +QualType APValue::LValueBase::getTypeInfoType() const { + assert(is<TypeInfoLValue>() && "not a type_info lvalue"); + return QualType::getFromOpaquePtr(TypeInfoType); +} + +namespace clang { +bool operator==(const APValue::LValueBase &LHS, + const APValue::LValueBase &RHS) { + if (LHS.Ptr != RHS.Ptr) + return false; + if (LHS.is<TypeInfoLValue>()) + return true; + return LHS.Local.CallIndex == RHS.Local.CallIndex && + LHS.Local.Version == RHS.Local.Version; +} +} + namespace { struct LVBase { APValue::LValueBase Base; @@ -46,26 +100,27 @@ APValue::LValueBase::operator bool () const { clang::APValue::LValueBase llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() { return clang::APValue::LValueBase( - DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getEmptyKey(), - DenseMapInfo<unsigned>::getEmptyKey(), - DenseMapInfo<unsigned>::getEmptyKey()); + DenseMapInfo<const ValueDecl*>::getEmptyKey()); } clang::APValue::LValueBase llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() { return clang::APValue::LValueBase( - DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getTombstoneKey(), - DenseMapInfo<unsigned>::getTombstoneKey(), - DenseMapInfo<unsigned>::getTombstoneKey()); + DenseMapInfo<const ValueDecl*>::getTombstoneKey()); +} + +namespace clang { +llvm::hash_code hash_value(const APValue::LValueBase &Base) { + if (Base.is<TypeInfoLValue>()) + return llvm::hash_value(Base.getOpaqueValue()); + return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(), + Base.getVersion()); +} } unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue( const clang::APValue::LValueBase &Base) { - llvm::FoldingSetNodeID ID; - ID.AddPointer(Base.getOpaqueValue()); - ID.AddInteger(Base.getCallIndex()); - ID.AddInteger(Base.getVersion()); - return ID.ComputeHash(); + return hash_value(Base); } bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual( @@ -164,9 +219,11 @@ APValue::UnionData::~UnionData () { delete Value; } -APValue::APValue(const APValue &RHS) : Kind(Uninitialized) { +APValue::APValue(const APValue &RHS) : Kind(None) { switch (RHS.getKind()) { - case Uninitialized: + case None: + case Indeterminate: + Kind = RHS.getKind(); break; case Int: MakeInt(); @@ -176,6 +233,11 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) { MakeFloat(); setFloat(RHS.getFloat()); break; + case FixedPoint: { + APFixedPoint FXCopy = RHS.getFixedPoint(); + MakeFixedPoint(std::move(FXCopy)); + break; + } case Vector: MakeVector(); setVector(((const Vec *)(const char *)RHS.Data.buffer)->Elts, @@ -233,6 +295,8 @@ void APValue::DestroyDataAndMakeUninit() { ((APSInt*)(char*)Data.buffer)->~APSInt(); else if (Kind == Float) ((APFloat*)(char*)Data.buffer)->~APFloat(); + else if (Kind == FixedPoint) + ((APFixedPoint *)(char *)Data.buffer)->~APFixedPoint(); else if (Kind == Vector) ((Vec*)(char*)Data.buffer)->~Vec(); else if (Kind == ComplexInt) @@ -251,12 +315,13 @@ void APValue::DestroyDataAndMakeUninit() { ((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData(); else if (Kind == AddrLabelDiff) ((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData(); - Kind = Uninitialized; + Kind = None; } bool APValue::needsCleanup() const { switch (getKind()) { - case Uninitialized: + case None: + case Indeterminate: case AddrLabelDiff: return false; case Struct: @@ -268,6 +333,8 @@ bool APValue::needsCleanup() const { return getInt().needsCleanup(); case Float: return getFloat().needsCleanup(); + case FixedPoint: + return getFixedPoint().getValue().needsCleanup(); case ComplexFloat: assert(getComplexFloatImag().needsCleanup() == getComplexFloatReal().needsCleanup() && @@ -312,8 +379,11 @@ static double GetApproxValue(const llvm::APFloat &F) { void APValue::dump(raw_ostream &OS) const { switch (getKind()) { - case Uninitialized: - OS << "Uninitialized"; + case None: + OS << "None"; + return; + case Indeterminate: + OS << "Indeterminate"; return; case Int: OS << "Int: " << getInt(); @@ -321,6 +391,9 @@ void APValue::dump(raw_ostream &OS) const { case Float: OS << "Float: " << GetApproxValue(getFloat()); return; + case FixedPoint: + OS << "FixedPoint : " << getFixedPoint(); + return; case Vector: OS << "Vector: "; getVectorElt(0).dump(OS); @@ -383,9 +456,13 @@ void APValue::dump(raw_ostream &OS) const { llvm_unreachable("Unknown APValue kind!"); } -void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ +void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, + QualType Ty) const { switch (getKind()) { - case APValue::Uninitialized: + case APValue::None: + Out << "<out of lifetime>"; + return; + case APValue::Indeterminate: Out << "<uninitialized>"; return; case APValue::Int: @@ -397,6 +474,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ case APValue::Float: Out << GetApproxValue(getFloat()); return; + case APValue::FixedPoint: + Out << getFixedPoint(); + return; case APValue::Vector: { Out << '{'; QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); @@ -453,7 +533,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) Out << *VD; - else { + else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { + TI.print(Out, Ctx.getPrintingPolicy()); + } else { assert(Base.get<const Expr *>() != nullptr && "Expecting non-null Expr"); Base.get<const Expr*>()->printPretty(Out, nullptr, @@ -478,6 +560,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { Out << *VD; ElemTy = VD->getType(); + } else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { + TI.print(Out, Ctx.getPrintingPolicy()); + ElemTy = Base.getTypeInfoType(); } else { const Expr *E = Base.get<const Expr*>(); assert(E != nullptr && "Expecting non-null Expr"); @@ -491,8 +576,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (ElemTy->getAs<RecordType>()) { // The lvalue refers to a class type, so the next path entry is a base // or member. - const Decl *BaseOrMember = - BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).getPointer(); + const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer(); if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { CastToBase = RD; ElemTy = Ctx.getRecordType(RD); @@ -506,7 +590,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ } } else { // The lvalue must refer to an array. - Out << '[' << Path[I].ArrayIndex << ']'; + Out << '[' << Path[I].getAsArrayIndex() << ']'; ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); } } @@ -592,7 +676,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ llvm_unreachable("Unknown APValue kind!"); } -std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const { +std::string APValue::getAsString(const ASTContext &Ctx, QualType Ty) const { std::string Result; llvm::raw_string_ostream Out(Result); printPretty(Out, Ctx, Ty); @@ -600,6 +684,26 @@ std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const { return Result; } +bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy, + const ASTContext &Ctx) const { + if (isInt()) { + Result = getInt(); + return true; + } + + if (isLValue() && isNullPointer()) { + Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy); + return true; + } + + if (isLValue() && !getLValueBase()) { + Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy); + return true; + } + + return false; +} + const APValue::LValueBase APValue::getLValueBase() const { assert(isLValue() && "Invalid accessor"); return ((const LV*)(const void*)Data.buffer)->Base; @@ -687,21 +791,21 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const { } void APValue::MakeLValue() { - assert(isUninit() && "Bad state change"); + assert(isAbsent() && "Bad state change"); static_assert(sizeof(LV) <= DataSize, "LV too big"); new ((void*)(char*)Data.buffer) LV(); Kind = LValue; } void APValue::MakeArray(unsigned InitElts, unsigned Size) { - assert(isUninit() && "Bad state change"); + assert(isAbsent() && "Bad state change"); new ((void*)(char*)Data.buffer) Arr(InitElts, Size); Kind = Array; } void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, ArrayRef<const CXXRecordDecl*> Path) { - assert(isUninit() && "Bad state change"); + assert(isAbsent() && "Bad state change"); MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData; Kind = MemberPointer; MPD->MemberAndIsDerivedMember.setPointer(Member); diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp index 55033b238c66..6bba8f1f80a9 100644 --- a/lib/AST/ASTConsumer.cpp +++ b/lib/AST/ASTConsumer.cpp @@ -1,9 +1,8 @@ //===--- ASTConsumer.cpp - Abstract interface for reading ASTs --*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 21b6f36e9aa7..0d69eb90abaf 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1,9 +1,8 @@ //===- ASTContext.cpp - Context to hold long-lived AST nodes --------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -95,38 +94,18 @@ using namespace clang; -unsigned ASTContext::NumImplicitDefaultConstructors; -unsigned ASTContext::NumImplicitDefaultConstructorsDeclared; -unsigned ASTContext::NumImplicitCopyConstructors; -unsigned ASTContext::NumImplicitCopyConstructorsDeclared; -unsigned ASTContext::NumImplicitMoveConstructors; -unsigned ASTContext::NumImplicitMoveConstructorsDeclared; -unsigned ASTContext::NumImplicitCopyAssignmentOperators; -unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; -unsigned ASTContext::NumImplicitMoveAssignmentOperators; -unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; -unsigned ASTContext::NumImplicitDestructors; -unsigned ASTContext::NumImplicitDestructorsDeclared; - enum FloatingRank { Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank }; RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { - if (!CommentsLoaded && ExternalSource) { - ExternalSource->ReadComments(); - -#ifndef NDEBUG - ArrayRef<RawComment *> RawComments = Comments.getComments(); - assert(std::is_sorted(RawComments.begin(), RawComments.end(), - BeforeThanCompare<RawComment>(SourceMgr))); -#endif - - CommentsLoaded = true; - } - assert(D); + // If we already tried to load comments but there are none, + // we won't find anything. + if (CommentsLoaded && Comments.getComments().empty()) + return nullptr; + // User can not attach documentation to implicit declarations. if (D->isImplicit()) return nullptr; @@ -176,12 +155,6 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { isa<TemplateTemplateParmDecl>(D)) return nullptr; - ArrayRef<RawComment *> RawComments = Comments.getComments(); - - // If there are no comments anywhere, we won't find anything. - if (RawComments.empty()) - return nullptr; - // Find declaration location. // For Objective-C declarations we generally don't expect to have multiple // declarators, thus use declaration starting location as the "declaration @@ -220,6 +193,23 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (DeclLoc.isInvalid() || !DeclLoc.isFileID()) return nullptr; + if (!CommentsLoaded && ExternalSource) { + ExternalSource->ReadComments(); + +#ifndef NDEBUG + ArrayRef<RawComment *> RawComments = Comments.getComments(); + assert(std::is_sorted(RawComments.begin(), RawComments.end(), + BeforeThanCompare<RawComment>(SourceMgr))); +#endif + + CommentsLoaded = true; + } + + ArrayRef<RawComment *> RawComments = Comments.getComments(); + // If there are no comments anywhere, we won't find anything. + if (RawComments.empty()) + return nullptr; + // Find the comment that occurs just after this declaration. ArrayRef<RawComment *>::iterator Comment; { @@ -238,12 +228,11 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (Found) { Comment = MaybeBeforeDecl + 1; - assert(Comment == std::lower_bound(RawComments.begin(), RawComments.end(), - &CommentAtDeclLoc, Compare)); + assert(Comment == + llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare)); } else { // Slow path. - Comment = std::lower_bound(RawComments.begin(), RawComments.end(), - &CommentAtDeclLoc, Compare); + Comment = llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare); } } @@ -265,6 +254,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second) == SourceMgr.getLineNumber(CommentBeginDecomp.first, CommentBeginDecomp.second)) { + (**Comment).setAttached(); return *Comment; } } @@ -306,6 +296,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (Text.find_first_of(";{}#@") != StringRef::npos) return nullptr; + (**Comment).setAttached(); return *Comment; } @@ -835,6 +826,9 @@ ASTContext::~ASTContext() { for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); + + for (APValue *Value : APValueCleanups) + Value->~APValue(); } class ASTContext::ParentMap { @@ -913,7 +907,7 @@ void ASTContext::setTraversalScope(const std::vector<Decl *> &TopLevelDecls) { Parents.reset(); } -void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { +void ASTContext::AddDeallocation(void (*Callback)(void *), void *Data) const { Deallocations.push_back({Callback, Data}); } @@ -1391,24 +1385,6 @@ ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst, TemplateOrInstantiation[Inst] = TSI; } -FunctionDecl *ASTContext::getClassScopeSpecializationPattern( - const FunctionDecl *FD){ - assert(FD && "Specialization is 0"); - llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos - = ClassScopeSpecializationPattern.find(FD); - if (Pos == ClassScopeSpecializationPattern.end()) - return nullptr; - - return Pos->second; -} - -void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD, - FunctionDecl *Pattern) { - assert(FD && "Specialization is 0"); - assert(Pattern && "Class scope specialization pattern is 0"); - ClassScopeSpecializationPattern[FD] = Pattern; -} - NamedDecl * ASTContext::getInstantiatedFromUsingDecl(NamedDecl *UUD) { auto Pos = InstantiatedFromUsingDecl.find(UUD); @@ -1548,8 +1524,14 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { return Target->getHalfFormat(); case BuiltinType::Float: return Target->getFloatFormat(); case BuiltinType::Double: return Target->getDoubleFormat(); - case BuiltinType::LongDouble: return Target->getLongDoubleFormat(); - case BuiltinType::Float128: return Target->getFloat128Format(); + case BuiltinType::LongDouble: + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) + return AuxTarget->getLongDoubleFormat(); + return Target->getLongDoubleFormat(); + case BuiltinType::Float128: + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) + return AuxTarget->getFloat128Format(); + return Target->getFloat128Format(); } } @@ -1610,8 +1592,10 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { if (BaseT.getQualifiers().hasUnaligned()) Align = Target->getCharWidth(); if (const auto *VD = dyn_cast<VarDecl>(D)) { - if (VD->hasGlobalStorage() && !ForAlignof) - Align = std::max(Align, getTargetInfo().getMinGlobalAlign()); + if (VD->hasGlobalStorage() && !ForAlignof) { + uint64_t TypeSize = getTypeSize(T.getTypePtr()); + Align = std::max(Align, getTargetInfo().getMinGlobalAlign(TypeSize)); + } } } @@ -1916,8 +1900,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; case BuiltinType::Float16: case BuiltinType::Half: - Width = Target->getHalfWidth(); - Align = Target->getHalfAlign(); + if (Target->hasFloat16Type() || !getLangOpts().OpenMP || + !getLangOpts().OpenMPIsDevice) { + Width = Target->getHalfWidth(); + Align = Target->getHalfAlign(); + } else { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "Expected OpenMP device compilation."); + Width = AuxTarget->getHalfWidth(); + Align = AuxTarget->getHalfAlign(); + } break; case BuiltinType::Float: Width = Target->getFloatWidth(); @@ -1928,12 +1920,27 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Align = Target->getDoubleAlign(); break; case BuiltinType::LongDouble: - Width = Target->getLongDoubleWidth(); - Align = Target->getLongDoubleAlign(); + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + (Target->getLongDoubleWidth() != AuxTarget->getLongDoubleWidth() || + Target->getLongDoubleAlign() != AuxTarget->getLongDoubleAlign())) { + Width = AuxTarget->getLongDoubleWidth(); + Align = AuxTarget->getLongDoubleAlign(); + } else { + Width = Target->getLongDoubleWidth(); + Align = Target->getLongDoubleAlign(); + } break; case BuiltinType::Float128: - Width = Target->getFloat128Width(); - Align = Target->getFloat128Align(); + if (Target->hasFloat128Type() || !getLangOpts().OpenMP || + !getLangOpts().OpenMPIsDevice) { + Width = Target->getFloat128Width(); + Align = Target->getFloat128Align(); + } else { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "Expected OpenMP device compilation."); + Width = AuxTarget->getFloat128Width(); + Align = AuxTarget->getFloat128Align(); + } break; case BuiltinType::NullPtr: Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) @@ -2057,6 +2064,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Paren: return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr()); + case Type::MacroQualified: + return getTypeInfo( + cast<MacroQualifiedType>(T)->getUnderlyingType().getTypePtr()); + case Type::ObjCTypeParam: return getTypeInfo(cast<ObjCTypeParamType>(T)->desugar().getTypePtr()); @@ -2134,7 +2145,7 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const { const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); UnadjustedAlign = toBits(Layout.getUnadjustedAlignment()); } else { - UnadjustedAlign = getTypeAlign(T); + UnadjustedAlign = getTypeAlign(T->getUnqualifiedDesugaredType()); } MemoizedUnadjustedAlign[T] = UnadjustedAlign; @@ -2233,7 +2244,8 @@ unsigned ASTContext::getTargetDefaultAlignForAttributeAligned() const { /// getAlignOfGlobalVar - Return the alignment in bits that should be given /// to a global variable of the specified type. unsigned ASTContext::getAlignOfGlobalVar(QualType T) const { - return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign()); + uint64_t TypeSize = getTypeSize(T.getTypePtr()); + return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign(TypeSize)); } /// getAlignOfGlobalVarInChars - Return the alignment in characters that @@ -2574,7 +2586,7 @@ ASTContext::getBlockVarCopyInit(const VarDecl*VD) const { return {nullptr, false}; } -/// Set the copy inialization expression of a block var decl. +/// Set the copy initialization expression of a block var decl. void ASTContext::setBlockVarCopyInit(const VarDecl*VD, Expr *CopyExpr, bool CanThrow) { assert(VD && CopyExpr && "Passed null params"); @@ -2763,6 +2775,12 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec( return getParenType( getFunctionTypeWithExceptionSpec(PT->getInnerType(), ESI)); + // Might be wrapped in a macro qualified type. + if (const auto *MQT = dyn_cast<MacroQualifiedType>(Orig)) + return getMacroQualifiedType( + getFunctionTypeWithExceptionSpec(MQT->getUnderlyingType(), ESI), + MQT->getMacroIdentifier()); + // Might have a calling-convention attribute. if (const auto *AT = dyn_cast<AttributedType>(Orig)) return getAttributedType( @@ -2772,7 +2790,7 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec( // Anything else must be a function type. Rebuild it with the new exception // specification. - const auto *Proto = cast<FunctionProtoType>(Orig); + const auto *Proto = Orig->getAs<FunctionProtoType>(); return getFunctionType( Proto->getReturnType(), Proto->getParamTypes(), Proto->getExtProtoInfo().withExceptionSpec(ESI)); @@ -3739,7 +3757,10 @@ QualType ASTContext::getFunctionTypeInternal( break; } - case EST_DynamicNone: case EST_BasicNoexcept: case EST_NoexceptTrue: + case EST_DynamicNone: + case EST_BasicNoexcept: + case EST_NoexceptTrue: + case EST_NoThrow: CanonicalEPI.ExceptionSpec.Type = EST_BasicNoexcept; break; @@ -3938,7 +3959,7 @@ QualType ASTContext::getAttributedType(attr::Kind attrKind, QualType canon = getCanonicalType(equivalentType); type = new (*this, TypeAlignment) - AttributedType(canon, attrKind, modifiedType, equivalentType); + AttributedType(canon, attrKind, modifiedType, equivalentType); Types.push_back(type); AttributedTypes.InsertNode(type, insertPos); @@ -4219,6 +4240,19 @@ ASTContext::getParenType(QualType InnerType) const { return QualType(T, 0); } +QualType +ASTContext::getMacroQualifiedType(QualType UnderlyingTy, + const IdentifierInfo *MacroII) const { + QualType Canon = UnderlyingTy; + if (!Canon.isCanonical()) + Canon = getCanonicalType(UnderlyingTy); + + auto *newType = new (*this, TypeAlignment) + MacroQualifiedType(UnderlyingTy, Canon, MacroII); + Types.push_back(newType); + return QualType(newType, 0); +} + QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, @@ -4356,7 +4390,13 @@ QualType ASTContext::getPackExpansionType(QualType Pattern, llvm::FoldingSetNodeID ID; PackExpansionType::Profile(ID, Pattern, NumExpansions); - assert(Pattern->containsUnexpandedParameterPack() && + // A deduced type can deduce to a pack, eg + // auto ...x = some_pack; + // That declaration isn't (yet) valid, but is created as part of building an + // init-capture pack: + // [...x = some_pack] {} + assert((Pattern->containsUnexpandedParameterPack() || + Pattern->getContainedDeducedType()) && "Pack expansions must expand one or more parameter packs"); void *InsertPos = nullptr; PackExpansionType *T @@ -4856,19 +4896,20 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent) const { + bool IsDependent, bool IsPack) const { + assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType, Keyword, IsDependent); + AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); auto *AT = new (*this, TypeAlignment) - AutoType(DeducedType, Keyword, IsDependent); + AutoType(DeducedType, Keyword, IsDependent, IsPack); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -4930,7 +4971,7 @@ QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) AutoDeductTy = QualType( new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - /*dependent*/false), + /*dependent*/false, /*pack*/false), 0); return AutoDeductTy; } @@ -5218,6 +5259,11 @@ ASTContext::getNameForTemplate(TemplateName Name, return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); } + case TemplateName::AssumedTemplate: { + AssumedTemplateStorage *Storage = Name.getAsAssumedTemplateName(); + return DeclarationNameInfo(Storage->getDeclName(), NameLoc); + } + case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); DeclarationName DName; @@ -5265,7 +5311,8 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { } case TemplateName::OverloadedTemplate: - llvm_unreachable("cannot canonicalize overloaded template"); + case TemplateName::AssumedTemplate: + llvm_unreachable("cannot canonicalize unresolved template"); case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); @@ -5609,6 +5656,12 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const { return -1; } +int ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const { + if (&getFloatTypeSemantics(LHS) == &getFloatTypeSemantics(RHS)) + return 0; + return getFloatingTypeOrder(LHS, RHS); +} + /// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This /// routine will assert if passed a built-in type that isn't an integer or enum, /// or if it is not canonicalized. @@ -6283,12 +6336,13 @@ void ASTContext::getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, // Encode type qualifer, 'in', 'inout', etc. for the parameter. getObjCEncodingForTypeQualifier(QT, S); // Encode parameter type. - getObjCEncodingForTypeImpl(T, S, true, true, nullptr, - true /*OutermostType*/, - false /*EncodingProperty*/, - false /*StructField*/, - Extended /*EncodeBlockParameters*/, - Extended /*EncodeClassNames*/); + ObjCEncOptions Options = ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType(); + if (Extended) + Options.setEncodeBlockParameters().setEncodeClassNames(); + getObjCEncodingForTypeImpl(T, S, Options, /*Field=*/nullptr); } /// getObjCEncodingForMethodDecl - Return the encoded type for this method @@ -6480,9 +6534,12 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S, // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the // same type. - getObjCEncodingForTypeImpl(T, S, true, true, Field, - true /* outermost type */, false, false, - false, false, false, NotEncodedT); + getObjCEncodingForTypeImpl(T, S, + ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType(), + Field, NotEncodedT); } void ASTContext::getObjCEncodingForPropertyType(QualType T, @@ -6490,9 +6547,13 @@ void ASTContext::getObjCEncodingForPropertyType(QualType T, // Encode result type. // GCC has some special rules regarding encoding of properties which // closely resembles encoding of ivars. - getObjCEncodingForTypeImpl(T, S, true, true, nullptr, - true /* outermost type */, - true /* encoding property */); + getObjCEncodingForTypeImpl(T, S, + ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType() + .setEncodingProperty(), + /*Field=*/nullptr); } static char getObjCEncodingForPrimitiveKind(const ASTContext *C, @@ -6639,16 +6700,9 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, } // FIXME: Use SmallString for accumulating string. -void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, - bool ExpandPointedToStructures, - bool ExpandStructures, +void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, + const ObjCEncOptions Options, const FieldDecl *FD, - bool OutermostType, - bool EncodingProperty, - bool StructField, - bool EncodeBlockParameters, - bool EncodeClassNames, - bool EncodePointerToObjCTypedef, QualType *NotEncodedT) const { CanQualType CT = getCanonicalType(T); switch (CT->getTypeClass()) { @@ -6665,14 +6719,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::Complex: { const auto *CT = T->castAs<ComplexType>(); S += 'j'; - getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr); + getObjCEncodingForTypeImpl(CT->getElementType(), S, ObjCEncOptions(), + /*Field=*/nullptr); return; } case Type::Atomic: { const auto *AT = T->castAs<AtomicType>(); S += 'A'; - getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr); + getObjCEncodingForTypeImpl(AT->getValueType(), S, ObjCEncOptions(), + /*Field=*/nullptr); return; } @@ -6698,11 +6754,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // the pointer itself gets ignored, _unless_ we are looking at a typedef! // Also, do not emit the 'r' for anything but the outermost type! if (isa<TypedefType>(T.getTypePtr())) { - if (OutermostType && T.isConstQualified()) { + if (Options.IsOutermostType() && T.isConstQualified()) { isReadOnly = true; S += 'r'; } - } else if (OutermostType) { + } else if (Options.IsOutermostType()) { QualType P = PointeeTy; while (P->getAs<PointerType>()) P = P->getAs<PointerType>()->getPointeeType(); @@ -6742,9 +6798,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += '^'; getLegacyIntegralTypeEncoding(PointeeTy); - getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, - nullptr, false, false, false, false, false, false, - NotEncodedT); + ObjCEncOptions NewOptions; + if (Options.ExpandPointedToStructures()) + NewOptions.setExpandStructures(); + getObjCEncodingForTypeImpl(PointeeTy, S, NewOptions, + /*Field=*/nullptr, NotEncodedT); return; } @@ -6753,12 +6811,13 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::VariableArray: { const auto *AT = cast<ArrayType>(CT); - if (isa<IncompleteArrayType>(AT) && !StructField) { + if (isa<IncompleteArrayType>(AT) && !Options.IsStructField()) { // Incomplete arrays are encoded as a pointer to the array element. S += '^'; - getObjCEncodingForTypeImpl(AT->getElementType(), S, - false, ExpandStructures, FD); + getObjCEncodingForTypeImpl( + AT->getElementType(), S, + Options.keepingOnly(ObjCEncOptions().setExpandStructures()), FD); } else { S += '['; @@ -6771,10 +6830,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += '0'; } - getObjCEncodingForTypeImpl(AT->getElementType(), S, - false, ExpandStructures, FD, - false, false, false, false, false, false, - NotEncodedT); + getObjCEncodingForTypeImpl( + AT->getElementType(), S, + Options.keepingOnly(ObjCEncOptions().setExpandStructures()), FD, + NotEncodedT); S += ']'; } return; @@ -6800,7 +6859,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } else { S += '?'; } - if (ExpandStructures) { + if (Options.ExpandStructures()) { S += '='; if (!RDecl->isUnion()) { getObjCEncodingForStructureImpl(RDecl, S, FD, true, NotEncodedT); @@ -6814,16 +6873,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Special case bit-fields. if (Field->isBitField()) { - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, + getObjCEncodingForTypeImpl(Field->getType(), S, + ObjCEncOptions().setExpandStructures(), Field); } else { QualType qt = Field->getType(); getLegacyIntegralTypeEncoding(qt); - getObjCEncodingForTypeImpl(qt, S, false, true, - FD, /*OutermostType*/false, - /*EncodingProperty*/false, - /*StructField*/true, - false, false, false, NotEncodedT); + getObjCEncodingForTypeImpl( + qt, S, + ObjCEncOptions().setExpandStructures().setIsStructField(), FD, + NotEncodedT); } } } @@ -6835,26 +6894,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::BlockPointer: { const auto *BT = T->castAs<BlockPointerType>(); S += "@?"; // Unlike a pointer-to-function, which is "^?". - if (EncodeBlockParameters) { + if (Options.EncodeBlockParameters()) { const auto *FT = BT->getPointeeType()->castAs<FunctionType>(); S += '<'; // Block return type - getObjCEncodingForTypeImpl( - FT->getReturnType(), S, ExpandPointedToStructures, ExpandStructures, - FD, false /* OutermostType */, EncodingProperty, - false /* StructField */, EncodeBlockParameters, EncodeClassNames, false, - NotEncodedT); + getObjCEncodingForTypeImpl(FT->getReturnType(), S, + Options.forComponentType(), FD, NotEncodedT); // Block self S += "@?"; // Block parameters if (const auto *FPT = dyn_cast<FunctionProtoType>(FT)) { for (const auto &I : FPT->param_types()) - getObjCEncodingForTypeImpl( - I, S, ExpandPointedToStructures, ExpandStructures, FD, - false /* OutermostType */, EncodingProperty, - false /* StructField */, EncodeBlockParameters, EncodeClassNames, - false, NotEncodedT); + getObjCEncodingForTypeImpl(I, S, Options.forComponentType(), FD, + NotEncodedT); } S += '>'; } @@ -6882,18 +6935,19 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, ObjCInterfaceDecl *OI = T->castAs<ObjCObjectType>()->getInterface(); S += '{'; S += OI->getObjCRuntimeNameAsString(); - if (ExpandStructures) { + if (Options.ExpandStructures()) { S += '='; SmallVector<const ObjCIvarDecl*, 32> Ivars; DeepCollectObjCIvars(OI, true, Ivars); for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { const FieldDecl *Field = Ivars[i]; if (Field->isBitField()) - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field); + getObjCEncodingForTypeImpl(Field->getType(), S, + ObjCEncOptions().setExpandStructures(), + Field); else - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD, - false, false, false, false, false, - EncodePointerToObjCTypedef, + getObjCEncodingForTypeImpl(Field->getType(), S, + ObjCEncOptions().setExpandStructures(), FD, NotEncodedT); } } @@ -6910,17 +6964,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { // FIXME: Consider if we need to output qualifiers for 'Class<p>'. - // Since this is a binary compatibility issue, need to consult with runtime - // folks. Fortunately, this is a *very* obscure construct. + // Since this is a binary compatibility issue, need to consult with + // runtime folks. Fortunately, this is a *very* obscure construct. S += '#'; return; } if (OPT->isObjCQualifiedIdType()) { - getObjCEncodingForTypeImpl(getObjCIdType(), S, - ExpandPointedToStructures, - ExpandStructures, FD); - if (FD || EncodingProperty || EncodeClassNames) { + getObjCEncodingForTypeImpl( + getObjCIdType(), S, + Options.keepingOnly(ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures()), + FD); + if (FD || Options.EncodingProperty() || Options.EncodeClassNames()) { // Note that we do extended encoding of protocol qualifer list // Only when doing ivar or property encoding. S += '"'; @@ -6934,39 +6991,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - QualType PointeeTy = OPT->getPointeeType(); - if (!EncodingProperty && - isa<TypedefType>(PointeeTy.getTypePtr()) && - !EncodePointerToObjCTypedef) { - // Another historical/compatibility reason. - // We encode the underlying type which comes out as - // {...}; - S += '^'; - if (FD && OPT->getInterfaceDecl()) { - // Prevent recursive encoding of fields in some rare cases. - ObjCInterfaceDecl *OI = OPT->getInterfaceDecl(); - SmallVector<const ObjCIvarDecl*, 32> Ivars; - DeepCollectObjCIvars(OI, true, Ivars); - for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { - if (Ivars[i] == FD) { - S += '{'; - S += OI->getObjCRuntimeNameAsString(); - S += '}'; - return; - } - } - } - getObjCEncodingForTypeImpl(PointeeTy, S, - false, ExpandPointedToStructures, - nullptr, - false, false, false, false, false, - /*EncodePointerToObjCTypedef*/true); - return; - } - S += '@'; if (OPT->getInterfaceDecl() && - (FD || EncodingProperty || EncodeClassNames)) { + (FD || Options.EncodingProperty() || Options.EncodeClassNames())) { S += '"'; S += OPT->getInterfaceDecl()->getObjCRuntimeNameAsString(); for (const auto *I : OPT->quals()) { @@ -6980,7 +7007,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } // gcc just blithely ignores member pointers. - // FIXME: we shoul do better than that. 'M' is available. + // FIXME: we should do better than that. 'M' is available. case Type::MemberPointer: // This matches gcc's encoding, even though technically it is insufficient. //FIXME. We should do a better job than gcc. @@ -7142,11 +7169,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, } else { QualType qt = field->getType(); getLegacyIntegralTypeEncoding(qt); - getObjCEncodingForTypeImpl(qt, S, false, true, FD, - /*OutermostType*/false, - /*EncodingProperty*/false, - /*StructField*/true, - false, false, false, NotEncodedT); + getObjCEncodingForTypeImpl( + qt, S, ObjCEncOptions().setExpandStructures().setIsStructField(), + FD, NotEncodedT); #ifndef NDEBUG CurOffs += getTypeSize(field->getType()); #endif @@ -7606,6 +7631,13 @@ ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, return TemplateName(OT); } +/// Retrieve a template name representing an unqualified-id that has been +/// assumed to name a template for ADL purposes. +TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const { + auto *OT = new (*this) AssumedTemplateStorage(Name); + return TemplateName(OT); +} + /// Retrieve the template name that represents a qualified /// template name such as \c std::vector. TemplateName @@ -8581,7 +8613,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lproto->isVariadic() != rproto->isVariadic()) return {}; - if (lproto->getTypeQuals() != rproto->getTypeQuals()) + if (lproto->getMethodQuals() != rproto->getMethodQuals()) return {}; SmallVector<FunctionProtoType::ExtParameterInfo, 4> newParamInfos; @@ -9246,7 +9278,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, // Read the prefixed modifiers first. bool Done = false; #ifndef NDEBUG - bool IsSpecialLong = false; + bool IsSpecial = false; #endif while (!Done) { switch (*Str++) { @@ -9265,26 +9297,26 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, Unsigned = true; break; case 'L': - assert(!IsSpecialLong && "Can't use 'L' with 'W' or 'N' modifiers"); + assert(!IsSpecial && "Can't use 'L' with 'W', 'N', 'Z' or 'O' modifiers"); assert(HowLong <= 2 && "Can't have LLLL modifier"); ++HowLong; break; case 'N': // 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise. - assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); + assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!"); #ifndef NDEBUG - IsSpecialLong = true; + IsSpecial = true; #endif if (Context.getTargetInfo().getLongWidth() == 32) ++HowLong; break; case 'W': // This modifier represents int64 type. - assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); + assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!"); #ifndef NDEBUG - IsSpecialLong = true; + IsSpecial = true; #endif switch (Context.getTargetInfo().getInt64Type()) { default: @@ -9297,6 +9329,38 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, break; } break; + case 'Z': + // This modifier represents int32 type. + assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!"); + assert(HowLong == 0 && "Can't use both 'L' and 'Z' modifiers!"); + #ifndef NDEBUG + IsSpecial = true; + #endif + switch (Context.getTargetInfo().getIntTypeByWidth(32, true)) { + default: + llvm_unreachable("Unexpected integer type"); + case TargetInfo::SignedInt: + HowLong = 0; + break; + case TargetInfo::SignedLong: + HowLong = 1; + break; + case TargetInfo::SignedLongLong: + HowLong = 2; + break; + } + break; + case 'O': + assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!"); + assert(HowLong == 0 && "Can't use both 'L' and 'O' modifiers!"); + #ifndef NDEBUG + IsSpecial = true; + #endif + if (Context.getLangOpts().OpenCL) + HowLong = 1; + else + HowLong = 2; + break; } } @@ -9518,6 +9582,10 @@ QualType ASTContext::GetBuiltinType(unsigned Id, GetBuiltinTypeError &Error, unsigned *IntegerConstantArgs) const { const char *TypeStr = BuiltinInfo.getTypeString(Id); + if (TypeStr[0] == '\0') { + Error = GE_Missing_type; + return {}; + } SmallVector<QualType, 8> ArgTypes; @@ -9553,10 +9621,12 @@ QualType ASTContext::GetBuiltinType(unsigned Id, assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); - FunctionType::ExtInfo EI(CC_C); + bool Variadic = (TypeStr[0] == '.'); + + FunctionType::ExtInfo EI(getDefaultCallingConvention( + Variadic, /*IsCXXMethod=*/false, /*IsBuiltin=*/true)); if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); - bool Variadic = (TypeStr[0] == '.'); // We really shouldn't be making a no-proto type here. if (ArgTypes.empty() && Variadic && !getLangOpts().CPlusPlus) @@ -9784,12 +9854,12 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; } else if (isa<PragmaCommentDecl>(D)) return true; - else if (isa<OMPThreadPrivateDecl>(D)) - return true; else if (isa<PragmaDetectMismatchDecl>(D)) return true; else if (isa<OMPThreadPrivateDecl>(D)) return !D->getDeclContext()->isDependentContext(); + else if (isa<OMPAllocateDecl>(D)) + return !D->getDeclContext()->isDependentContext(); else if (isa<OMPDeclareReductionDecl>(D)) return !D->getDeclContext()->isDependentContext(); else if (isa<ImportDecl>(D)) @@ -9931,34 +10001,39 @@ void ASTContext::forEachMultiversionedFunctionVersion( } CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, - bool IsCXXMethod) const { + bool IsCXXMethod, + bool IsBuiltin) const { // Pass through to the C++ ABI object if (IsCXXMethod) return ABI->getDefaultMethodCallConv(IsVariadic); - switch (LangOpts.getDefaultCallingConv()) { - case LangOptions::DCC_None: - break; - case LangOptions::DCC_CDecl: - return CC_C; - case LangOptions::DCC_FastCall: - if (getTargetInfo().hasFeature("sse2") && !IsVariadic) - return CC_X86FastCall; - break; - case LangOptions::DCC_StdCall: - if (!IsVariadic) - return CC_X86StdCall; - break; - case LangOptions::DCC_VectorCall: - // __vectorcall cannot be applied to variadic functions. - if (!IsVariadic) - return CC_X86VectorCall; - break; - case LangOptions::DCC_RegCall: - // __regcall cannot be applied to variadic functions. - if (!IsVariadic) - return CC_X86RegCall; - break; + // Builtins ignore user-specified default calling convention and remain the + // Target's default calling convention. + if (!IsBuiltin) { + switch (LangOpts.getDefaultCallingConv()) { + case LangOptions::DCC_None: + break; + case LangOptions::DCC_CDecl: + return CC_C; + case LangOptions::DCC_FastCall: + if (getTargetInfo().hasFeature("sse2") && !IsVariadic) + return CC_X86FastCall; + break; + case LangOptions::DCC_StdCall: + if (!IsVariadic) + return CC_X86StdCall; + break; + case LangOptions::DCC_VectorCall: + // __vectorcall cannot be applied to variadic functions. + if (!IsVariadic) + return CC_X86VectorCall; + break; + case LangOptions::DCC_RegCall: + // __regcall cannot be applied to variadic functions. + if (!IsVariadic) + return CC_X86RegCall; + break; + } } return Target->getDefaultCallingConv(TargetInfo::CCMT_Unknown); } @@ -9978,8 +10053,10 @@ VTableContextBase *ASTContext::getVTableContext() { return VTContext.get(); } -MangleContext *ASTContext::createMangleContext() { - switch (Target->getCXXABI().getKind()) { +MangleContext *ASTContext::createMangleContext(const TargetInfo *T) { + if (!T) + T = Target; + switch (T->getCXXABI().getKind()) { case TargetCXXABI::GenericAArch64: case TargetCXXABI::GenericItanium: case TargetCXXABI::GenericARM: @@ -10010,8 +10087,7 @@ size_t ASTContext::getSideTableAllocatedMemory() const { llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) + llvm::capacity_in_bytes(OverriddenMethods) + llvm::capacity_in_bytes(Types) + - llvm::capacity_in_bytes(VariableArrayTypes) + - llvm::capacity_in_bytes(ClassScopeSpecializationPattern); + llvm::capacity_in_bytes(VariableArrayTypes); } /// getIntTypeForBitwidth - @@ -10140,6 +10216,31 @@ ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E, return MaterializedTemporaryValues.lookup(E); } +QualType ASTContext::getStringLiteralArrayType(QualType EltTy, + unsigned Length) const { + // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). + if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings) + EltTy = EltTy.withConst(); + + EltTy = adjustStringLiteralBaseType(EltTy); + + // Get an array type for the string, according to C99 6.4.5. This includes + // the null terminator character. + return getConstantArrayType(EltTy, llvm::APInt(32, Length + 1), + ArrayType::Normal, /*IndexTypeQuals*/ 0); +} + +StringLiteral * +ASTContext::getPredefinedStringLiteralFromCache(StringRef Key) const { + StringLiteral *&Result = StringLiteralCache[Key]; + if (!Result) + Result = StringLiteral::Create( + *this, Key, StringLiteral::Ascii, + /*Pascal*/ false, getStringLiteralArrayType(CharTy, Key.size()), + SourceLocation()); + return Result; +} + bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const { const llvm::Triple &T = getTargetInfo().getTriple(); if (!T.isOSDarwin()) @@ -10485,7 +10586,13 @@ unsigned char ASTContext::getFixedPointIBits(QualType Ty) const { } FixedPointSemantics ASTContext::getFixedPointSemantics(QualType Ty) const { - assert(Ty->isFixedPointType()); + assert((Ty->isFixedPointType() || Ty->isIntegerType()) && + "Can only get the fixed point semantics for a " + "fixed point or integer type."); + if (Ty->isIntegerType()) + return FixedPointSemantics::GetIntegerSemantics(getIntWidth(Ty), + Ty->isSignedIntegerType()); + bool isSigned = Ty->isSignedFixedPointType(); return FixedPointSemantics( static_cast<unsigned>(getTypeSize(Ty)), getFixedPointScale(Ty), isSigned, @@ -10502,3 +10609,38 @@ APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const { assert(Ty->isFixedPointType()); return APFixedPoint::getMin(getFixedPointSemantics(Ty)); } + +QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const { + assert(Ty->isUnsignedFixedPointType() && + "Expected unsigned fixed point type"); + const auto *BTy = Ty->getAs<BuiltinType>(); + + switch (BTy->getKind()) { + case BuiltinType::UShortAccum: + return ShortAccumTy; + case BuiltinType::UAccum: + return AccumTy; + case BuiltinType::ULongAccum: + return LongAccumTy; + case BuiltinType::SatUShortAccum: + return SatShortAccumTy; + case BuiltinType::SatUAccum: + return SatAccumTy; + case BuiltinType::SatULongAccum: + return SatLongAccumTy; + case BuiltinType::UShortFract: + return ShortFractTy; + case BuiltinType::UFract: + return FractTy; + case BuiltinType::ULongFract: + return LongFractTy; + case BuiltinType::SatUShortFract: + return SatShortFractTy; + case BuiltinType::SatUFract: + return SatFractTy; + case BuiltinType::SatULongFract: + return SatLongFractTy; + default: + llvm_unreachable("Unexpected unsigned fixed point type"); + } +} diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index dd0585558572..15df86585294 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -1,9 +1,8 @@ //===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -42,6 +41,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { QT = PT->desugar(); continue; } + // ... or a macro defined type ... + if (const MacroQualifiedType *MDT = dyn_cast<MacroQualifiedType>(Ty)) { + QT = MDT->desugar(); + continue; + } // ...or a substituted template type parameter ... if (const SubstTemplateTypeParmType *ST = dyn_cast<SubstTemplateTypeParmType>(Ty)) { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index b52ec21943e6..22196a1a2600 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1,9 +1,8 @@ //===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -12,21 +11,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTDumper.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/ASTDumperUtils.h" -#include "clang/AST/Attr.h" -#include "clang/AST/AttrVisitor.h" -#include "clang/AST/CommentVisitor.h" -#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclLookups.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclOpenMP.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/LocInfoType.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TemplateArgumentVisitor.h" -#include "clang/AST/TextNodeDumper.h" -#include "clang/AST/TypeVisitor.h" +#include "clang/AST/JSONNodeDumper.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" @@ -34,345 +22,8 @@ using namespace clang; using namespace clang::comments; -//===----------------------------------------------------------------------===// -// ASTDumper Visitor -//===----------------------------------------------------------------------===// - -namespace { - - class ASTDumper - : public ConstDeclVisitor<ASTDumper>, - public ConstStmtVisitor<ASTDumper>, - public ConstCommentVisitor<ASTDumper, void, const FullComment *>, - public TypeVisitor<ASTDumper>, - public ConstAttrVisitor<ASTDumper>, - public ConstTemplateArgumentVisitor<ASTDumper> { - - TextNodeDumper NodeDumper; - - raw_ostream &OS; - - /// The policy to use for printing; can be defaulted. - PrintingPolicy PrintPolicy; - - /// Indicates whether we should trigger deserialization of nodes that had - /// not already been loaded. - bool Deserialize = false; - - const bool ShowColors; - - /// Dump a child of the current node. - template<typename Fn> void dumpChild(Fn DoDumpChild) { - NodeDumper.AddChild(DoDumpChild); - } - template <typename Fn> void dumpChild(StringRef Label, Fn DoDumpChild) { - NodeDumper.AddChild(Label, DoDumpChild); - } - - public: - ASTDumper(raw_ostream &OS, const CommandTraits *Traits, - const SourceManager *SM) - : ASTDumper(OS, Traits, SM, - SM && SM->getDiagnostics().getShowColors()) {} - - ASTDumper(raw_ostream &OS, const CommandTraits *Traits, - const SourceManager *SM, bool ShowColors) - : ASTDumper(OS, Traits, SM, ShowColors, LangOptions()) {} - ASTDumper(raw_ostream &OS, const CommandTraits *Traits, - const SourceManager *SM, bool ShowColors, - const PrintingPolicy &PrintPolicy) - : NodeDumper(OS, ShowColors, SM, PrintPolicy, Traits), OS(OS), - PrintPolicy(PrintPolicy), ShowColors(ShowColors) {} - - void setDeserialize(bool D) { Deserialize = D; } - - void dumpDecl(const Decl *D); - void dumpStmt(const Stmt *S, StringRef Label = {}); - - // Utilities - void dumpTypeAsChild(QualType T); - void dumpTypeAsChild(const Type *T); - void dumpDeclContext(const DeclContext *DC); - void dumpLookups(const DeclContext *DC, bool DumpDecls); - void dumpAttr(const Attr *A); - - // C++ Utilities - void dumpCXXCtorInitializer(const CXXCtorInitializer *Init); - void dumpTemplateParameters(const TemplateParameterList *TPL); - void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI); - void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A, - const Decl *From = nullptr, - const char *Label = nullptr); - void dumpTemplateArgumentList(const TemplateArgumentList &TAL); - void dumpTemplateArgument(const TemplateArgument &A, - SourceRange R = SourceRange(), - const Decl *From = nullptr, - const char *Label = nullptr); - template <typename SpecializationDecl> - void dumpTemplateDeclSpecialization(const SpecializationDecl *D, - bool DumpExplicitInst, - bool DumpRefOnly); - template <typename TemplateDecl> - void dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst); - - // Objective-C utilities. - void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams); - - // Types - void VisitComplexType(const ComplexType *T) { - dumpTypeAsChild(T->getElementType()); - } - void VisitLocInfoType(const LocInfoType *T) { - dumpTypeAsChild(T->getTypeSourceInfo()->getType()); - } - void VisitPointerType(const PointerType *T) { - dumpTypeAsChild(T->getPointeeType()); - } - void VisitBlockPointerType(const BlockPointerType *T) { - dumpTypeAsChild(T->getPointeeType()); - } - void VisitReferenceType(const ReferenceType *T) { - dumpTypeAsChild(T->getPointeeType()); - } - void VisitMemberPointerType(const MemberPointerType *T) { - dumpTypeAsChild(T->getClass()); - dumpTypeAsChild(T->getPointeeType()); - } - void VisitArrayType(const ArrayType *T) { - dumpTypeAsChild(T->getElementType()); - } - void VisitVariableArrayType(const VariableArrayType *T) { - VisitArrayType(T); - dumpStmt(T->getSizeExpr()); - } - void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { - dumpTypeAsChild(T->getElementType()); - dumpStmt(T->getSizeExpr()); - } - void VisitDependentSizedExtVectorType( - const DependentSizedExtVectorType *T) { - dumpTypeAsChild(T->getElementType()); - dumpStmt(T->getSizeExpr()); - } - void VisitVectorType(const VectorType *T) { - dumpTypeAsChild(T->getElementType()); - } - void VisitFunctionType(const FunctionType *T) { - dumpTypeAsChild(T->getReturnType()); - } - void VisitFunctionProtoType(const FunctionProtoType *T) { - VisitFunctionType(T); - for (QualType PT : T->getParamTypes()) - dumpTypeAsChild(PT); - if (T->getExtProtoInfo().Variadic) - dumpChild([=] { OS << "..."; }); - } - void VisitTypeOfExprType(const TypeOfExprType *T) { - dumpStmt(T->getUnderlyingExpr()); - } - void VisitDecltypeType(const DecltypeType *T) { - dumpStmt(T->getUnderlyingExpr()); - } - void VisitUnaryTransformType(const UnaryTransformType *T) { - dumpTypeAsChild(T->getBaseType()); - } - void VisitAttributedType(const AttributedType *T) { - // FIXME: AttrKind - dumpTypeAsChild(T->getModifiedType()); - } - void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { - dumpTypeAsChild(T->getReplacedParameter()); - } - void VisitSubstTemplateTypeParmPackType( - const SubstTemplateTypeParmPackType *T) { - dumpTypeAsChild(T->getReplacedParameter()); - dumpTemplateArgument(T->getArgumentPack()); - } - void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - for (auto &Arg : *T) - dumpTemplateArgument(Arg); - if (T->isTypeAlias()) - dumpTypeAsChild(T->getAliasedType()); - } - void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { - dumpTypeAsChild(T->getPointeeType()); - } - void VisitAtomicType(const AtomicType *T) { - dumpTypeAsChild(T->getValueType()); - } - void VisitPipeType(const PipeType *T) { - dumpTypeAsChild(T->getElementType()); - } - void VisitAdjustedType(const AdjustedType *T) { - dumpTypeAsChild(T->getOriginalType()); - } - void VisitPackExpansionType(const PackExpansionType *T) { - if (!T->isSugared()) - dumpTypeAsChild(T->getPattern()); - } - // FIXME: ElaboratedType, DependentNameType, - // DependentTemplateSpecializationType, ObjCObjectType - - // Decls - void VisitLabelDecl(const LabelDecl *D); - void VisitTypedefDecl(const TypedefDecl *D); - void VisitEnumDecl(const EnumDecl *D); - void VisitRecordDecl(const RecordDecl *D); - void VisitEnumConstantDecl(const EnumConstantDecl *D); - void VisitIndirectFieldDecl(const IndirectFieldDecl *D); - void VisitFunctionDecl(const FunctionDecl *D); - void VisitFieldDecl(const FieldDecl *D); - void VisitVarDecl(const VarDecl *D); - void VisitDecompositionDecl(const DecompositionDecl *D); - void VisitBindingDecl(const BindingDecl *D); - void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D); - void VisitImportDecl(const ImportDecl *D); - void VisitPragmaCommentDecl(const PragmaCommentDecl *D); - void VisitPragmaDetectMismatchDecl(const PragmaDetectMismatchDecl *D); - void VisitCapturedDecl(const CapturedDecl *D); - - // OpenMP decls - void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); - void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D); - void VisitOMPRequiresDecl(const OMPRequiresDecl *D); - void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D); - - // C++ Decls - void VisitNamespaceDecl(const NamespaceDecl *D); - void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D); - void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D); - void VisitTypeAliasDecl(const TypeAliasDecl *D); - void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D); - void VisitCXXRecordDecl(const CXXRecordDecl *D); - void VisitStaticAssertDecl(const StaticAssertDecl *D); - void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); - void VisitClassTemplateDecl(const ClassTemplateDecl *D); - void VisitClassTemplateSpecializationDecl( - const ClassTemplateSpecializationDecl *D); - void VisitClassTemplatePartialSpecializationDecl( - const ClassTemplatePartialSpecializationDecl *D); - void VisitClassScopeFunctionSpecializationDecl( - const ClassScopeFunctionSpecializationDecl *D); - void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D); - void VisitVarTemplateDecl(const VarTemplateDecl *D); - void VisitVarTemplateSpecializationDecl( - const VarTemplateSpecializationDecl *D); - void VisitVarTemplatePartialSpecializationDecl( - const VarTemplatePartialSpecializationDecl *D); - void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); - void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); - void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); - void VisitUsingDecl(const UsingDecl *D); - void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); - void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); - void VisitUsingShadowDecl(const UsingShadowDecl *D); - void VisitConstructorUsingShadowDecl(const ConstructorUsingShadowDecl *D); - void VisitLinkageSpecDecl(const LinkageSpecDecl *D); - void VisitAccessSpecDecl(const AccessSpecDecl *D); - void VisitFriendDecl(const FriendDecl *D); - - // ObjC Decls - void VisitObjCIvarDecl(const ObjCIvarDecl *D); - void VisitObjCMethodDecl(const ObjCMethodDecl *D); - void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D); - void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); - void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); - void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); - void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D); - void VisitObjCImplementationDecl(const ObjCImplementationDecl *D); - void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D); - void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); - void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); - void Visit(const BlockDecl::Capture &C); - void VisitBlockDecl(const BlockDecl *D); - - // Stmts. - void VisitDeclStmt(const DeclStmt *Node); - void VisitAttributedStmt(const AttributedStmt *Node); - void VisitCXXCatchStmt(const CXXCatchStmt *Node); - void VisitCapturedStmt(const CapturedStmt *Node); - - // OpenMP - void Visit(const OMPClause *C); - void VisitOMPExecutableDirective(const OMPExecutableDirective *Node); - - // Exprs - void VisitInitListExpr(const InitListExpr *ILE); - void VisitBlockExpr(const BlockExpr *Node); - void VisitOpaqueValueExpr(const OpaqueValueExpr *Node); - void VisitGenericSelectionExpr(const GenericSelectionExpr *E); - - // C++ - void VisitLambdaExpr(const LambdaExpr *Node) { - dumpDecl(Node->getLambdaClass()); - } - void VisitSizeOfPackExpr(const SizeOfPackExpr *Node); - - // ObjC - void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); - - // Comments. - void dumpComment(const Comment *C, const FullComment *FC); - - void VisitExpressionTemplateArgument(const TemplateArgument &TA) { - dumpStmt(TA.getAsExpr()); - } - void VisitPackTemplateArgument(const TemplateArgument &TA) { - for (const auto &TArg : TA.pack_elements()) - dumpTemplateArgument(TArg); - } - -// Implements Visit methods for Attrs. -#include "clang/AST/AttrNodeTraverse.inc" - }; -} - -//===----------------------------------------------------------------------===// -// Utilities -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpTypeAsChild(QualType T) { - SplitQualType SQT = T.split(); - if (!SQT.Quals.hasQualifiers()) - return dumpTypeAsChild(SQT.Ty); - - dumpChild([=] { - NodeDumper.Visit(T); - dumpTypeAsChild(T.split().Ty); - }); -} - -void ASTDumper::dumpTypeAsChild(const Type *T) { - dumpChild([=] { - NodeDumper.Visit(T); - if (!T) - return; - TypeVisitor<ASTDumper>::Visit(T); - - QualType SingleStepDesugar = - T->getLocallyUnqualifiedSingleStepDesugaredType(); - if (SingleStepDesugar != QualType(T, 0)) - dumpTypeAsChild(SingleStepDesugar); - }); -} - -void ASTDumper::dumpDeclContext(const DeclContext *DC) { - if (!DC) - return; - - for (auto *D : (Deserialize ? DC->decls() : DC->noload_decls())) - dumpDecl(D); - - if (DC->hasExternalLexicalStorage()) { - dumpChild([=] { - ColorScope Color(OS, ShowColors, UndeserializedColor); - OS << "<undeserialized declarations>"; - }); - } -} - void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { - dumpChild([=] { + NodeDumper.AddChild([=] { OS << "StoredDeclsMap "; NodeDumper.dumpBareDeclRef(cast<Decl>(DC)); @@ -384,14 +35,14 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); - auto Range = Deserialize + auto Range = getDeserialize() ? Primary->lookups() : Primary->noload_lookups(/*PreserveInternalState=*/true); for (auto I = Range.begin(), E = Range.end(); I != E; ++I) { DeclarationName Name = I.getLookupName(); DeclContextLookupResult R = *I; - dumpChild([=] { + NodeDumper.AddChild([=] { OS << "DeclarationName "; { ColorScope Color(OS, ShowColors, DeclNameColor); @@ -400,7 +51,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); RI != RE; ++RI) { - dumpChild([=] { + NodeDumper.AddChild([=] { NodeDumper.dumpBareDeclRef(*RI); if ((*RI)->isHidden()) @@ -412,7 +63,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) { if (Decl *Prev = D->getPreviousDecl()) DumpWithPrev(Prev); - dumpDecl(D); + Visit(D); }; DumpWithPrev(*RI); } @@ -422,7 +73,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { } if (HasUndeserializedLookups) { - dumpChild([=] { + NodeDumper.AddChild([=] { ColorScope Color(OS, ShowColors, UndeserializedColor); OS << "<undeserialized lookups>"; }); @@ -430,560 +81,12 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { }); } -void ASTDumper::dumpAttr(const Attr *A) { - dumpChild([=] { - NodeDumper.Visit(A); - ConstAttrVisitor<ASTDumper>::Visit(A); - }); -} - -//===----------------------------------------------------------------------===// -// C++ Utilities -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) { - dumpChild([=] { - NodeDumper.Visit(Init); - dumpStmt(Init->getInit()); - }); -} - -void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) { - if (!TPL) - return; - - for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end(); - I != E; ++I) - dumpDecl(*I); -} - -void ASTDumper::dumpTemplateArgumentListInfo( - const TemplateArgumentListInfo &TALI) { - for (unsigned i = 0, e = TALI.size(); i < e; ++i) - dumpTemplateArgumentLoc(TALI[i]); -} - -void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A, - const Decl *From, const char *Label) { - dumpTemplateArgument(A.getArgument(), A.getSourceRange(), From, Label); -} - -void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) { - for (unsigned i = 0, e = TAL.size(); i < e; ++i) - dumpTemplateArgument(TAL[i]); -} - -void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R, - const Decl *From, const char *Label) { - dumpChild([=] { - NodeDumper.Visit(A, R, From, Label); - ConstTemplateArgumentVisitor<ASTDumper>::Visit(A); - }); -} - -//===----------------------------------------------------------------------===// -// Objective-C Utilities -//===----------------------------------------------------------------------===// -void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) { - if (!typeParams) - return; - - for (auto typeParam : *typeParams) { - dumpDecl(typeParam); - } -} - -//===----------------------------------------------------------------------===// -// Decl dumping methods. -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpDecl(const Decl *D) { - dumpChild([=] { - NodeDumper.Visit(D); - if (!D) - return; - - ConstDeclVisitor<ASTDumper>::Visit(D); - - for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E; - ++I) - dumpAttr(*I); - - if (const FullComment *Comment = - D->getASTContext().getLocalCommentForDeclUncached(D)) - dumpComment(Comment, Comment); - - // Decls within functions are visited by the body. - if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) { - auto DC = dyn_cast<DeclContext>(D); - if (DC && - (DC->hasExternalLexicalStorage() || - (Deserialize ? DC->decls_begin() != DC->decls_end() - : DC->noload_decls_begin() != DC->noload_decls_end()))) - dumpDeclContext(DC); - } - }); -} - -void ASTDumper::VisitLabelDecl(const LabelDecl *D) { NodeDumper.dumpName(D); } - -void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getUnderlyingType()); - if (D->isModulePrivate()) - OS << " __module_private__"; - dumpTypeAsChild(D->getUnderlyingType()); -} - -void ASTDumper::VisitEnumDecl(const EnumDecl *D) { - if (D->isScoped()) { - if (D->isScopedUsingClassTag()) - OS << " class"; - else - OS << " struct"; - } - NodeDumper.dumpName(D); - if (D->isModulePrivate()) - OS << " __module_private__"; - if (D->isFixed()) - NodeDumper.dumpType(D->getIntegerType()); -} - -void ASTDumper::VisitRecordDecl(const RecordDecl *D) { - OS << ' ' << D->getKindName(); - NodeDumper.dumpName(D); - if (D->isModulePrivate()) - OS << " __module_private__"; - if (D->isCompleteDefinition()) - OS << " definition"; -} - -void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - if (const Expr *Init = D->getInitExpr()) - dumpStmt(Init); -} - -void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - - for (auto *Child : D->chain()) - NodeDumper.dumpDeclRef(Child); -} - -void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - - StorageClass SC = D->getStorageClass(); - if (SC != SC_None) - OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); - if (D->isInlineSpecified()) - OS << " inline"; - if (D->isVirtualAsWritten()) - OS << " virtual"; - if (D->isModulePrivate()) - OS << " __module_private__"; - - if (D->isPure()) - OS << " pure"; - if (D->isDefaulted()) { - OS << " default"; - if (D->isDeleted()) - OS << "_delete"; - } - if (D->isDeletedAsWritten()) - OS << " delete"; - if (D->isTrivial()) - OS << " trivial"; - - if (const auto *FPT = D->getType()->getAs<FunctionProtoType>()) { - FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - switch (EPI.ExceptionSpec.Type) { - default: break; - case EST_Unevaluated: - OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl; - break; - case EST_Uninstantiated: - OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate; - break; - } - } - - if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { - if (MD->size_overridden_methods() != 0) { - auto dumpOverride = [=](const CXXMethodDecl *D) { - SplitQualType T_split = D->getType().split(); - OS << D << " " << D->getParent()->getName() - << "::" << D->getNameAsString() << " '" - << QualType::getAsString(T_split, PrintPolicy) << "'"; - }; - - dumpChild([=] { - auto Overrides = MD->overridden_methods(); - OS << "Overrides: [ "; - dumpOverride(*Overrides.begin()); - for (const auto *Override : - llvm::make_range(Overrides.begin() + 1, Overrides.end())) { - OS << ", "; - dumpOverride(Override); - } - OS << " ]"; - }); - } - } - - if (const auto *FTSI = D->getTemplateSpecializationInfo()) - dumpTemplateArgumentList(*FTSI->TemplateArguments); - - if (!D->param_begin() && D->getNumParams()) - dumpChild([=] { OS << "<<NULL params x " << D->getNumParams() << ">>"; }); - else - for (const ParmVarDecl *Parameter : D->parameters()) - dumpDecl(Parameter); - - if (const auto *C = dyn_cast<CXXConstructorDecl>(D)) - for (const auto *I : C->inits()) - dumpCXXCtorInitializer(I); - - if (D->doesThisDeclarationHaveABody()) - dumpStmt(D->getBody()); -} - -void ASTDumper::VisitFieldDecl(const FieldDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - if (D->isMutable()) - OS << " mutable"; - if (D->isModulePrivate()) - OS << " __module_private__"; - - if (D->isBitField()) - dumpStmt(D->getBitWidth()); - if (Expr *Init = D->getInClassInitializer()) - dumpStmt(Init); -} - -void ASTDumper::VisitVarDecl(const VarDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - StorageClass SC = D->getStorageClass(); - if (SC != SC_None) - OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); - switch (D->getTLSKind()) { - case VarDecl::TLS_None: break; - case VarDecl::TLS_Static: OS << " tls"; break; - case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break; - } - if (D->isModulePrivate()) - OS << " __module_private__"; - if (D->isNRVOVariable()) - OS << " nrvo"; - if (D->isInline()) - OS << " inline"; - if (D->isConstexpr()) - OS << " constexpr"; - if (D->hasInit()) { - switch (D->getInitStyle()) { - case VarDecl::CInit: OS << " cinit"; break; - case VarDecl::CallInit: OS << " callinit"; break; - case VarDecl::ListInit: OS << " listinit"; break; - } - dumpStmt(D->getInit()); - } -} - -void ASTDumper::VisitDecompositionDecl(const DecompositionDecl *D) { - VisitVarDecl(D); - for (auto *B : D->bindings()) - dumpDecl(B); -} - -void ASTDumper::VisitBindingDecl(const BindingDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - if (auto *E = D->getBinding()) - dumpStmt(E); -} - -void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { - dumpStmt(D->getAsmString()); -} - -void ASTDumper::VisitImportDecl(const ImportDecl *D) { - OS << ' ' << D->getImportedModule()->getFullModuleName(); -} - -void ASTDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) { - OS << ' '; - switch (D->getCommentKind()) { - case PCK_Unknown: llvm_unreachable("unexpected pragma comment kind"); - case PCK_Compiler: OS << "compiler"; break; - case PCK_ExeStr: OS << "exestr"; break; - case PCK_Lib: OS << "lib"; break; - case PCK_Linker: OS << "linker"; break; - case PCK_User: OS << "user"; break; - } - StringRef Arg = D->getArg(); - if (!Arg.empty()) - OS << " \"" << Arg << "\""; -} - -void ASTDumper::VisitPragmaDetectMismatchDecl( - const PragmaDetectMismatchDecl *D) { - OS << " \"" << D->getName() << "\" \"" << D->getValue() << "\""; -} - -void ASTDumper::VisitCapturedDecl(const CapturedDecl *D) { - dumpStmt(D->getBody()); -} - -//===----------------------------------------------------------------------===// -// OpenMP Declarations -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { - for (auto *E : D->varlists()) - dumpStmt(E); -} - -void ASTDumper::VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - OS << " combiner"; - NodeDumper.dumpPointer(D->getCombiner()); - if (const auto *Initializer = D->getInitializer()) { - OS << " initializer"; - NodeDumper.dumpPointer(Initializer); - switch (D->getInitializerKind()) { - case OMPDeclareReductionDecl::DirectInit: - OS << " omp_priv = "; - break; - case OMPDeclareReductionDecl::CopyInit: - OS << " omp_priv ()"; - break; - case OMPDeclareReductionDecl::CallInit: - break; - } - } - - dumpStmt(D->getCombiner()); - if (const auto *Initializer = D->getInitializer()) - dumpStmt(Initializer); -} - -void ASTDumper::VisitOMPRequiresDecl(const OMPRequiresDecl *D) { - for (auto *C : D->clauselists()) { - dumpChild([=] { - if (!C) { - ColorScope Color(OS, ShowColors, NullColor); - OS << "<<<NULL>>> OMPClause"; - return; - } - { - ColorScope Color(OS, ShowColors, AttrColor); - StringRef ClauseName(getOpenMPClauseName(C->getClauseKind())); - OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper() - << ClauseName.drop_front() << "Clause"; - } - NodeDumper.dumpPointer(C); - NodeDumper.dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc())); - }); - } -} - -void ASTDumper::VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - dumpStmt(D->getInit()); -} - -//===----------------------------------------------------------------------===// -// C++ Declarations -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) { - NodeDumper.dumpName(D); - if (D->isInline()) - OS << " inline"; - if (!D->isOriginalNamespace()) - NodeDumper.dumpDeclRef(D->getOriginalNamespace(), "original"); -} - -void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { - OS << ' '; - NodeDumper.dumpBareDeclRef(D->getNominatedNamespace()); -} - -void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getAliasedNamespace()); -} - -void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getUnderlyingType()); - dumpTypeAsChild(D->getUnderlyingType()); -} - -void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { - NodeDumper.dumpName(D); - dumpTemplateParameters(D->getTemplateParameters()); - dumpDecl(D->getTemplatedDecl()); -} - -void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { - VisitRecordDecl(D); - if (!D->isCompleteDefinition()) - return; - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "DefinitionData"; - } -#define FLAG(fn, name) if (D->fn()) OS << " " #name; - FLAG(isParsingBaseSpecifiers, parsing_base_specifiers); - - FLAG(isGenericLambda, generic); - FLAG(isLambda, lambda); - - FLAG(canPassInRegisters, pass_in_registers); - FLAG(isEmpty, empty); - FLAG(isAggregate, aggregate); - FLAG(isStandardLayout, standard_layout); - FLAG(isTriviallyCopyable, trivially_copyable); - FLAG(isPOD, pod); - FLAG(isTrivial, trivial); - FLAG(isPolymorphic, polymorphic); - FLAG(isAbstract, abstract); - FLAG(isLiteral, literal); - - FLAG(hasUserDeclaredConstructor, has_user_declared_ctor); - FLAG(hasConstexprNonCopyMoveConstructor, has_constexpr_non_copy_move_ctor); - FLAG(hasMutableFields, has_mutable_fields); - FLAG(hasVariantMembers, has_variant_members); - FLAG(allowConstDefaultInit, can_const_default_init); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "DefaultConstructor"; - } - FLAG(hasDefaultConstructor, exists); - FLAG(hasTrivialDefaultConstructor, trivial); - FLAG(hasNonTrivialDefaultConstructor, non_trivial); - FLAG(hasUserProvidedDefaultConstructor, user_provided); - FLAG(hasConstexprDefaultConstructor, constexpr); - FLAG(needsImplicitDefaultConstructor, needs_implicit); - FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "CopyConstructor"; - } - FLAG(hasSimpleCopyConstructor, simple); - FLAG(hasTrivialCopyConstructor, trivial); - FLAG(hasNonTrivialCopyConstructor, non_trivial); - FLAG(hasUserDeclaredCopyConstructor, user_declared); - FLAG(hasCopyConstructorWithConstParam, has_const_param); - FLAG(needsImplicitCopyConstructor, needs_implicit); - FLAG(needsOverloadResolutionForCopyConstructor, - needs_overload_resolution); - if (!D->needsOverloadResolutionForCopyConstructor()) - FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted); - FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "MoveConstructor"; - } - FLAG(hasMoveConstructor, exists); - FLAG(hasSimpleMoveConstructor, simple); - FLAG(hasTrivialMoveConstructor, trivial); - FLAG(hasNonTrivialMoveConstructor, non_trivial); - FLAG(hasUserDeclaredMoveConstructor, user_declared); - FLAG(needsImplicitMoveConstructor, needs_implicit); - FLAG(needsOverloadResolutionForMoveConstructor, - needs_overload_resolution); - if (!D->needsOverloadResolutionForMoveConstructor()) - FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "CopyAssignment"; - } - FLAG(hasTrivialCopyAssignment, trivial); - FLAG(hasNonTrivialCopyAssignment, non_trivial); - FLAG(hasCopyAssignmentWithConstParam, has_const_param); - FLAG(hasUserDeclaredCopyAssignment, user_declared); - FLAG(needsImplicitCopyAssignment, needs_implicit); - FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution); - FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "MoveAssignment"; - } - FLAG(hasMoveAssignment, exists); - FLAG(hasSimpleMoveAssignment, simple); - FLAG(hasTrivialMoveAssignment, trivial); - FLAG(hasNonTrivialMoveAssignment, non_trivial); - FLAG(hasUserDeclaredMoveAssignment, user_declared); - FLAG(needsImplicitMoveAssignment, needs_implicit); - FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "Destructor"; - } - FLAG(hasSimpleDestructor, simple); - FLAG(hasIrrelevantDestructor, irrelevant); - FLAG(hasTrivialDestructor, trivial); - FLAG(hasNonTrivialDestructor, non_trivial); - FLAG(hasUserDeclaredDestructor, user_declared); - FLAG(needsImplicitDestructor, needs_implicit); - FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution); - if (!D->needsOverloadResolutionForDestructor()) - FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted); - }); - }); - - for (const auto &I : D->bases()) { - dumpChild([=] { - if (I.isVirtual()) - OS << "virtual "; - NodeDumper.dumpAccessSpecifier(I.getAccessSpecifier()); - NodeDumper.dumpType(I.getType()); - if (I.isPackExpansion()) - OS << "..."; - }); - } -} - -void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) { - dumpStmt(D->getAssertExpr()); - dumpStmt(D->getMessage()); -} - template <typename SpecializationDecl> void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, bool DumpExplicitInst, bool DumpRefOnly) { bool DumpedAny = false; - for (auto *RedeclWithBadType : D->redecls()) { + for (const auto *RedeclWithBadType : D->redecls()) { // FIXME: The redecls() range sometimes has elements of a less-specific // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives // us TagDecls, and should give CXXRecordDecls). @@ -1007,7 +110,7 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, if (DumpRefOnly) NodeDumper.dumpDeclRef(Redecl); else - dumpDecl(Redecl); + Visit(Redecl); DumpedAny = true; break; case TSK_ExplicitSpecialization: @@ -1022,12 +125,11 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, template <typename TemplateDecl> void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) { - NodeDumper.dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); - dumpDecl(D->getTemplatedDecl()); + Visit(D->getTemplatedDecl()); - for (auto *Child : D->specializations()) + for (const auto *Child : D->specializations()) dumpTemplateDeclSpecialization(Child, DumpExplicitInst, !D->isCanonicalDecl()); } @@ -1043,500 +145,10 @@ void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { dumpTemplateDecl(D, false); } -void ASTDumper::VisitClassTemplateSpecializationDecl( - const ClassTemplateSpecializationDecl *D) { - VisitCXXRecordDecl(D); - dumpTemplateArgumentList(D->getTemplateArgs()); -} - -void ASTDumper::VisitClassTemplatePartialSpecializationDecl( - const ClassTemplatePartialSpecializationDecl *D) { - VisitClassTemplateSpecializationDecl(D); - dumpTemplateParameters(D->getTemplateParameters()); -} - -void ASTDumper::VisitClassScopeFunctionSpecializationDecl( - const ClassScopeFunctionSpecializationDecl *D) { - dumpDecl(D->getSpecialization()); - if (D->hasExplicitTemplateArgs()) - dumpTemplateArgumentListInfo(D->templateArgs()); -} - void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D, false); } -void ASTDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { - NodeDumper.dumpName(D); - dumpTemplateParameters(D->getTemplateParameters()); -} - -void ASTDumper::VisitVarTemplateSpecializationDecl( - const VarTemplateSpecializationDecl *D) { - dumpTemplateArgumentList(D->getTemplateArgs()); - VisitVarDecl(D); -} - -void ASTDumper::VisitVarTemplatePartialSpecializationDecl( - const VarTemplatePartialSpecializationDecl *D) { - dumpTemplateParameters(D->getTemplateParameters()); - VisitVarTemplateSpecializationDecl(D); -} - -void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { - if (D->wasDeclaredWithTypename()) - OS << " typename"; - else - OS << " class"; - OS << " depth " << D->getDepth() << " index " << D->getIndex(); - if (D->isParameterPack()) - OS << " ..."; - NodeDumper.dumpName(D); - if (D->hasDefaultArgument()) - dumpTemplateArgument(D->getDefaultArgument(), SourceRange(), - D->getDefaultArgStorage().getInheritedFrom(), - D->defaultArgumentWasInherited() ? "inherited from" - : "previous"); -} - -void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { - NodeDumper.dumpType(D->getType()); - OS << " depth " << D->getDepth() << " index " << D->getIndex(); - if (D->isParameterPack()) - OS << " ..."; - NodeDumper.dumpName(D); - if (D->hasDefaultArgument()) - dumpTemplateArgument(D->getDefaultArgument(), SourceRange(), - D->getDefaultArgStorage().getInheritedFrom(), - D->defaultArgumentWasInherited() ? "inherited from" - : "previous"); -} - -void ASTDumper::VisitTemplateTemplateParmDecl( - const TemplateTemplateParmDecl *D) { - OS << " depth " << D->getDepth() << " index " << D->getIndex(); - if (D->isParameterPack()) - OS << " ..."; - NodeDumper.dumpName(D); - dumpTemplateParameters(D->getTemplateParameters()); - if (D->hasDefaultArgument()) - dumpTemplateArgumentLoc( - D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(), - D->defaultArgumentWasInherited() ? "inherited from" : "previous"); -} - -void ASTDumper::VisitUsingDecl(const UsingDecl *D) { - OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); -} - -void ASTDumper::VisitUnresolvedUsingTypenameDecl( - const UnresolvedUsingTypenameDecl *D) { - OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); -} - -void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { - OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); - NodeDumper.dumpType(D->getType()); -} - -void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) { - OS << ' '; - NodeDumper.dumpBareDeclRef(D->getTargetDecl()); - if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl())) - dumpTypeAsChild(TD->getTypeForDecl()); -} - -void ASTDumper::VisitConstructorUsingShadowDecl( - const ConstructorUsingShadowDecl *D) { - if (D->constructsVirtualBase()) - OS << " virtual"; - - dumpChild([=] { - OS << "target "; - NodeDumper.dumpBareDeclRef(D->getTargetDecl()); - }); - - dumpChild([=] { - OS << "nominated "; - NodeDumper.dumpBareDeclRef(D->getNominatedBaseClass()); - OS << ' '; - NodeDumper.dumpBareDeclRef(D->getNominatedBaseClassShadowDecl()); - }); - - dumpChild([=] { - OS << "constructed "; - NodeDumper.dumpBareDeclRef(D->getConstructedBaseClass()); - OS << ' '; - NodeDumper.dumpBareDeclRef(D->getConstructedBaseClassShadowDecl()); - }); -} - -void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { - switch (D->getLanguage()) { - case LinkageSpecDecl::lang_c: OS << " C"; break; - case LinkageSpecDecl::lang_cxx: OS << " C++"; break; - } -} - -void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) { - OS << ' '; - NodeDumper.dumpAccessSpecifier(D->getAccess()); -} - -void ASTDumper::VisitFriendDecl(const FriendDecl *D) { - if (TypeSourceInfo *T = D->getFriendType()) - NodeDumper.dumpType(T->getType()); - else - dumpDecl(D->getFriendDecl()); -} - -//===----------------------------------------------------------------------===// -// Obj-C Declarations -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - if (D->getSynthesize()) - OS << " synthesize"; - - switch (D->getAccessControl()) { - case ObjCIvarDecl::None: - OS << " none"; - break; - case ObjCIvarDecl::Private: - OS << " private"; - break; - case ObjCIvarDecl::Protected: - OS << " protected"; - break; - case ObjCIvarDecl::Public: - OS << " public"; - break; - case ObjCIvarDecl::Package: - OS << " package"; - break; - } -} - -void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { - if (D->isInstanceMethod()) - OS << " -"; - else - OS << " +"; - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getReturnType()); - - if (D->isThisDeclarationADefinition()) { - dumpDeclContext(D); - } else { - for (const ParmVarDecl *Parameter : D->parameters()) - dumpDecl(Parameter); - } - - if (D->isVariadic()) - dumpChild([=] { OS << "..."; }); - - if (D->hasBody()) - dumpStmt(D->getBody()); -} - -void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) { - NodeDumper.dumpName(D); - switch (D->getVariance()) { - case ObjCTypeParamVariance::Invariant: - break; - - case ObjCTypeParamVariance::Covariant: - OS << " covariant"; - break; - - case ObjCTypeParamVariance::Contravariant: - OS << " contravariant"; - break; - } - - if (D->hasExplicitBound()) - OS << " bounded"; - NodeDumper.dumpType(D->getUnderlyingType()); -} - -void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getClassInterface()); - NodeDumper.dumpDeclRef(D->getImplementation()); - for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), - E = D->protocol_end(); - I != E; ++I) - NodeDumper.dumpDeclRef(*I); - dumpObjCTypeParamList(D->getTypeParamList()); -} - -void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getClassInterface()); - NodeDumper.dumpDeclRef(D->getCategoryDecl()); -} - -void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { - NodeDumper.dumpName(D); - - for (auto *Child : D->protocols()) - NodeDumper.dumpDeclRef(Child); -} - -void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getSuperClass(), "super"); - - NodeDumper.dumpDeclRef(D->getImplementation()); - for (auto *Child : D->protocols()) - NodeDumper.dumpDeclRef(Child); - dumpObjCTypeParamList(D->getTypeParamListAsWritten()); -} - -void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getSuperClass(), "super"); - NodeDumper.dumpDeclRef(D->getClassInterface()); - for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(), - E = D->init_end(); - I != E; ++I) - dumpCXXCtorInitializer(*I); -} - -void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getClassInterface()); -} - -void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - - if (D->getPropertyImplementation() == ObjCPropertyDecl::Required) - OS << " required"; - else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional) - OS << " optional"; - - ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes(); - if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) { - if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly) - OS << " readonly"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) - OS << " assign"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite) - OS << " readwrite"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_retain) - OS << " retain"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_copy) - OS << " copy"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) - OS << " nonatomic"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic) - OS << " atomic"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_weak) - OS << " weak"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_strong) - OS << " strong"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) - OS << " unsafe_unretained"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_class) - OS << " class"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) - NodeDumper.dumpDeclRef(D->getGetterMethodDecl(), "getter"); - if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) - NodeDumper.dumpDeclRef(D->getSetterMethodDecl(), "setter"); - } -} - -void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { - NodeDumper.dumpName(D->getPropertyDecl()); - if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) - OS << " synthesize"; - else - OS << " dynamic"; - NodeDumper.dumpDeclRef(D->getPropertyDecl()); - NodeDumper.dumpDeclRef(D->getPropertyIvarDecl()); -} - -void ASTDumper::Visit(const BlockDecl::Capture &C) { - dumpChild([=] { - NodeDumper.Visit(C); - if (C.hasCopyExpr()) - dumpStmt(C.getCopyExpr()); - }); -} - -void ASTDumper::VisitBlockDecl(const BlockDecl *D) { - for (auto I : D->parameters()) - dumpDecl(I); - - if (D->isVariadic()) - dumpChild([=]{ OS << "..."; }); - - if (D->capturesCXXThis()) - dumpChild([=]{ OS << "capture this"; }); - - for (const auto &I : D->captures()) - Visit(I); - dumpStmt(D->getBody()); -} - -//===----------------------------------------------------------------------===// -// Stmt dumping methods. -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpStmt(const Stmt *S, StringRef Label) { - dumpChild(Label, [=] { - NodeDumper.Visit(S); - - if (!S) { - return; - } - - ConstStmtVisitor<ASTDumper>::Visit(S); - - // Some statements have custom mechanisms for dumping their children. - if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S)) { - return; - } - - for (const Stmt *SubStmt : S->children()) - dumpStmt(SubStmt); - }); -} - -void ASTDumper::VisitDeclStmt(const DeclStmt *Node) { - for (DeclStmt::const_decl_iterator I = Node->decl_begin(), - E = Node->decl_end(); - I != E; ++I) - dumpDecl(*I); -} - -void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) { - for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(), - E = Node->getAttrs().end(); - I != E; ++I) - dumpAttr(*I); -} - -void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) { - dumpDecl(Node->getExceptionDecl()); -} - -void ASTDumper::VisitCapturedStmt(const CapturedStmt *Node) { - dumpDecl(Node->getCapturedDecl()); -} - -//===----------------------------------------------------------------------===// -// OpenMP dumping methods. -//===----------------------------------------------------------------------===// - -void ASTDumper::Visit(const OMPClause *C) { - dumpChild([=] { - NodeDumper.Visit(C); - for (auto *S : C->children()) - dumpStmt(S); - }); -} - -void ASTDumper::VisitOMPExecutableDirective( - const OMPExecutableDirective *Node) { - for (const auto *C : Node->clauses()) - Visit(C); -} - -//===----------------------------------------------------------------------===// -// Expr dumping methods. -//===----------------------------------------------------------------------===// - - -void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) { - if (auto *Filler = ILE->getArrayFiller()) { - dumpStmt(Filler, "array_filler"); - } -} - -void ASTDumper::VisitBlockExpr(const BlockExpr *Node) { - dumpDecl(Node->getBlockDecl()); -} - -void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { - if (Expr *Source = Node->getSourceExpr()) - dumpStmt(Source); -} - -void ASTDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) { - if (E->isResultDependent()) - OS << " result_dependent"; - dumpStmt(E->getControllingExpr()); - dumpTypeAsChild(E->getControllingExpr()->getType()); // FIXME: remove - - for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { - dumpChild([=] { - if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) { - OS << "case "; - NodeDumper.dumpType(TSI->getType()); - } else { - OS << "default"; - } - - if (!E->isResultDependent() && E->getResultIndex() == I) - OS << " selected"; - - if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) - dumpTypeAsChild(TSI->getType()); - dumpStmt(E->getAssocExpr(I)); - }); - } -} - -//===----------------------------------------------------------------------===// -// C++ Expressions -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) { - if (Node->isPartiallySubstituted()) - for (const auto &A : Node->getPartialArguments()) - dumpTemplateArgument(A); -} - -//===----------------------------------------------------------------------===// -// Obj-C Expressions -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) { - if (const VarDecl *CatchParam = Node->getCatchParamDecl()) - dumpDecl(CatchParam); -} - -//===----------------------------------------------------------------------===// -// Comments -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpComment(const Comment *C, const FullComment *FC) { - dumpChild([=] { - NodeDumper.Visit(C, FC); - if (!C) { - return; - } - ConstCommentVisitor<ASTDumper, void, const FullComment *>::visit(C, FC); - for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); - I != E; ++I) - dumpComment(*I, FC); - }); -} - //===----------------------------------------------------------------------===// // Type method implementations //===----------------------------------------------------------------------===// @@ -1551,7 +163,7 @@ LLVM_DUMP_METHOD void QualType::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS) const { ASTDumper Dumper(OS, nullptr, nullptr); - Dumper.dumpTypeAsChild(*this); + Dumper.Visit(*this); } LLVM_DUMP_METHOD void Type::dump() const { dump(llvm::errs()); } @@ -1566,13 +178,22 @@ LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const { LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); } -LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const { - const ASTContext &Ctx = getASTContext(); +LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize, + ASTDumpOutputFormat Format) const { + ASTContext &Ctx = getASTContext(); const SourceManager &SM = Ctx.getSourceManager(); - ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM, - SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); - P.setDeserialize(Deserialize); - P.dumpDecl(this); + + if (ADOF_JSON == Format) { + JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(), + &Ctx.getCommentCommandTraits()); + (void)Deserialize; // FIXME? + P.Visit(this); + } else { + ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM, + SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); + P.setDeserialize(Deserialize); + P.Visit(this); + } } LLVM_DUMP_METHOD void Decl::dumpColor() const { @@ -1580,7 +201,7 @@ LLVM_DUMP_METHOD void Decl::dumpColor() const { ASTDumper P(llvm::errs(), &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager(), /*ShowColors*/ true, Ctx.getPrintingPolicy()); - P.dumpDecl(this); + P.Visit(this); } LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { @@ -1611,22 +232,22 @@ LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const { LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { ASTDumper P(OS, nullptr, &SM); - P.dumpStmt(this); + P.Visit(this); } LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const { ASTDumper P(OS, nullptr, nullptr); - P.dumpStmt(this); + P.Visit(this); } LLVM_DUMP_METHOD void Stmt::dump() const { ASTDumper P(llvm::errs(), nullptr, nullptr); - P.dumpStmt(this); + P.Visit(this); } LLVM_DUMP_METHOD void Stmt::dumpColor() const { ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); - P.dumpStmt(this); + P.Visit(this); } //===----------------------------------------------------------------------===// @@ -1648,7 +269,7 @@ void Comment::dump(raw_ostream &OS, const CommandTraits *Traits, if (!FC) return; ASTDumper D(OS, Traits, SM); - D.dumpComment(FC, FC); + D.Visit(FC, FC); } LLVM_DUMP_METHOD void Comment::dumpColor() const { @@ -1656,5 +277,5 @@ LLVM_DUMP_METHOD void Comment::dumpColor() const { if (!FC) return; ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); - D.dumpComment(FC, FC); + D.Visit(FC, FC); } diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 44832557e97b..9d5dd84161de 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, diff --git a/lib/AST/ASTImporterLookupTable.cpp b/lib/AST/ASTImporterLookupTable.cpp index fbcd4f5cb341..7390329d4ed8 100644 --- a/lib/AST/ASTImporterLookupTable.cpp +++ b/lib/AST/ASTImporterLookupTable.cpp @@ -1,9 +1,8 @@ //===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -27,17 +26,30 @@ struct Builder : RecursiveASTVisitor<Builder> { LT.add(D); return true; } + // In most cases the FriendDecl contains the declaration of the befriended + // class as a child node, so it is discovered during the recursive + // visitation. However, there are cases when the befriended class is not a + // child, thus it must be fetched explicitly from the FriendDecl, and only + // then can we add it to the lookup table. bool VisitFriendDecl(FriendDecl *D) { if (D->getFriendType()) { QualType Ty = D->getFriendType()->getType(); - // FIXME Can this be other than elaborated? - QualType NamedTy = cast<ElaboratedType>(Ty)->getNamedType(); - if (!NamedTy->isDependentType()) { - if (const auto *RTy = dyn_cast<RecordType>(NamedTy)) + if (isa<ElaboratedType>(Ty)) + Ty = cast<ElaboratedType>(Ty)->getNamedType(); + // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization) + // always has that decl as child node. + // However, there are non-dependent cases which does not have the + // type as a child node. We have to dig up that type now. + if (!Ty->isDependentType()) { + if (const auto *RTy = dyn_cast<RecordType>(Ty)) LT.add(RTy->getAsCXXRecordDecl()); - else if (const auto *SpecTy = - dyn_cast<TemplateSpecializationType>(NamedTy)) { + else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty)) LT.add(SpecTy->getAsCXXRecordDecl()); + else if (isa<TypedefType>(Ty)) { + // We do not put friend typedefs to the lookup table because + // ASTImporter does not organize typedefs into redecl chains. + } else { + llvm_unreachable("Unhandled type of friend class"); } } } diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp index d19b89bb95b4..912db3c130c5 100644 --- a/lib/AST/ASTStructuralEquivalence.cpp +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -1,9 +1,8 @@ //===- ASTStructuralEquivalence.cpp ---------------------------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -74,6 +73,7 @@ #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" @@ -101,6 +101,59 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, const TemplateArgument &Arg2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NestedNameSpecifier *NNS1, + NestedNameSpecifier *NNS2); +static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, + const IdentifierInfo *Name2); + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const DeclarationName Name1, + const DeclarationName Name2) { + if (Name1.getNameKind() != Name2.getNameKind()) + return false; + + switch (Name1.getNameKind()) { + + case DeclarationName::Identifier: + return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(), + Name2.getAsIdentifierInfo()); + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + return IsStructurallyEquivalent(Context, Name1.getCXXNameType(), + Name2.getCXXNameType()); + + case DeclarationName::CXXDeductionGuideName: { + if (!IsStructurallyEquivalent( + Context, Name1.getCXXDeductionGuideTemplate()->getDeclName(), + Name2.getCXXDeductionGuideTemplate()->getDeclName())) + return false; + return IsStructurallyEquivalent(Context, + Name1.getCXXDeductionGuideTemplate(), + Name2.getCXXDeductionGuideTemplate()); + } + + case DeclarationName::CXXOperatorName: + return Name1.getCXXOverloadedOperator() == Name2.getCXXOverloadedOperator(); + + case DeclarationName::CXXLiteralOperatorName: + return IsStructurallyEquivalent(Name1.getCXXLiteralIdentifier(), + Name2.getCXXLiteralIdentifier()); + + case DeclarationName::CXXUsingDirective: + return true; // FIXME When do we consider two using directives equal? + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return true; // FIXME + } + + llvm_unreachable("Unhandled kind of DeclarationName"); + return true; +} /// Determine structural equivalence of two expressions. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, @@ -108,7 +161,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!E1 || !E2) return E1 == E2; - // FIXME: Actually perform a structural comparison! + if (auto *DE1 = dyn_cast<DependentScopeDeclRefExpr>(E1)) { + auto *DE2 = dyn_cast<DependentScopeDeclRefExpr>(E2); + if (!DE2) + return false; + if (!IsStructurallyEquivalent(Context, DE1->getDeclName(), + DE2->getDeclName())) + return false; + return IsStructurallyEquivalent(Context, DE1->getQualifier(), + DE2->getQualifier()); + } else if (auto CastE1 = dyn_cast<ImplicitCastExpr>(E1)) { + auto *CastE2 = dyn_cast<ImplicitCastExpr>(E2); + if (!CastE2) + return false; + if (!IsStructurallyEquivalent(Context, CastE1->getType(), + CastE2->getType())) + return false; + return IsStructurallyEquivalent(Context, CastE1->getSubExpr(), + CastE2->getSubExpr()); + } + // FIXME: Handle other kind of expressions! return true; } @@ -181,6 +253,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return I1 == E1 && I2 == E2; } + case TemplateName::AssumedTemplate: { + AssumedTemplateStorage *TN1 = N1.getAsAssumedTemplateName(), + *TN2 = N1.getAsAssumedTemplateName(); + return TN1->getDeclName() == TN2->getDeclName(); + } + case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(), *QN2 = N2.getAsQualifiedTemplateName(); @@ -297,6 +375,62 @@ static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// Determine structural equivalence based on the ExtInfo of functions. This +/// is inspired by ASTContext::mergeFunctionTypes(), we compare calling +/// conventions bits but must not compare some other bits. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FunctionType::ExtInfo EI1, + FunctionType::ExtInfo EI2) { + // Compatible functions must have compatible calling conventions. + if (EI1.getCC() != EI2.getCC()) + return false; + + // Regparm is part of the calling convention. + if (EI1.getHasRegParm() != EI2.getHasRegParm()) + return false; + if (EI1.getRegParm() != EI2.getRegParm()) + return false; + + if (EI1.getProducesResult() != EI2.getProducesResult()) + return false; + if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs()) + return false; + if (EI1.getNoCfCheck() != EI2.getNoCfCheck()) + return false; + + return true; +} + +/// Check the equivalence of exception specifications. +static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context, + const FunctionProtoType *Proto1, + const FunctionProtoType *Proto2) { + + auto Spec1 = Proto1->getExceptionSpecType(); + auto Spec2 = Proto2->getExceptionSpecType(); + + if (isUnresolvedExceptionSpec(Spec1) || isUnresolvedExceptionSpec(Spec2)) + return true; + + if (Spec1 != Spec2) + return false; + if (Spec1 == EST_Dynamic) { + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + } else if (isComputedNoexcept(Spec1)) { + if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(), + Proto2->getNoexceptExpr())) + return false; + } + + return true; +} + /// Determine structural equivalence of two types. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, QualType T1, QualType T2) { @@ -503,7 +637,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Proto1->isVariadic() != Proto2->isVariadic()) return false; - if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) + if (Proto1->getMethodQuals() != Proto2->getMethodQuals()) return false; // Check exceptions, this information is lost in canonical type. @@ -511,24 +645,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx)); const auto *OrigProto2 = cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx)); - auto Spec1 = OrigProto1->getExceptionSpecType(); - auto Spec2 = OrigProto2->getExceptionSpecType(); - - if (Spec1 != Spec2) + if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2)) return false; - if (Spec1 == EST_Dynamic) { - if (OrigProto1->getNumExceptions() != OrigProto2->getNumExceptions()) - return false; - for (unsigned I = 0, N = OrigProto1->getNumExceptions(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, OrigProto1->getExceptionType(I), - OrigProto2->getExceptionType(I))) - return false; - } - } else if (isComputedNoexcept(Spec1)) { - if (!IsStructurallyEquivalent(Context, OrigProto1->getNoexceptExpr(), - OrigProto2->getNoexceptExpr())) - return false; - } // Fall through to check the bits common with FunctionNoProtoType. LLVM_FALLTHROUGH; @@ -540,7 +658,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), Function2->getReturnType())) return false; - if (Function1->getExtInfo() != Function2->getExtInfo()) + if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(), + Function2->getExtInfo())) return false; break; } @@ -569,6 +688,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + case Type::MacroQualified: + if (!IsStructurallyEquivalent( + Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(), + cast<MacroQualifiedType>(T2)->getUnderlyingType())) + return false; + break; + case Type::Typedef: if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(), cast<TypedefType>(T2)->getDecl())) @@ -834,10 +960,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, IdentifierInfo *Name2 = Field2->getIdentifier(); if (!::IsStructurallyEquivalent(Name1, Name2)) { if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2( + Owner2->getLocation(), + Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(Owner2); Context.Diag2(Field2->getLocation(), diag::note_odr_field_name) << Field2->getDeclName(); @@ -850,10 +975,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, Field1->getType(), Field2->getType())) { if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2( + Owner2->getLocation(), + Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(Owner2); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); @@ -865,10 +989,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Field1->isBitField() != Field2->isBitField()) { if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2( + Owner2->getLocation(), + Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(Owner2); if (Field1->isBitField()) { Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) @@ -895,9 +1018,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Bits1 != Bits2) { if (Context.Complain) { Context.Diag2(Owner2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(Owner2); Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) << Field2->getDeclName() << Field2->getType() << Bits2; @@ -933,13 +1055,15 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) { auto *Constructor2 = cast<CXXConstructorDecl>(Method2); - if (Constructor1->isExplicit() != Constructor2->isExplicit()) + if (!Constructor1->getExplicitSpecifier().isEquivalent( + Constructor2->getExplicitSpecifier())) return false; } if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) { auto *Conversion2 = cast<CXXConversionDecl>(Method2); - if (Conversion1->isExplicit() != Conversion2->isExplicit()) + if (!Conversion1->getExplicitSpecifier().isEquivalent( + Conversion2->getExplicitSpecifier())) return false; if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(), Conversion2->getConversionType())) @@ -961,15 +1085,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// Determine structural equivalence of two lambda classes. +static bool +IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context, + CXXRecordDecl *D1, CXXRecordDecl *D2) { + assert(D1->isLambda() && D2->isLambda() && + "Must be called on lambda classes"); + if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(), + D2->getLambdaCallOperator())) + return false; + + return true; +} + /// Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { if (D1->isUnion() != D2->isUnion()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) << D1->getDeclName() << (unsigned)D1->getTagKind(); @@ -1044,9 +1179,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX); } + if (D1CXX->isLambda() != D2CXX->isLambda()) + return false; + if (D1CXX->isLambda()) { + if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX)) + return false; + } + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) << D2CXX->getNumBases(); @@ -1065,7 +1209,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Base2->getType())) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base) << Base2->getType() << Base2->getSourceRange(); @@ -1079,7 +1224,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Base1->isVirtual() != Base2->isVirtual()) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base) << Base2->isVirtual() << Base2->getSourceRange(); @@ -1092,15 +1238,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // Check the friends for consistency. CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(), - Friend2End = D2CXX->friend_end(); + Friend2End = D2CXX->friend_end(); for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(), - Friend1End = D1CXX->friend_end(); + Friend1End = D1CXX->friend_end(); Friend1 != Friend1End; ++Friend1, ++Friend2) { if (Friend2 == Friend2End) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - diag::warn_odr_tag_type_inconsistent) - << Context.ToCtx.getTypeDeclType(D2CXX); + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) + << Context.ToCtx.getTypeDeclType(D2CXX); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend); } @@ -1109,8 +1256,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.ToCtx.getTypeDeclType(D2CXX); + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) + << Context.ToCtx.getTypeDeclType(D2CXX); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); } @@ -1120,8 +1269,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Friend2 != Friend2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) + << Context.ToCtx.getTypeDeclType(D2); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend); } @@ -1129,7 +1280,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } } else if (D1CXX->getNumBases() > 0) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base) @@ -1149,9 +1302,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Field2 == Field2End) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(Field1->getLocation(), diag::note_odr_field) << Field1->getDeclName() << Field1->getType(); @@ -1166,10 +1318,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Field2 != Field2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); @@ -1200,9 +1350,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (EC2 == EC2End) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) << EC1->getDeclName() << EC1->getInitVal().toString(10); @@ -1217,9 +1366,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) << EC2->getDeclName() << EC2->getInitVal().toString(10); @@ -1232,10 +1380,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (EC2 != EC2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) << EC2->getDeclName() << EC2->getInitVal().toString(10); @@ -1253,7 +1399,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Params1->size() != Params2->size()) { if (Context.Complain) { Context.Diag2(Params2->getTemplateLoc(), - diag::err_odr_different_num_template_parameters) + Context.getApplicableDiagnostic( + diag::err_odr_different_num_template_parameters)) << Params1->size() << Params2->size(); Context.Diag1(Params1->getTemplateLoc(), diag::note_odr_template_parameter_list); @@ -1265,7 +1412,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { if (Context.Complain) { Context.Diag2(Params2->getParam(I)->getLocation(), - diag::err_odr_different_template_parameter_kind); + Context.getApplicableDiagnostic( + diag::err_odr_different_template_parameter_kind)); Context.Diag1(Params1->getParam(I)->getLocation(), diag::note_odr_template_parameter_here); } @@ -1285,7 +1433,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateTypeParmDecl *D2) { if (D1->isParameterPack() != D2->isParameterPack()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_parameter_pack_non_pack)) << D2->isParameterPack(); Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) << D1->isParameterPack(); @@ -1301,7 +1451,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, NonTypeTemplateParmDecl *D2) { if (D1->isParameterPack() != D2->isParameterPack()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_parameter_pack_non_pack)) << D2->isParameterPack(); Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) << D1->isParameterPack(); @@ -1313,7 +1465,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - diag::err_odr_non_type_parameter_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_non_type_parameter_type_inconsistent)) << D2->getType() << D1->getType(); Context.Diag1(D1->getLocation(), diag::note_odr_value_here) << D1->getType(); @@ -1329,7 +1482,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateTemplateParmDecl *D2) { if (D1->isParameterPack() != D2->isParameterPack()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_parameter_pack_non_pack)) << D2->isParameterPack(); Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) << D1->isParameterPack(); @@ -1378,6 +1533,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ConceptDecl *D1, + ConceptDecl *D2) { + // Check template parameters. + if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2)) + return false; + + // Check the constraint expression. + return IsStructurallyEquivalent(Context, D1->getConstraintExpr(), + D2->getConstraintExpr()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FriendDecl *D1, FriendDecl *D2) { if ((D1->getFriendType() && D2->getFriendDecl()) || (D1->getFriendDecl() && D2->getFriendType())) { @@ -1485,6 +1652,52 @@ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { return Index; } +unsigned StructuralEquivalenceContext::getApplicableDiagnostic( + unsigned ErrorDiagnostic) { + if (ErrorOnTagTypeMismatch) + return ErrorDiagnostic; + + switch (ErrorDiagnostic) { + case diag::err_odr_variable_type_inconsistent: + return diag::warn_odr_variable_type_inconsistent; + case diag::err_odr_variable_multiple_def: + return diag::warn_odr_variable_multiple_def; + case diag::err_odr_function_type_inconsistent: + return diag::warn_odr_function_type_inconsistent; + case diag::err_odr_tag_type_inconsistent: + return diag::warn_odr_tag_type_inconsistent; + case diag::err_odr_field_type_inconsistent: + return diag::warn_odr_field_type_inconsistent; + case diag::err_odr_ivar_type_inconsistent: + return diag::warn_odr_ivar_type_inconsistent; + case diag::err_odr_objc_superclass_inconsistent: + return diag::warn_odr_objc_superclass_inconsistent; + case diag::err_odr_objc_method_result_type_inconsistent: + return diag::warn_odr_objc_method_result_type_inconsistent; + case diag::err_odr_objc_method_num_params_inconsistent: + return diag::warn_odr_objc_method_num_params_inconsistent; + case diag::err_odr_objc_method_param_type_inconsistent: + return diag::warn_odr_objc_method_param_type_inconsistent; + case diag::err_odr_objc_method_variadic_inconsistent: + return diag::warn_odr_objc_method_variadic_inconsistent; + case diag::err_odr_objc_property_type_inconsistent: + return diag::warn_odr_objc_property_type_inconsistent; + case diag::err_odr_objc_property_impl_kind_inconsistent: + return diag::warn_odr_objc_property_impl_kind_inconsistent; + case diag::err_odr_objc_synthesize_ivar_inconsistent: + return diag::warn_odr_objc_synthesize_ivar_inconsistent; + case diag::err_odr_different_num_template_parameters: + return diag::warn_odr_different_num_template_parameters; + case diag::err_odr_different_template_parameter_kind: + return diag::warn_odr_different_template_parameter_kind; + case diag::err_odr_parameter_pack_non_pack: + return diag::warn_odr_parameter_pack_non_pack; + case diag::err_odr_non_type_parameter_type_inconsistent: + return diag::warn_odr_non_type_parameter_type_inconsistent; + } + llvm_unreachable("Diagnostic kind not handled in preceding switch"); +} + bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) { // Ensure that the implementation functions (all static functions in this TU) @@ -1590,6 +1803,14 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence( // Class template/non-class-template mismatch. return false; } + } else if (auto *ConceptDecl1 = dyn_cast<ConceptDecl>(D1)) { + if (auto *ConceptDecl2 = dyn_cast<ConceptDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, ConceptDecl1, ConceptDecl2)) + return false; + } else { + // Concept/non-concept mismatch. + return false; + } } else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) { if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) @@ -1624,6 +1845,12 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence( } } else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) { if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) { + if (FD1->isOverloadedOperator()) { + if (!FD2->isOverloadedOperator()) + return false; + if (FD1->getOverloadedOperator() != FD2->getOverloadedOperator()) + return false; + } if (!::IsStructurallyEquivalent(FD1->getIdentifier(), FD2->getIdentifier())) return false; diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp index 461084ce707c..ba1581bd3f6b 100644 --- a/lib/AST/ASTTypeTraits.cpp +++ b/lib/AST/ASTTypeTraits.cpp @@ -1,9 +1,8 @@ //===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -38,6 +37,9 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = { { NKI_None, "Type" }, #define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" }, #include "clang/AST/TypeNodes.def" + { NKI_None, "OMPClause" }, +#define OPENMP_CLAUSE(TextualSpelling, Class) {NKI_OMPClause, #Class}, +#include "clang/Basic/OpenMPKinds.def" }; bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const { @@ -104,6 +106,19 @@ ASTNodeKind ASTNodeKind::getFromNode(const Type &T) { #include "clang/AST/TypeNodes.def" } llvm_unreachable("invalid type kind"); + } + +ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) { + switch (C.getClauseKind()) { +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: return ASTNodeKind(NKI_##Class); +#include "clang/Basic/OpenMPKinds.def" + case OMPC_threadprivate: + case OMPC_uniform: + case OMPC_unknown: + llvm_unreachable("unexpected OpenMP clause kind"); + } + llvm_unreachable("invalid stmt kind"); } void DynTypedNode::print(llvm::raw_ostream &OS, @@ -152,6 +167,8 @@ SourceRange DynTypedNode::getSourceRange() const { return D->getSourceRange(); if (const Stmt *S = get<Stmt>()) return S->getSourceRange(); + if (const auto *C = get<OMPClause>()) + return SourceRange(C->getBeginLoc(), C->getEndLoc()); return SourceRange(); } diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index b06b50c9b4b8..0ef925ec1c90 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -1,9 +1,8 @@ //===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 06295b58178b..31cb36918726 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -1,9 +1,8 @@ //===----- CXXABI.h - Interface to C++ ABIs ---------------------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index ddb350e72bbd..ecf451b175af 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -1,9 +1,8 @@ //===- CXXInheritance.cpp - C++ Inheritance -------------------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -487,6 +486,21 @@ bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier, return false; } +bool CXXRecordDecl::FindOMPMapperMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + DeclarationName Name) { + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); + + for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); + Path.Decls = Path.Decls.slice(1)) { + if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPMapper)) + return true; + } + + return false; +} + bool CXXRecordDecl:: FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, @@ -540,8 +554,7 @@ void OverridingMethods::add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding) { SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides = Overrides[OverriddenSubobject]; - if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(), - Overriding) == SubobjectOverrides.end()) + if (llvm::find(SubobjectOverrides, Overriding) == SubobjectOverrides.end()) SubobjectOverrides.push_back(Overriding); } diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 0d759e226c42..25339c7901e3 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -1,9 +1,8 @@ //===--- Comment.cpp - Comment AST node implementation --------------------===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp index 5ec7586a475d..2b648cbb1d4b 100644 --- a/lib/AST/CommentBriefParser.cpp +++ b/lib/AST/CommentBriefParser.cpp @@ -1,9 +1,8 @@ //===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index 7378a7c3ac06..b306fcbb154f 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -1,9 +1,8 @@ //===--- CommentCommandTraits.cpp - Comment command properties --*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index c43275318dd7..19485f6018c0 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -1,9 +1,8 @@ //===--- CommentLexer.cpp -------------------------------------------------===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index 7f70b95e9812..c7f8aa7e16a0 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -1,9 +1,8 @@ //===--- CommentParser.cpp - Doxygen comment parser -----------------------===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index 88588a7a89e6..067b3ae4222e 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -1,9 +1,8 @@ //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/AST/ComparisonCategories.cpp b/lib/AST/ComparisonCategories.cpp index 87f51facc59b..ee4c1b0443a3 100644 --- a/lib/AST/ComparisonCategories.cpp +++ b/lib/AST/ComparisonCategories.cpp @@ -1,9 +1,8 @@ //===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/DataCollection.cpp b/lib/AST/DataCollection.cpp index c2ecabe8e6f8..8e67c101dee1 100644 --- a/lib/AST/DataCollection.cpp +++ b/lib/AST/DataCollection.cpp @@ -1,9 +1,8 @@ //===-- DataCollection.cpp --------------------------------------*- C++ -*-===// // -// 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 // //===----------------------------------------------------------------------===// diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5536358b1ecf..21cf9da18a8b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1,9 +1,8 @@ //===- Decl.cpp - Declaration AST Node Implementation ---------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -568,7 +567,14 @@ static bool isSingleLineLanguageLinkage(const Decl &D) { return false; } -static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { +/// Determine whether D is declared in the purview of a named module. +static bool isInModulePurview(const NamedDecl *D) { + if (auto *M = D->getOwningModule()) + return M->isModulePurview(); + return false; +} + +static bool isExportedFromModuleInterfaceUnit(const NamedDecl *D) { // FIXME: Handle isModulePrivate. switch (D->getModuleOwnershipKind()) { case Decl::ModuleOwnershipKind::Unowned: @@ -576,8 +582,7 @@ static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { return false; case Decl::ModuleOwnershipKind::Visible: case Decl::ModuleOwnershipKind::VisibleWhenImported: - if (auto *M = D->getOwningModule()) - return M->Kind == Module::ModuleInterfaceUnit; + return isInModulePurview(D); } llvm_unreachable("unexpected module ownership kind"); } @@ -587,9 +592,8 @@ static LinkageInfo getInternalLinkageFor(const NamedDecl *D) { // as "module-internal linkage", which means that they have internal linkage // formally but can be indirectly accessed from outside the module via inline // functions and templates defined within the module. - if (auto *M = D->getOwningModule()) - if (M->Kind == Module::ModuleInterfaceUnit) - return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); + if (isInModulePurview(D)) + return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); return LinkageInfo::internal(); } @@ -599,15 +603,25 @@ static LinkageInfo getExternalLinkageFor(const NamedDecl *D) { // - A name declared at namespace scope that does not have internal linkage // by the previous rules and that is introduced by a non-exported // declaration has module linkage. - if (auto *M = D->getOwningModule()) - if (M->Kind == Module::ModuleInterfaceUnit) - if (!isExportedFromModuleIntefaceUnit( - cast<NamedDecl>(D->getCanonicalDecl()))) - return LinkageInfo(ModuleLinkage, DefaultVisibility, false); + if (isInModulePurview(D) && !isExportedFromModuleInterfaceUnit( + cast<NamedDecl>(D->getCanonicalDecl()))) + return LinkageInfo(ModuleLinkage, DefaultVisibility, false); return LinkageInfo::external(); } +static StorageClass getStorageClass(const Decl *D) { + if (auto *TD = dyn_cast<TemplateDecl>(D)) + D = TD->getTemplatedDecl(); + if (D) { + if (auto *VD = dyn_cast<VarDecl>(D)) + return VD->getStorageClass(); + if (auto *FD = dyn_cast<FunctionDecl>(D)) + return FD->getStorageClass(); + } + return SC_None; +} + LinkageInfo LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation, @@ -619,24 +633,28 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // C++ [basic.link]p3: // A name having namespace scope (3.3.6) has internal linkage if it // is the name of - // - an object, reference, function or function template that is - // explicitly declared static; or, - // (This bullet corresponds to C99 6.2.2p3.) + + if (getStorageClass(D->getCanonicalDecl()) == SC_Static) { + // - a variable, variable template, function, or function template + // that is explicitly declared static; or + // (This bullet corresponds to C99 6.2.2p3.) + return getInternalLinkageFor(D); + } + if (const auto *Var = dyn_cast<VarDecl>(D)) { - // Explicitly declared static. - if (Var->getStorageClass() == SC_Static) - return getInternalLinkageFor(Var); - - // - a non-inline, non-volatile object or reference that is explicitly - // declared const or constexpr and neither explicitly declared extern - // nor previously declared to have external linkage; or (there is no - // equivalent in C99) - // The C++ modules TS adds "non-exported" to this list. + // - a non-template variable of non-volatile const-qualified type, unless + // - it is explicitly declared extern, or + // - it is inline or exported, or + // - it was previously declared and the prior declaration did not have + // internal linkage + // (There is no equivalent in C99.) if (Context.getLangOpts().CPlusPlus && Var->getType().isConstQualified() && !Var->getType().isVolatileQualified() && !Var->isInline() && - !isExportedFromModuleIntefaceUnit(Var)) { + !isExportedFromModuleInterfaceUnit(Var) && + !isa<VarTemplateSpecializationDecl>(Var) && + !Var->getDescribedVarTemplate()) { const VarDecl *PrevVar = Var->getPreviousDecl(); if (PrevVar) return getLVForDecl(PrevVar, computation); @@ -656,14 +674,6 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, if (PrevVar->getStorageClass() == SC_Static) return getInternalLinkageFor(Var); } - } else if (const FunctionDecl *Function = D->getAsFunction()) { - // C++ [temp]p4: - // A non-member function template can have internal linkage; any - // other template name shall have external linkage. - - // Explicitly declared static. - if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) - return getInternalLinkageFor(Function); } else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) { // - a data member of an anonymous union. const VarDecl *VD = IFD->getVarDecl(); @@ -672,6 +682,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, } assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!"); + // FIXME: This gives internal linkage to names that should have no linkage + // (those not covered by [basic.link]p6). if (D->isInAnonymousNamespace()) { const auto *Var = dyn_cast<VarDecl>(D); const auto *Func = dyn_cast<FunctionDecl>(D); @@ -731,10 +743,20 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // C++ [basic.link]p4: - // A name having namespace scope has external linkage if it is the - // name of + // A name having namespace scope that has not been given internal linkage + // above and that is the name of + // [...bullets...] + // has its linkage determined as follows: + // - if the enclosing namespace has internal linkage, the name has + // internal linkage; [handled above] + // - otherwise, if the declaration of the name is attached to a named + // module and is not exported, the name has module linkage; + // - otherwise, the name has external linkage. + // LV is currently set up to handle the last two bullets. // - // - an object or reference, unless it has internal linkage; or + // The bullets are: + + // - a variable; or if (const auto *Var = dyn_cast<VarDecl>(D)) { // GCC applies the following optimization to variables and static // data members, but not to functions: @@ -780,7 +802,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, mergeTemplateLV(LV, spec, computation); } - // - a function, unless it has internal linkage; or + // - a function; or } else if (const auto *Function = dyn_cast<FunctionDecl>(D)) { // In theory, we can modify the function's LV by the LV of its // type unless it has C linkage (see comment above about variables @@ -834,7 +856,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, mergeTemplateLV(LV, spec, computation); } - // - an enumerator belonging to an enumeration with external linkage; + // FIXME: This is not part of the C++ standard any more. + // - an enumerator belonging to an enumeration with external linkage; or } else if (isa<EnumConstantDecl>(D)) { LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), computation); @@ -842,16 +865,16 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, return LinkageInfo::none(); LV.merge(EnumLV); - // - a template, unless it is a function template that has - // internal linkage (Clause 14); + // - a template } else if (const auto *temp = dyn_cast<TemplateDecl>(D)) { bool considerVisibility = !hasExplicitVisibilityAlready(computation); LinkageInfo tempLV = getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); - // - a namespace (7.3), unless it is declared within an unnamed - // namespace. + // An unnamed namespace or a namespace declared directly or indirectly + // within an unnamed namespace has internal linkage. All other namespaces + // have external linkage. // // We handled names in anonymous namespaces above. } else if (isa<NamespaceDecl>(D)) { @@ -1508,6 +1531,11 @@ Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const { } return InternalLinkage ? M->Parent : nullptr; } + + case Module::PrivateModuleFragment: + // The private module fragment is part of its containing module for linkage + // purposes. + return M->Parent; } llvm_unreachable("unknown module kind"); @@ -1532,10 +1560,16 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, const PrintingPolicy &P) const { const DeclContext *Ctx = getDeclContext(); - // For ObjC methods, look through categories and use the interface as context. + // For ObjC methods and properties, look through categories and use the + // interface as context. if (auto *MD = dyn_cast<ObjCMethodDecl>(this)) if (auto *ID = MD->getClassInterface()) Ctx = ID; + if (auto *PD = dyn_cast<ObjCPropertyDecl>(this)) { + if (auto *MD = PD->getGetterMethodDecl()) + if (auto *ID = MD->getClassInterface()) + Ctx = ID; + } if (Ctx->isFunctionOrMethod()) { printName(OS); @@ -2211,12 +2245,16 @@ void VarDecl::setInit(Expr *I) { Init = I; } -bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const { +bool VarDecl::mightBeUsableInConstantExpressions(ASTContext &C) const { const LangOptions &Lang = C.getLangOpts(); if (!Lang.CPlusPlus) return false; + // Function parameters are never usable in constant expressions. + if (isa<ParmVarDecl>(this)) + return false; + // In C++11, any variable of reference type can be used in a constant // expression if it is initialized by a constant expression. if (Lang.CPlusPlus11 && getType()->isReferenceType()) @@ -2238,6 +2276,22 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const { return Lang.CPlusPlus11 && isConstexpr(); } +bool VarDecl::isUsableInConstantExpressions(ASTContext &Context) const { + // C++2a [expr.const]p3: + // A variable is usable in constant expressions after its initializing + // declaration is encountered... + const VarDecl *DefVD = nullptr; + const Expr *Init = getAnyInitializer(DefVD); + if (!Init || Init->isValueDependent() || getType()->isDependentType()) + return false; + // ... if it is a constexpr variable, or it is of reference type or of + // const-qualified integral or enumeration type, ... + if (!DefVD->mightBeUsableInConstantExpressions(Context)) + return false; + // ... and its initializer is a constant initializer. + return DefVD->checkInitIsICE(); +} + /// Convert the initializer for this declaration to the elaborated EvaluatedStmt /// form, which contains extra information on the evaluated value of the /// initializer. @@ -2268,7 +2322,7 @@ APValue *VarDecl::evaluateValue( // first time it is evaluated. FIXME: The notes won't always be emitted the // first time we try evaluation, so might not be produced at all. if (Eval->WasEvaluated) - return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated; + return Eval->Evaluated.isAbsent() ? nullptr : &Eval->Evaluated; const auto *Init = cast<Expr>(Eval->Value); assert(!Init->isValueDependent()); @@ -2363,6 +2417,10 @@ bool VarDecl::checkInitIsICE() const { return Eval->IsICE; } +bool VarDecl::isParameterPack() const { + return isa<PackExpansionType>(getType()); +} + template<typename DeclT> static DeclT *getDefinitionOrSelf(DeclT *D) { assert(D); @@ -2380,48 +2438,61 @@ bool VarDecl::isNonEscapingByref() const { } VarDecl *VarDecl::getTemplateInstantiationPattern() const { - // If it's a variable template specialization, find the template or partial - // specialization from which it was instantiated. - if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(this)) { - auto From = VDTemplSpec->getInstantiatedFrom(); - if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) { - while (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) { - if (NewVTD->isMemberSpecialization()) - break; - VTD = NewVTD; - } - return getDefinitionOrSelf(VTD->getTemplatedDecl()); - } - if (auto *VTPSD = - From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { - while (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) { - if (NewVTPSD->isMemberSpecialization()) - break; - VTPSD = NewVTPSD; - } - return getDefinitionOrSelf<VarDecl>(VTPSD); - } - } + const VarDecl *VD = this; - if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + // If this is an instantiated member, walk back to the template from which + // it was instantiated. + if (MemberSpecializationInfo *MSInfo = VD->getMemberSpecializationInfo()) { if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { - VarDecl *VD = getInstantiatedFromStaticDataMember(); + VD = VD->getInstantiatedFromStaticDataMember(); while (auto *NewVD = VD->getInstantiatedFromStaticDataMember()) VD = NewVD; - return getDefinitionOrSelf(VD); } } - if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) { - while (VarTemplate->getInstantiatedFromMemberTemplate()) { - if (VarTemplate->isMemberSpecialization()) + // If it's an instantiated variable template specialization, find the + // template or partial specialization from which it was instantiated. + if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(VD)) { + if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) { + auto From = VDTemplSpec->getInstantiatedFrom(); + if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) { + while (!VTD->isMemberSpecialization()) { + auto *NewVTD = VTD->getInstantiatedFromMemberTemplate(); + if (!NewVTD) + break; + VTD = NewVTD; + } + return getDefinitionOrSelf(VTD->getTemplatedDecl()); + } + if (auto *VTPSD = + From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { + while (!VTPSD->isMemberSpecialization()) { + auto *NewVTPSD = VTPSD->getInstantiatedFromMember(); + if (!NewVTPSD) + break; + VTPSD = NewVTPSD; + } + return getDefinitionOrSelf<VarDecl>(VTPSD); + } + } + } + + // If this is the pattern of a variable template, find where it was + // instantiated from. FIXME: Is this necessary? + if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) { + while (!VarTemplate->isMemberSpecialization()) { + auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate(); + if (!NewVT) break; - VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate(); + VarTemplate = NewVT; } return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); } - return nullptr; + + if (VD == this) + return nullptr; + return getDefinitionOrSelf(const_cast<VarDecl*>(VD)); } VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { @@ -2441,6 +2512,17 @@ TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { return TSK_Undeclared; } +TemplateSpecializationKind +VarDecl::getTemplateSpecializationKindForInstantiation() const { + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return MSI->getTemplateSpecializationKind(); + + if (const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(this)) + return Spec->getSpecializationKind(); + + return TSK_Undeclared; +} + SourceLocation VarDecl::getPointOfInstantiation() const { if (const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(this)) return Spec->getPointOfInstantiation(); @@ -2501,15 +2583,14 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, if (VarTemplateSpecializationDecl *Spec = dyn_cast<VarTemplateSpecializationDecl>(this)) { Spec->setSpecializationKind(TSK); - if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && Spec->getPointOfInstantiation().isInvalid()) { Spec->setPointOfInstantiation(PointOfInstantiation); if (ASTMutationListener *L = getASTContext().getASTMutationListener()) L->InstantiationRequested(this); } - } - - if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { + } else if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { MSI->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && MSI->getPointOfInstantiation().isInvalid()) { @@ -2626,10 +2707,6 @@ bool ParmVarDecl::hasDefaultArg() const { !Init.isNull(); } -bool ParmVarDecl::isParameterPack() const { - return isa<PackExpansionType>(getType()); -} - void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) { getASTContext().setParameterIndex(this, parameterIndex); ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel; @@ -2647,7 +2724,8 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, - bool isInlineSpecified, bool isConstexprSpecified) + bool isInlineSpecified, + ConstexprSpecKind ConstexprKind) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), DeclContext(DK), redeclarable_base(C), ODRHash(0), @@ -2656,7 +2734,6 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.SClass = S; FunctionDeclBits.IsInline = isInlineSpecified; FunctionDeclBits.IsInlineSpecified = isInlineSpecified; - FunctionDeclBits.IsExplicitSpecified = false; FunctionDeclBits.IsVirtualAsWritten = false; FunctionDeclBits.IsPure = false; FunctionDeclBits.HasInheritedPrototype = false; @@ -2668,7 +2745,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.IsExplicitlyDefaulted = false; FunctionDeclBits.HasImplicitReturnZero = false; FunctionDeclBits.IsLateTemplateParsed = false; - FunctionDeclBits.IsConstexpr = isConstexprSpecified; + FunctionDeclBits.ConstexprKind = ConstexprKind; FunctionDeclBits.InstantiationIsPending = false; FunctionDeclBits.UsesSEHTry = false; FunctionDeclBits.HasSkippedBody = false; @@ -2904,6 +2981,8 @@ bool FunctionDecl::isExternC() const { } bool FunctionDecl::isInExternCContext() const { + if (hasAttr<OpenCLKernelAttr>()) + return true; return getLexicalDeclContext()->isExternCContext(); } @@ -2982,16 +3061,20 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } -/// Returns a value indicating whether this function -/// corresponds to a builtin function. +/// Returns a value indicating whether this function corresponds to a builtin +/// function. /// -/// The function corresponds to a built-in function if it is -/// declared at translation scope or within an extern "C" block and -/// its name matches with the name of a builtin. The returned value -/// will be 0 for functions that do not correspond to a builtin, a -/// value of type \c Builtin::ID if in the target-independent range -/// \c [1,Builtin::First), or a target-specific builtin value. -unsigned FunctionDecl::getBuiltinID() const { +/// The function corresponds to a built-in function if it is declared at +/// translation scope or within an extern "C" block and its name matches with +/// the name of a builtin. The returned value will be 0 for functions that do +/// not correspond to a builtin, a value of type \c Builtin::ID if in the +/// target-independent range \c [1,Builtin::First), or a target-specific builtin +/// value. +/// +/// \param ConsiderWrapperFunctions If true, we should consider wrapper +/// functions as their wrapped builtins. This shouldn't be done in general, but +/// it's useful in Sema to diagnose calls to wrappers based on their semantics. +unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const { if (!getIdentifier()) return 0; @@ -3019,7 +3102,7 @@ unsigned FunctionDecl::getBuiltinID() const { // If the function is marked "overloadable", it has a different mangled name // and is not the C library function. - if (hasAttr<OverloadableAttr>()) + if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>()) return 0; if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) @@ -3030,7 +3113,7 @@ unsigned FunctionDecl::getBuiltinID() const { // function or whether it just has the same name. // If this is a static function, it's not a builtin. - if (getStorageClass() == SC_Static) + if (!ConsiderWrapperFunctions && getStorageClass() == SC_Static) return 0; // OpenCL v1.2 s6.9.f - The library functions defined in @@ -3337,7 +3420,13 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { } MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { - return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>(); + if (auto *MSI = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) + return MSI; + if (auto *FTSI = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) + return FTSI->getMemberSpecializationInfo(); + return nullptr; } void @@ -3356,6 +3445,8 @@ FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const { } void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { + assert(TemplateOrSpecialization.isNull() && + "Member function is already a specialization"); TemplateOrSpecialization = Template; } @@ -3364,19 +3455,15 @@ bool FunctionDecl::isImplicitlyInstantiable() const { if (isInvalidDecl()) return false; - switch (getTemplateSpecializationKind()) { + switch (getTemplateSpecializationKindForInstantiation()) { case TSK_Undeclared: case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: return false; case TSK_ImplicitInstantiation: return true; - // It is possible to instantiate TSK_ExplicitSpecialization kind - // if the FunctionDecl has a class scope specialization pattern. - case TSK_ExplicitSpecialization: - return getClassScopeSpecializationPattern() != nullptr; - case TSK_ExplicitInstantiationDeclaration: // Handled below. break; @@ -3399,26 +3486,12 @@ bool FunctionDecl::isImplicitlyInstantiable() const { } bool FunctionDecl::isTemplateInstantiation() const { - switch (getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return false; - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - return true; - } - llvm_unreachable("All TSK values handled."); + // FIXME: Remove this, it's not clear what it means. (Which template + // specialization kind?) + return clang::isTemplateInstantiation(getTemplateSpecializationKind()); } FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { - // Handle class scope explicit specialization special case. - if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { - if (auto *Spec = getClassScopeSpecializationPattern()) - return getDefinitionOrSelf(Spec); - return nullptr; - } - // If this is a generic lambda call operator specialization, its // instantiation pattern is always its primary template's pattern // even if its primary template was instantiated from another @@ -3434,21 +3507,28 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl()); } + if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) { + if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind())) + return nullptr; + return getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom())); + } + + if (!clang::isTemplateInstantiation(getTemplateSpecializationKind())) + return nullptr; + if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { - while (Primary->getInstantiatedFromMemberTemplate()) { - // If we have hit a point where the user provided a specialization of - // this template, we're done looking. - if (Primary->isMemberSpecialization()) + // If we hit a point where the user provided a specialization of this + // template, we're done looking. + while (!Primary->isMemberSpecialization()) { + auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate(); + if (!NewPrimary) break; - Primary = Primary->getInstantiatedFromMemberTemplate(); + Primary = NewPrimary; } return getDefinitionOrSelf(Primary->getTemplatedDecl()); } - if (auto *MFD = getInstantiatedFromMemberFunction()) - return getDefinitionOrSelf(MFD); - return nullptr; } @@ -3456,15 +3536,11 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast<FunctionTemplateSpecializationInfo*>()) { - return Info->Template.getPointer(); + return Info->getTemplate(); } return nullptr; } -FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const { - return getASTContext().getClassScopeSpecializationPattern(this); -} - FunctionTemplateSpecializationInfo * FunctionDecl::getTemplateSpecializationInfo() const { return TemplateOrSpecialization @@ -3499,15 +3575,19 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, TemplateSpecializationKind TSK, const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation PointOfInstantiation) { + assert((TemplateOrSpecialization.isNull() || + TemplateOrSpecialization.is<MemberSpecializationInfo *>()) && + "Member function is already a specialization"); assert(TSK != TSK_Undeclared && "Must specify the type of function template specialization"); - FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (!Info) - Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK, - TemplateArgs, - TemplateArgsAsWritten, - PointOfInstantiation); + assert((TemplateOrSpecialization.isNull() || + TSK == TSK_ExplicitSpecialization) && + "Member specialization must be an explicit specialization"); + FunctionTemplateSpecializationInfo *Info = + FunctionTemplateSpecializationInfo::Create( + C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten, + PointOfInstantiation, + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()); TemplateOrSpecialization = Info; Template->addSpecialization(Info, InsertPos); } @@ -3558,14 +3638,47 @@ DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. - FunctionTemplateSpecializationInfo *FTSInfo - = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (FTSInfo) + if (FunctionTemplateSpecializationInfo *FTSInfo = + TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) + return FTSInfo->getTemplateSpecializationKind(); + + if (MemberSpecializationInfo *MSInfo = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +TemplateSpecializationKind +FunctionDecl::getTemplateSpecializationKindForInstantiation() const { + // This is the same as getTemplateSpecializationKind(), except that for a + // function that is both a function template specialization and a member + // specialization, we prefer the member specialization information. Eg: + // + // template<typename T> struct A { + // template<typename U> void f() {} + // template<> void f<int>() {} + // }; + // + // For A<int>::f<int>(): + // * getTemplateSpecializationKind() will return TSK_ExplicitSpecialization + // * getTemplateSpecializationKindForInstantiation() will return + // TSK_ImplicitInstantiation + // + // This reflects the facts that A<int>::f<int> is an explicit specialization + // of A<int>::f, and that A<int>::f<int> should be implicitly instantiated + // from A::f<int> if a definition is needed. + if (FunctionTemplateSpecializationInfo *FTSInfo = + TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) { + if (auto *MSInfo = FTSInfo->getMemberSpecializationInfo()) + return MSInfo->getTemplateSpecializationKind(); return FTSInfo->getTemplateSpecializationKind(); + } - MemberSpecializationInfo *MSInfo - = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); - if (MSInfo) + if (MemberSpecializationInfo *MSInfo = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) return MSInfo->getTemplateSpecializationKind(); return TSK_Undeclared; @@ -3673,6 +3786,10 @@ unsigned FunctionDecl::getMemoryFunctionKind() const { case Builtin::BImemcmp: return Builtin::BImemcmp; + case Builtin::BI__builtin_bcmp: + case Builtin::BIbcmp: + return Builtin::BIbcmp; + case Builtin::BI__builtin_strncpy: case Builtin::BI__builtin___strncpy_chk: case Builtin::BIstrncpy: @@ -3713,6 +3830,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const { return Builtin::BImemmove; else if (FnInfo->isStr("memcmp")) return Builtin::BImemcmp; + else if (FnInfo->isStr("bcmp")) + return Builtin::BIbcmp; else if (FnInfo->isStr("strncpy")) return Builtin::BIstrncpy; else if (FnInfo->isStr("strncmp")) @@ -3794,6 +3913,39 @@ bool FieldDecl::isZeroLengthBitField(const ASTContext &Ctx) const { getBitWidthValue(Ctx) == 0; } +bool FieldDecl::isZeroSize(const ASTContext &Ctx) const { + if (isZeroLengthBitField(Ctx)) + return true; + + // C++2a [intro.object]p7: + // An object has nonzero size if it + // -- is not a potentially-overlapping subobject, or + if (!hasAttr<NoUniqueAddressAttr>()) + return false; + + // -- is not of class type, or + const auto *RT = getType()->getAs<RecordType>(); + if (!RT) + return false; + const RecordDecl *RD = RT->getDecl()->getDefinition(); + if (!RD) { + assert(isInvalidDecl() && "valid field has incomplete type"); + return false; + } + + // -- [has] virtual member functions or virtual base classes, or + // -- has subobjects of nonzero size or bit-fields of nonzero length + const auto *CXXRD = cast<CXXRecordDecl>(RD); + if (!CXXRD->isEmpty()) + return false; + + // Otherwise, [...] the circumstances under which the object has zero size + // are implementation-defined. + // FIXME: This might be Itanium ABI specific; we don't yet know what the MS + // ABI will do. + return true; +} + unsigned FieldDecl::getFieldIndex() const { const FieldDecl *Canonical = getCanonicalDecl(); if (Canonical != this) @@ -4100,6 +4252,9 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C, setNonTrivialToPrimitiveDefaultInitialize(false); setNonTrivialToPrimitiveCopy(false); setNonTrivialToPrimitiveDestroy(false); + setHasNonTrivialToPrimitiveDefaultInitializeCUnion(false); + setHasNonTrivialToPrimitiveDestructCUnion(false); + setHasNonTrivialToPrimitiveCopyCUnion(false); setParamDestroyedInCallee(false); setArgPassingRestrictions(APK_CanPassInRegs); } @@ -4260,6 +4415,7 @@ BlockDecl::BlockDecl(DeclContext *DC, SourceLocation CaretLoc) setBlockMissingReturnType(true); setIsConversionFromLambda(false); setDoesNotEscape(false); + setCanAvoidCopyToHeap(false); } void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) { @@ -4422,13 +4578,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - StorageClass SC, - bool isInlineSpecified, + StorageClass SC, bool isInlineSpecified, bool hasWrittenPrototype, - bool isConstexprSpecified) { + ConstexprSpecKind ConstexprKind) { FunctionDecl *New = new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo, - SC, isInlineSpecified, isConstexprSpecified); + SC, isInlineSpecified, ConstexprKind); New->setHasWrittenPrototype(hasWrittenPrototype); return New; } @@ -4436,7 +4591,7 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - SC_None, false, false); + SC_None, false, CSK_unspecified); } BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index b83082e9eb08..fd80e1532eb5 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -1,9 +1,8 @@ //===- DeclBase.cpp - Declaration AST Node Implementation -----------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -209,8 +208,8 @@ bool Decl::isTemplateParameterPack() const { } bool Decl::isParameterPack() const { - if (const auto *Parm = dyn_cast<ParmVarDecl>(this)) - return Parm->isParameterPack(); + if (const auto *Var = dyn_cast<VarDecl>(this)) + return Var->isParameterPack(); return isTemplateParameterPack(); } @@ -355,7 +354,8 @@ bool Decl::isInAnonymousNamespace() const { } bool Decl::isInStdNamespace() const { - return getDeclContext()->isStdNamespace(); + const DeclContext *DC = getDeclContext(); + return DC && DC->isStdNamespace(); } TranslationUnitDecl *Decl::getTranslationUnitDecl() { @@ -431,22 +431,6 @@ bool Decl::isReferenced() const { return false; } -bool Decl::isExported() const { - if (isModulePrivate()) - return false; - // Namespaces are always exported. - if (isa<TranslationUnitDecl>(this) || isa<NamespaceDecl>(this)) - return true; - // Otherwise, this is a strictly lexical check. - for (auto *DC = getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) { - if (cast<Decl>(DC)->isModulePrivate()) - return false; - if (isa<ExportDecl>(DC)) - return true; - } - return false; -} - ExternalSourceSymbolAttr *Decl::getExternalSourceSymbolAttr() const { const Decl *Definition = nullptr; if (auto *ID = dyn_cast<ObjCInterfaceDecl>(this)) { @@ -726,6 +710,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Binding: case NonTypeTemplateParm: case VarTemplate: + case Concept: // These (C++-only) declarations are found by redeclaration lookup for // tag types, so we include them in the tag namespace. return IDNS_Ordinary | IDNS_Tag; @@ -781,6 +766,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case OMPDeclareReduction: return IDNS_OMPReduction; + case OMPDeclareMapper: + return IDNS_OMPMapper; + // Never have names. case Friend: case FriendTemplate: @@ -810,6 +798,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCCategoryImpl: case Import: case OMPThreadPrivate: + case OMPAllocate: case OMPRequires: case OMPCapturedExpr: case Empty: @@ -932,6 +921,7 @@ bool Decl::AccessDeclContextSanity() const { if (isa<TranslationUnitDecl>(this) || isa<TemplateTypeParmDecl>(this) || isa<NonTypeTemplateParmDecl>(this) || + !getDeclContext() || !isa<CXXRecordDecl>(getDeclContext()) || isInvalidDecl() || isa<StaticAssertDecl>(this) || @@ -969,6 +959,8 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const { if (Ty->isFunctionPointerType()) Ty = Ty->getAs<PointerType>()->getPointeeType(); + else if (Ty->isFunctionReferenceType()) + Ty = Ty->getAs<ReferenceType>()->getPointeeType(); else if (BlocksToo && Ty->isBlockPointerType()) Ty = Ty->getAs<BlockPointerType>()->getPointeeType(); @@ -1054,6 +1046,18 @@ DeclContext *DeclContext::getLookupParent() { return getParent(); } +const BlockDecl *DeclContext::getInnermostBlockDecl() const { + const DeclContext *Ctx = this; + + do { + if (Ctx->isClosure()) + return cast<BlockDecl>(Ctx); + Ctx = Ctx->getParent(); + } while (Ctx); + + return nullptr; +} + bool DeclContext::isInlineNamespace() const { return isNamespace() && cast<NamespaceDecl>(this)->isInline(); @@ -1164,6 +1168,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::Block: case Decl::Captured: case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: // There is only one DeclContext for these entities. return this; @@ -1175,13 +1180,15 @@ DeclContext *DeclContext::getPrimaryContext() { return this; case Decl::ObjCInterface: - if (auto *Def = cast<ObjCInterfaceDecl>(this)->getDefinition()) - return Def; + if (auto *OID = dyn_cast<ObjCInterfaceDecl>(this)) + if (auto *Def = OID->getDefinition()) + return Def; return this; case Decl::ObjCProtocol: - if (auto *Def = cast<ObjCProtocolDecl>(this)->getDefinition()) - return Def; + if (auto *OPD = dyn_cast<ObjCProtocolDecl>(this)) + if (auto *Def = OPD->getDefinition()) + return Def; return this; case Decl::ObjCCategory: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 31ffeb0dcd1e..59710a55498f 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1,9 +1,8 @@ //===- DeclCXX.cpp - C++ Declaration AST Node Implementation --------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -606,14 +605,19 @@ bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType( // that sure looks like a wording bug. // -- If X is a non-union class type with a non-static data member - // [recurse to] the first non-static data member of X + // [recurse to each field] that is either of zero size or is the + // first non-static data member of X // -- If X is a union type, [recurse to union members] + bool IsFirstField = true; for (auto *FD : X->fields()) { // FIXME: Should we really care about the type of the first non-static // data member of a non-union if there are preceding unnamed bit-fields? if (FD->isUnnamedBitfield()) continue; + if (!IsFirstField && !FD->isZeroSize(Ctx)) + continue; + // -- If X is n array type, [visit the element type] QualType T = Ctx.getBaseElementType(FD->getType()); if (auto *RD = T->getAsCXXRecordDecl()) @@ -621,7 +625,7 @@ bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType( return true; if (!X->isUnion()) - break; + IsFirstField = false; } } @@ -641,7 +645,8 @@ bool CXXRecordDecl::lambdaIsDefaultConstructibleAndAssignable() const { // C++17 [expr.prim.lambda]p21: // The closure type associated with a lambda-expression has no default // constructor and a deleted copy assignment operator. - if (getLambdaCaptureDefault() != LCD_None) + if (getLambdaCaptureDefault() != LCD_None || + getLambdaData().NumCaptures != 0) return false; return getASTContext().getLangOpts().CPlusPlus2a; } @@ -992,6 +997,17 @@ void CXXRecordDecl::addedMember(Decl *D) { setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs); Data.HasIrrelevantDestructor = false; + + if (isUnion()) { + data().DefaultedCopyConstructorIsDeleted = true; + data().DefaultedMoveConstructorIsDeleted = true; + data().DefaultedMoveAssignmentIsDeleted = true; + data().DefaultedDestructorIsDeleted = true; + data().NeedOverloadResolutionForCopyConstructor = true; + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForMoveAssignment = true; + data().NeedOverloadResolutionForDestructor = true; + } } else if (!Context.getLangOpts().ObjCAutoRefCount) { setHasObjectMember(true); } @@ -1058,6 +1074,10 @@ void CXXRecordDecl::addedMember(Decl *D) { if (T->isReferenceType()) data().DefaultedMoveAssignmentIsDeleted = true; + // Bitfields of length 0 are also zero-sized, but we already bailed out for + // those because they are always unnamed. + bool IsZeroSize = Field->isZeroSize(Context); + if (const auto *RecordTy = T->getAs<RecordType>()) { auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { @@ -1173,7 +1193,8 @@ void CXXRecordDecl::addedMember(Decl *D) { // A standard-layout class is a class that: // [...] // -- has no element of the set M(S) of types as a base class. - if (data().IsStandardLayout && (isUnion() || IsFirstField) && + if (data().IsStandardLayout && + (isUnion() || IsFirstField || IsZeroSize) && hasSubobjectAtOffsetZeroOfEmptyBaseType(Context, FieldRec)) data().IsStandardLayout = false; @@ -1255,8 +1276,10 @@ void CXXRecordDecl::addedMember(Decl *D) { } // C++14 [meta.unary.prop]p4: - // T is a class type [...] with [...] no non-static data members - data().Empty = false; + // T is a class type [...] with [...] no non-static data members other + // than subobjects of zero size + if (data().Empty && !IsZeroSize) + data().Empty = false; } // Handle using declarations of conversion functions. @@ -1411,13 +1434,28 @@ void CXXRecordDecl::getCaptureFields( TemplateParameterList * CXXRecordDecl::getGenericLambdaTemplateParameterList() const { - if (!isLambda()) return nullptr; + if (!isGenericLambda()) return nullptr; CXXMethodDecl *CallOp = getLambdaCallOperator(); if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate()) return Tmpl->getTemplateParameters(); return nullptr; } +ArrayRef<NamedDecl *> +CXXRecordDecl::getLambdaExplicitTemplateParameters() const { + TemplateParameterList *List = getGenericLambdaTemplateParameterList(); + if (!List) + return {}; + + assert(std::is_partitioned(List->begin(), List->end(), + [](const NamedDecl *D) { return !D->isImplicit(); }) + && "Explicit template params should be ordered before implicit ones"); + + const auto ExplicitEnd = llvm::partition_point( + *List, [](const NamedDecl *D) { return !D->isImplicit(); }); + return llvm::makeArrayRef(List->begin(), ExplicitEnd); +} + Decl *CXXRecordDecl::getLambdaContextDecl() const { assert(isLambda() && "Not a lambda closure type!"); ExternalASTSource *Source = getParentASTContext().getExternalSource(); @@ -1586,8 +1624,8 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { for (unsigned I = 0, E = Convs.size(); I != E; ++I) { if (Convs[I].getDecl() == ConvDecl) { Convs.erase(I); - assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end() - && "conversion was found multiple times in unresolved set"); + assert(llvm::find(Convs, ConvDecl) == Convs.end() && + "conversion was found multiple times in unresolved set"); return; } } @@ -1852,19 +1890,47 @@ bool CXXRecordDecl::mayBeAbstract() const { void CXXDeductionGuideDecl::anchor() {} +bool ExplicitSpecifier::isEquivalent(const ExplicitSpecifier Other) const { + if ((getKind() != Other.getKind() || + getKind() == ExplicitSpecKind::Unresolved)) { + if (getKind() == ExplicitSpecKind::Unresolved && + Other.getKind() == ExplicitSpecKind::Unresolved) { + ODRHash SelfHash, OtherHash; + SelfHash.AddStmt(getExpr()); + OtherHash.AddStmt(Other.getExpr()); + return SelfHash.CalculateHash() == OtherHash.CalculateHash(); + } else + return false; + } + return true; +} + +ExplicitSpecifier ExplicitSpecifier::getFromDecl(FunctionDecl *Function) { + switch (Function->getDeclKind()) { + case Decl::Kind::CXXConstructor: + return cast<CXXConstructorDecl>(Function)->getExplicitSpecifier(); + case Decl::Kind::CXXConversion: + return cast<CXXConversionDecl>(Function)->getExplicitSpecifier(); + case Decl::Kind::CXXDeductionGuide: + return cast<CXXDeductionGuideDecl>(Function)->getExplicitSpecifier(); + default: + return {}; + } +} + CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create( - ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit, - const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - SourceLocation EndLocation) { - return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, IsExplicit, - NameInfo, T, TInfo, EndLocation); + ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, SourceLocation EndLocation) { + return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T, + TInfo, EndLocation); } CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) CXXDeductionGuideDecl(C, nullptr, SourceLocation(), false, - DeclarationNameInfo(), QualType(), - nullptr, SourceLocation()); + return new (C, ID) CXXDeductionGuideDecl( + C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(), + QualType(), nullptr, SourceLocation()); } void CXXMethodDecl::anchor() {} @@ -1891,8 +1957,8 @@ static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, } CXXMethodDecl * -CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, - bool MayBeBase) { +CXXMethodDecl::getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD, + bool MayBeBase) { if (this->getParent()->getCanonicalDecl() == RD->getCanonicalDecl()) return this; @@ -1918,6 +1984,15 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, return MD; } + return nullptr; +} + +CXXMethodDecl * +CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, + bool MayBeBase) { + if (auto *MD = getCorrespondingMethodDeclaredInClass(RD, MayBeBase)) + return MD; + for (const auto &I : RD->bases()) { const RecordType *RT = I.getType()->getAs<RecordType>(); if (!RT) @@ -1931,22 +2006,22 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, return nullptr; } -CXXMethodDecl * -CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - StorageClass SC, bool isInline, - bool isConstexpr, SourceLocation EndLocation) { - return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, - T, TInfo, SC, isInline, isConstexpr, - EndLocation); +CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass SC, bool isInline, + ConstexprSpecKind ConstexprKind, + SourceLocation EndLocation) { + return new (C, RD) + CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, + isInline, ConstexprKind, EndLocation); } CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(), - DeclarationNameInfo(), QualType(), nullptr, - SC_None, false, false, SourceLocation()); + return new (C, ID) CXXMethodDecl( + CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(), + QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation()); } CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, @@ -2081,8 +2156,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction( return false; // In C++17 onwards, all potential usual deallocation functions are actual - // usual deallocation functions. - if (Context.getLangOpts().AlignedAllocation) + // usual deallocation functions. Honor this behavior when post-C++14 + // deallocation functions are offered as extensions too. + // FIXME(EricWF): Destrying Delete should be a language option. How do we + // handle when destroying delete is used prior to C++17? + if (Context.getLangOpts().CPlusPlus17 || + Context.getLangOpts().AlignedAllocation || + isDestroyingOperatorDelete()) return true; // This function is a usual deallocation function if there are no @@ -2173,12 +2253,23 @@ CXXMethodDecl::overridden_methods() const { return getASTContext().overridden_methods(this); } +static QualType getThisObjectType(ASTContext &C, const FunctionProtoType *FPT, + const CXXRecordDecl *Decl) { + QualType ClassTy = C.getTypeDeclType(Decl); + return C.getQualifiedType(ClassTy, FPT->getMethodQuals()); +} + QualType CXXMethodDecl::getThisType(const FunctionProtoType *FPT, const CXXRecordDecl *Decl) { ASTContext &C = Decl->getASTContext(); - QualType ClassTy = C.getTypeDeclType(Decl); - ClassTy = C.getQualifiedType(ClassTy, FPT->getTypeQuals()); - return C.getPointerType(ClassTy); + QualType ObjectTy = ::getThisObjectType(C, FPT, Decl); + return C.getPointerType(ObjectTy); +} + +QualType CXXMethodDecl::getThisObjectType(const FunctionProtoType *FPT, + const CXXRecordDecl *Decl) { + ASTContext &C = Decl->getASTContext(); + return ::getThisObjectType(C, FPT, Decl); } QualType CXXMethodDecl::getThisType() const { @@ -2193,6 +2284,14 @@ QualType CXXMethodDecl::getThisType() const { getParent()); } +QualType CXXMethodDecl::getThisObjectType() const { + // Ditto getThisType. + assert(isInstance() && "No 'this' for static methods!"); + + return CXXMethodDecl::getThisObjectType(getType()->getAs<FunctionProtoType>(), + getParent()); +} + bool CXXMethodDecl::hasInlineBody() const { // If this function is a template instantiation, look at the template from // which it was instantiated. @@ -2297,47 +2396,55 @@ SourceRange CXXCtorInitializer::getSourceRange() const { CXXConstructorDecl::CXXConstructorDecl( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared, - bool isConstexpr, InheritedConstructor Inherited) + ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, + ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, isConstexpr, SourceLocation()) { + SC_None, isInline, ConstexprKind, SourceLocation()) { setNumCtorInitializers(0); setInheritingConstructor(static_cast<bool>(Inherited)); setImplicit(isImplicitlyDeclared); + CXXConstructorDeclBits.HasTrailingExplicitSpecifier = ES.getExpr() ? 1 : 0; if (Inherited) *getTrailingObjects<InheritedConstructor>() = Inherited; - setExplicitSpecified(isExplicitSpecified); + setExplicitSpecifier(ES); } void CXXConstructorDecl::anchor() {} CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID, - bool Inherited) { - unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited); - auto *Result = new (C, ID, Extra) CXXConstructorDecl( - C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - false, false, false, false, InheritedConstructor()); - Result->setInheritingConstructor(Inherited); + uint64_t AllocKind) { + bool hasTraillingExplicit = static_cast<bool>(AllocKind & TAKHasTailExplicit); + bool isInheritingConstructor = + static_cast<bool>(AllocKind & TAKInheritsConstructor); + unsigned Extra = + additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>( + isInheritingConstructor, hasTraillingExplicit); + auto *Result = new (C, ID, Extra) + CXXConstructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(), + QualType(), nullptr, ExplicitSpecifier(), false, false, + CSK_unspecified, InheritedConstructor()); + Result->setInheritingConstructor(isInheritingConstructor); + Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier = + hasTraillingExplicit; + Result->setExplicitSpecifier(ExplicitSpecifier()); return Result; } -CXXConstructorDecl * -CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isExplicit, bool isInline, - bool isImplicitlyDeclared, bool isConstexpr, - InheritedConstructor Inherited) { +CXXConstructorDecl *CXXConstructorDecl::Create( + ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, + ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); unsigned Extra = - additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0); - return new (C, RD, Extra) CXXConstructorDecl( - C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline, - isImplicitlyDeclared, isConstexpr, Inherited); + additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>( + Inherited ? 1 : 0, ES.getExpr() ? 1 : 0); + return new (C, RD, Extra) + CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline, + isImplicitlyDeclared, ConstexprKind, Inherited); } CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const { @@ -2488,25 +2595,22 @@ void CXXConversionDecl::anchor() {} CXXConversionDecl * CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(), - DeclarationNameInfo(), QualType(), - nullptr, false, false, false, - SourceLocation()); + return new (C, ID) CXXConversionDecl( + C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, + false, ExplicitSpecifier(), CSK_unspecified, SourceLocation()); } -CXXConversionDecl * -CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicit, - bool isConstexpr, SourceLocation EndLocation) { +CXXConversionDecl *CXXConversionDecl::Create( + ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind, + SourceLocation EndLocation) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, - isInline, isExplicit, isConstexpr, - EndLocation); + return new (C, RD) + CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES, + ConstexprKind, EndLocation); } bool CXXConversionDecl::isLambdaToBlockPointerConversion() const { @@ -2857,6 +2961,12 @@ BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr); } +ValueDecl *BindingDecl::getDecomposedDecl() const { + ExternalASTSource *Source = + Decomp.isOffset() ? getASTContext().getExternalSource() : nullptr; + return cast_or_null<ValueDecl>(Decomp.get(Source)); +} + VarDecl *BindingDecl::getHoldingVar() const { Expr *B = getBinding(); if (!B) diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp index 08fbed361579..8ec1dea84df5 100644 --- a/lib/AST/DeclFriend.cpp +++ b/lib/AST/DeclFriend.cpp @@ -1,9 +1,8 @@ //===- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation ----===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp index f74ef9bbb839..27dbdaab6f30 100644 --- a/lib/AST/DeclGroup.cpp +++ b/lib/AST/DeclGroup.cpp @@ -1,9 +1,8 @@ //===- DeclGroup.cpp - Classes for representing groups of Decls -----------===// // -// 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 // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 1ed7fc71b025..bf748fbab8e9 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -1,9 +1,8 @@ //===- DeclObjC.cpp - ObjC Declaration AST Node Implementation ------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -1642,7 +1641,7 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { if (!layout.empty()) { // Order synthesized ivars by their size. - std::stable_sort(layout.begin(), layout.end()); + llvm::stable_sort(layout); unsigned Ix = 0, EIx = layout.size(); if (!data().IvarList) { data().IvarList = layout[0].Ivar; Ix++; diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp index b77a67cbf38d..af321280d417 100644 --- a/lib/AST/DeclOpenMP.cpp +++ b/lib/AST/DeclOpenMP.cpp @@ -1,9 +1,8 @@ //===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===// // -// 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 // //===----------------------------------------------------------------------===// /// \file @@ -54,6 +53,49 @@ void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) { } //===----------------------------------------------------------------------===// +// OMPAllocateDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPAllocateDecl::anchor() { } + +OMPAllocateDecl *OMPAllocateDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, ArrayRef<Expr *> VL, + ArrayRef<OMPClause *> CL) { + OMPAllocateDecl *D = new ( + C, DC, additionalSizeToAlloc<Expr *, OMPClause *>(VL.size(), CL.size())) + OMPAllocateDecl(OMPAllocate, DC, L); + D->NumVars = VL.size(); + D->setVars(VL); + D->NumClauses = CL.size(); + D->setClauses(CL); + return D; +} + +OMPAllocateDecl *OMPAllocateDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NVars, + unsigned NClauses) { + OMPAllocateDecl *D = + new (C, ID, additionalSizeToAlloc<Expr *, OMPClause *>(NVars, NClauses)) + OMPAllocateDecl(OMPAllocate, nullptr, SourceLocation()); + D->NumVars = NVars; + D->NumClauses = NClauses; + return D; +} + +void OMPAllocateDecl::setVars(ArrayRef<Expr *> VL) { + assert(VL.size() == NumVars && + "Number of variables is not the same as the preallocated buffer"); + std::uninitialized_copy(VL.begin(), VL.end(), getTrailingObjects<Expr *>()); +} + +void OMPAllocateDecl::setClauses(ArrayRef<OMPClause *> CL) { + assert(CL.size() == NumClauses && + "Number of variables is not the same as the preallocated buffer"); + std::uninitialized_copy(CL.begin(), CL.end(), + getTrailingObjects<OMPClause *>()); +} + +//===----------------------------------------------------------------------===// // OMPRequiresDecl Implementation. //===----------------------------------------------------------------------===// @@ -124,6 +166,66 @@ OMPDeclareReductionDecl::getPrevDeclInScope() const { } //===----------------------------------------------------------------------===// +// OMPDeclareMapperDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPDeclareMapperDecl::anchor() {} + +OMPDeclareMapperDecl * +OMPDeclareMapperDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, QualType T, + DeclarationName VarName, + OMPDeclareMapperDecl *PrevDeclInScope) { + return new (C, DC) OMPDeclareMapperDecl(OMPDeclareMapper, DC, L, Name, T, + VarName, PrevDeclInScope); +} + +OMPDeclareMapperDecl *OMPDeclareMapperDecl::CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned N) { + auto *D = new (C, ID) + OMPDeclareMapperDecl(OMPDeclareMapper, /*DC=*/nullptr, SourceLocation(), + DeclarationName(), QualType(), DeclarationName(), + /*PrevDeclInScope=*/nullptr); + if (N) { + auto **ClauseStorage = C.Allocate<OMPClause *>(N); + D->Clauses = llvm::makeMutableArrayRef<OMPClause *>(ClauseStorage, N); + } + return D; +} + +/// Creates an array of clauses to this mapper declaration and intializes +/// them. The space used to store clause pointers is dynamically allocated, +/// because we do not know the number of clauses when creating +/// OMPDeclareMapperDecl +void OMPDeclareMapperDecl::CreateClauses(ASTContext &C, + ArrayRef<OMPClause *> CL) { + assert(Clauses.empty() && "Number of clauses should be 0 on initialization"); + size_t NumClauses = CL.size(); + if (NumClauses) { + auto **ClauseStorage = C.Allocate<OMPClause *>(NumClauses); + Clauses = llvm::makeMutableArrayRef<OMPClause *>(ClauseStorage, NumClauses); + setClauses(CL); + } +} + +void OMPDeclareMapperDecl::setClauses(ArrayRef<OMPClause *> CL) { + assert(CL.size() == Clauses.size() && + "Number of clauses is not the same as the preallocated buffer"); + std::uninitialized_copy(CL.begin(), CL.end(), Clauses.data()); +} + +OMPDeclareMapperDecl *OMPDeclareMapperDecl::getPrevDeclInScope() { + return cast_or_null<OMPDeclareMapperDecl>( + PrevDeclInScope.get(getASTContext().getExternalSource())); +} + +const OMPDeclareMapperDecl *OMPDeclareMapperDecl::getPrevDeclInScope() const { + return cast_or_null<OMPDeclareMapperDecl>( + PrevDeclInScope.get(getASTContext().getExternalSource())); +} + +//===----------------------------------------------------------------------===// // OMPCapturedExprDecl Implementation. //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 517851f9eeb1..f5c69944034a 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -1,9 +1,8 @@ //===--- DeclPrinter.cpp - Printing implementation for Decl ASTs ----------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -16,6 +15,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -100,11 +100,14 @@ namespace { void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPAllocateDecl(OMPAllocateDecl *D); void VisitOMPRequiresDecl(OMPRequiresDecl *D); void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D); void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); - void printTemplateParameters(const TemplateParameterList *Params); + void printTemplateParameters(const TemplateParameterList *Params, + bool OmitTemplateKW = false); void printTemplateArguments(const TemplateArgumentList &Args, const TemplateParameterList *Params = nullptr); |