2010-08-18 23:56:31 +00:00
|
|
|
//===--- ASTWriterDecl.cpp - Declaration Serialization --------------------===//
|
2009-04-27 06:16:06 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// 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
|
2009-04-27 06:16:06 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements serialization for Declarations.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-04-24 16:28:13 +00:00
|
|
|
#include "ASTCommon.h"
|
2019-11-15 17:31:55 -08:00
|
|
|
#include "clang/AST/Attr.h"
|
2010-05-07 21:43:38 +00:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2012-12-04 09:13:33 +00:00
|
|
|
#include "clang/AST/DeclVisitor.h"
|
2009-04-27 06:16:06 +00:00
|
|
|
#include "clang/AST/Expr.h"
|
2018-09-26 04:28:39 +00:00
|
|
|
#include "clang/AST/OpenMPClause.h"
|
2018-03-23 00:07:18 +00:00
|
|
|
#include "clang/AST/PrettyDeclStackTrace.h"
|
2011-10-28 22:54:21 +00:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2012-12-04 09:13:33 +00:00
|
|
|
#include "clang/Serialization/ASTReader.h"
|
2019-12-14 03:17:03 -05:00
|
|
|
#include "clang/Serialization/ASTRecordWriter.h"
|
2019-07-03 22:40:07 +00:00
|
|
|
#include "llvm/Bitstream/BitstreamWriter.h"
|
2009-12-03 09:13:36 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2023-01-14 11:07:21 -08:00
|
|
|
#include <optional>
|
2009-04-27 06:16:06 +00:00
|
|
|
using namespace clang;
|
2011-04-24 16:28:13 +00:00
|
|
|
using namespace serialization;
|
2009-04-27 06:16:06 +00:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Declaration serialization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-06-29 22:47:00 +00:00
|
|
|
namespace clang {
|
2010-08-18 23:56:27 +00:00
|
|
|
class ASTDeclWriter : public DeclVisitor<ASTDeclWriter, void> {
|
2010-08-18 23:56:21 +00:00
|
|
|
ASTWriter &Writer;
|
2016-04-01 22:52:03 +00:00
|
|
|
ASTRecordWriter Record;
|
2009-04-27 06:16:06 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
serialization::DeclCode Code;
|
2009-04-27 07:35:58 +00:00
|
|
|
unsigned AbbrevToUse;
|
2009-04-27 06:16:06 +00:00
|
|
|
|
2024-03-08 10:12:51 +08:00
|
|
|
bool GeneratingReducedBMI = false;
|
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
public:
|
|
|
|
ASTDeclWriter(ASTWriter &Writer, ASTContext &Context,
|
2024-03-08 10:12:51 +08:00
|
|
|
ASTWriter::RecordDataImpl &Record, bool GeneratingReducedBMI)
|
2024-11-07 14:40:21 -08:00
|
|
|
: Writer(Writer), Record(Context, Writer, Record),
|
2024-03-08 10:12:51 +08:00
|
|
|
Code((serialization::DeclCode)0), AbbrevToUse(0),
|
|
|
|
GeneratingReducedBMI(GeneratingReducedBMI) {}
|
2016-04-01 22:52:03 +00:00
|
|
|
|
|
|
|
uint64_t Emit(Decl *D) {
|
|
|
|
if (!Code)
|
|
|
|
llvm::report_fatal_error(StringRef("unexpected declaration kind '") +
|
|
|
|
D->getDeclKindName() + "'");
|
2016-04-14 00:29:55 +00:00
|
|
|
return Record.Emit(Code, AbbrevToUse);
|
2009-04-27 07:35:58 +00:00
|
|
|
}
|
2010-10-24 17:26:27 +00:00
|
|
|
|
2010-07-02 15:58:43 +00:00
|
|
|
void Visit(Decl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
|
|
|
|
void VisitDecl(Decl *D);
|
2016-03-02 17:28:48 +00:00
|
|
|
void VisitPragmaCommentDecl(PragmaCommentDecl *D);
|
2016-03-02 19:28:54 +00:00
|
|
|
void VisitPragmaDetectMismatchDecl(PragmaDetectMismatchDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitTranslationUnitDecl(TranslationUnitDecl *D);
|
|
|
|
void VisitNamedDecl(NamedDecl *D);
|
2011-02-17 07:39:24 +00:00
|
|
|
void VisitLabelDecl(LabelDecl *LD);
|
2010-02-21 18:22:14 +00:00
|
|
|
void VisitNamespaceDecl(NamespaceDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
|
|
|
|
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitTypeDecl(TypeDecl *D);
|
2011-12-19 14:40:25 +00:00
|
|
|
void VisitTypedefNameDecl(TypedefNameDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitTypedefDecl(TypedefDecl *D);
|
2011-04-15 14:24:37 +00:00
|
|
|
void VisitTypeAliasDecl(TypeAliasDecl *D);
|
2010-06-30 08:49:30 +00:00
|
|
|
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
|
2021-05-31 11:24:52 -04:00
|
|
|
void VisitUnresolvedUsingIfExistsDecl(UnresolvedUsingIfExistsDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitTagDecl(TagDecl *D);
|
|
|
|
void VisitEnumDecl(EnumDecl *D);
|
|
|
|
void VisitRecordDecl(RecordDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitCXXRecordDecl(CXXRecordDecl *D);
|
|
|
|
void VisitClassTemplateSpecializationDecl(
|
|
|
|
ClassTemplateSpecializationDecl *D);
|
|
|
|
void VisitClassTemplatePartialSpecializationDecl(
|
|
|
|
ClassTemplatePartialSpecializationDecl *D);
|
2013-08-06 01:03:05 +00:00
|
|
|
void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
|
|
|
|
void VisitVarTemplatePartialSpecializationDecl(
|
|
|
|
VarTemplatePartialSpecializationDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitValueDecl(ValueDecl *D);
|
|
|
|
void VisitEnumConstantDecl(EnumConstantDecl *D);
|
2010-06-30 08:49:30 +00:00
|
|
|
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
|
2009-08-19 01:28:35 +00:00
|
|
|
void VisitDeclaratorDecl(DeclaratorDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitFunctionDecl(FunctionDecl *D);
|
2017-02-17 20:05:37 +00:00
|
|
|
void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitCXXMethodDecl(CXXMethodDecl *D);
|
|
|
|
void VisitCXXConstructorDecl(CXXConstructorDecl *D);
|
|
|
|
void VisitCXXDestructorDecl(CXXDestructorDecl *D);
|
|
|
|
void VisitCXXConversionDecl(CXXConversionDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitFieldDecl(FieldDecl *D);
|
2013-04-16 07:28:30 +00:00
|
|
|
void VisitMSPropertyDecl(MSPropertyDecl *D);
|
Rework how UuidAttr, CXXUuidofExpr, and GUID template arguments and constants are represented.
Summary:
Previously, we treated CXXUuidofExpr as quite a special case: it was the
only kind of expression that could be a canonical template argument, it
could be a constant lvalue base object, and so on. In addition, we
represented the UUID value as a string, whose source form we did not
preserve faithfully, and that we partially parsed in multiple different
places.
With this patch, we create an MSGuidDecl object to represent the
implicit object of type 'struct _GUID' created by a UuidAttr. Each
UuidAttr holds a pointer to its 'struct _GUID' and its original
(as-written) UUID string. A non-value-dependent CXXUuidofExpr behaves
like a DeclRefExpr denoting that MSGuidDecl object. We cache an APValue
representation of the GUID on the MSGuidDecl and use it from constant
evaluation where needed.
This allows removing a lot of the special-case logic to handle these
expressions. Unfortunately, many parts of Clang assume there are only
a couple of interesting kinds of ValueDecl, so the total amount of
special-case logic is not really reduced very much.
This fixes a few bugs and issues:
* PR38490: we now support reading from GUID objects returned from
__uuidof during constant evaluation.
* Our Itanium mangling for a non-instantiation-dependent template
argument involving __uuidof no longer depends on which CXXUuidofExpr
template argument we happened to see first.
* We now predeclare ::_GUID, and permit use of __uuidof without
any header inclusion, better matching MSVC's behavior. We do not
predefine ::__s_GUID, though; that seems like a step too far.
* Our IR representation for GUID constants now uses the correct IR type
wherever possible. We will still fall back to using the
{i32, i16, i16, [8 x i8]}
layout if a definition of struct _GUID is not available. This is not
ideal: in principle the two layouts could have different padding.
Reviewers: rnk, jdoerfert
Subscribers: arphaman, cfe-commits, aeubanks
Tags: #clang
Differential Revision: https://reviews.llvm.org/D78171
2020-04-11 22:15:29 -07:00
|
|
|
void VisitMSGuidDecl(MSGuidDecl *D);
|
[Clang] Implement __builtin_source_location.
This builtin returns the address of a global instance of the
`std::source_location::__impl` type, which must be defined (with an
appropriate shape) before calling the builtin.
It will be used to implement std::source_location in libc++ in a
future change. The builtin is compatible with GCC's implementation,
and libstdc++'s usage. An intentional divergence is that GCC declares
the builtin's return type to be `const void*` (for
ease-of-implementation reasons), while Clang uses the actual type,
`const std::source_location::__impl*`.
In order to support this new functionality, I've also added a new
'UnnamedGlobalConstantDecl'. This artificial Decl is modeled after
MSGuidDecl, and is used to represent a generic concept of an lvalue
constant with global scope, deduplicated by its value. It's possible
that MSGuidDecl itself, or some of the other similar sorts of things
in Clang might be able to be refactored onto this more-generic
concept, but there's enough special-case weirdness in MSGuidDecl that
I gave up attempting to share code there, at least for now.
Finally, for compatibility with libstdc++'s <source_location> header,
I've added a second exception to the "cannot cast from void* to T* in
constant evaluation" rule. This seems a bit distasteful, but feels
like the best available option.
Reviewers: aaron.ballman, erichkeane
Differential Revision: https://reviews.llvm.org/D120159
2022-03-28 18:27:18 -04:00
|
|
|
void VisitUnnamedGlobalConstantDecl(UnnamedGlobalConstantDecl *D);
|
2020-09-20 23:16:08 -07:00
|
|
|
void VisitTemplateParamObjectDecl(TemplateParamObjectDecl *D);
|
2010-11-21 06:08:52 +00:00
|
|
|
void VisitIndirectFieldDecl(IndirectFieldDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitVarDecl(VarDecl *D);
|
|
|
|
void VisitImplicitParamDecl(ImplicitParamDecl *D);
|
|
|
|
void VisitParmVarDecl(ParmVarDecl *D);
|
2016-08-12 02:21:25 +00:00
|
|
|
void VisitDecompositionDecl(DecompositionDecl *D);
|
|
|
|
void VisitBindingDecl(BindingDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
|
|
|
|
void VisitTemplateDecl(TemplateDecl *D);
|
2019-07-10 21:25:49 +00:00
|
|
|
void VisitConceptDecl(ConceptDecl *D);
|
2022-10-24 12:20:36 -07:00
|
|
|
void VisitImplicitConceptSpecializationDecl(
|
|
|
|
ImplicitConceptSpecializationDecl *D);
|
2020-01-18 09:11:43 +02:00
|
|
|
void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);
|
2010-07-29 16:11:51 +00:00
|
|
|
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitClassTemplateDecl(ClassTemplateDecl *D);
|
2013-08-06 01:03:05 +00:00
|
|
|
void VisitVarTemplateDecl(VarTemplateDecl *D);
|
2010-06-22 09:55:07 +00:00
|
|
|
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
|
2011-05-05 21:57:07 +00:00
|
|
|
void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
|
2010-06-20 14:40:59 +00:00
|
|
|
void VisitUsingDecl(UsingDecl *D);
|
2021-05-05 08:55:02 -07:00
|
|
|
void VisitUsingEnumDecl(UsingEnumDecl *D);
|
2016-12-20 21:35:28 +00:00
|
|
|
void VisitUsingPackDecl(UsingPackDecl *D);
|
2010-06-20 14:40:59 +00:00
|
|
|
void VisitUsingShadowDecl(UsingShadowDecl *D);
|
P0136R1, DR1573, DR1645, DR1715, DR1736, DR1903, DR1941, DR1959, DR1991:
Replace inheriting constructors implementation with new approach, voted into
C++ last year as a DR against C++11.
Instead of synthesizing a set of derived class constructors for each inherited
base class constructor, we make the constructors of the base class visible to
constructor lookup in the derived class, using the normal rules for
using-declarations.
For constructors, UsingShadowDecl now has a ConstructorUsingShadowDecl derived
class that tracks the requisite additional information. We create shadow
constructors (not found by name lookup) in the derived class to model the
actual initialization, and have a new expression node,
CXXInheritedCtorInitExpr, to model the initialization of a base class from such
a constructor. (This initialization is special because it performs real perfect
forwarding of arguments.)
In cases where argument forwarding is not possible (for inalloca calls,
variadic calls, and calls with callee parameter cleanup), the shadow inheriting
constructor is not emitted and instead we directly emit the initialization code
into the caller of the inherited constructor.
Note that this new model is not perfectly compatible with the old model in some
corner cases. In particular:
* if B inherits a private constructor from A, and C uses that constructor to
construct a B, then we previously required that A befriends B and B
befriends C, but the new rules require A to befriend C directly, and
* if a derived class has its own constructors (and so its implicit default
constructor is suppressed), it may still inherit a default constructor from
a base class
llvm-svn: 274049
2016-06-28 19:03:57 +00:00
|
|
|
void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
|
2016-09-08 23:14:54 +00:00
|
|
|
void VisitExportDecl(ExportDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
|
2022-06-08 09:59:40 +00:00
|
|
|
void VisitTopLevelStmtDecl(TopLevelStmtDecl *D);
|
2011-12-02 23:23:56 +00:00
|
|
|
void VisitImportDecl(ImportDecl *D);
|
2010-06-05 05:09:32 +00:00
|
|
|
void VisitAccessSpecDecl(AccessSpecDecl *D);
|
2010-06-29 22:47:00 +00:00
|
|
|
void VisitFriendDecl(FriendDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
|
|
|
|
void VisitStaticAssertDecl(StaticAssertDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitBlockDecl(BlockDecl *D);
|
2013-04-16 19:37:38 +00:00
|
|
|
void VisitCapturedDecl(CapturedDecl *D);
|
2013-02-22 17:15:32 +00:00
|
|
|
void VisitEmptyDecl(EmptyDecl *D);
|
2019-11-17 11:41:55 +01:00
|
|
|
void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
|
2016-04-13 02:12:03 +00:00
|
|
|
void VisitDeclContext(DeclContext *DC);
|
2010-08-03 17:30:10 +00:00
|
|
|
template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
|
2022-07-15 10:45:57 -07:00
|
|
|
void VisitHLSLBufferDecl(HLSLBufferDecl *D);
|
2010-05-07 21:43:38 +00:00
|
|
|
|
2010-05-30 07:21:58 +00:00
|
|
|
// FIXME: Put in the same order is DeclNodes.td?
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 03:57:15 +00:00
|
|
|
void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
|
2009-04-27 06:16:06 +00:00
|
|
|
void VisitObjCContainerDecl(ObjCContainerDecl *D);
|
|
|
|
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
|
|
|
void VisitObjCIvarDecl(ObjCIvarDecl *D);
|
|
|
|
void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
|
|
|
|
void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
|
|
|
|
void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
|
|
|
|
void VisitObjCImplDecl(ObjCImplDecl *D);
|
|
|
|
void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
|
|
|
|
void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
|
|
|
|
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
|
|
|
|
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
|
|
|
|
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
|
2013-03-22 06:34:35 +00:00
|
|
|
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
|
2019-03-07 17:54:44 +00:00
|
|
|
void VisitOMPAllocateDecl(OMPAllocateDecl *D);
|
2018-09-26 04:28:39 +00:00
|
|
|
void VisitOMPRequiresDecl(OMPRequiresDecl *D);
|
2016-03-03 05:21:39 +00:00
|
|
|
void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
|
2019-02-01 20:25:04 +00:00
|
|
|
void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
|
2016-02-11 05:35:55 +00:00
|
|
|
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
|
2014-03-22 23:33:22 +00:00
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 03:57:15 +00:00
|
|
|
/// Add an Objective-C type parameter list to the given record.
|
|
|
|
void AddObjCTypeParamList(ObjCTypeParamList *typeParams) {
|
|
|
|
// Empty type parameter list.
|
|
|
|
if (!typeParams) {
|
|
|
|
Record.push_back(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Record.push_back(typeParams->size());
|
2022-09-03 23:27:27 -07:00
|
|
|
for (auto *typeParam : *typeParams) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(typeParam);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 03:57:15 +00:00
|
|
|
}
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(typeParams->getLAngleLoc());
|
|
|
|
Record.AddSourceLocation(typeParams->getRAngleLoc());
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 03:57:15 +00:00
|
|
|
}
|
|
|
|
|
2024-12-11 09:40:47 +08:00
|
|
|
/// Collect the first declaration from each module file that provides a
|
|
|
|
/// declaration of D.
|
|
|
|
void CollectFirstDeclFromEachModule(
|
|
|
|
const Decl *D, bool IncludeLocal,
|
|
|
|
llvm::MapVector<ModuleFile *, const Decl *> &Firsts) {
|
|
|
|
|
2015-08-22 01:47:18 +00:00
|
|
|
// FIXME: We can skip entries that we know are implied by others.
|
2015-08-27 21:38:25 +00:00
|
|
|
for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) {
|
|
|
|
if (R->isFromASTFile())
|
2015-08-22 01:47:18 +00:00
|
|
|
Firsts[Writer.Chain->getOwningModuleFile(R)] = R;
|
2015-08-27 21:38:25 +00:00
|
|
|
else if (IncludeLocal)
|
|
|
|
Firsts[nullptr] = R;
|
|
|
|
}
|
2024-12-11 09:40:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Add to the record the first declaration from each module file that
|
|
|
|
/// provides a declaration of D. The intent is to provide a sufficient
|
|
|
|
/// set such that reloading this set will load all current redeclarations.
|
|
|
|
void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) {
|
|
|
|
llvm::MapVector<ModuleFile *, const Decl *> Firsts;
|
|
|
|
CollectFirstDeclFromEachModule(D, IncludeLocal, Firsts);
|
|
|
|
|
2015-08-22 01:47:18 +00:00
|
|
|
for (const auto &F : Firsts)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(F.second);
|
2015-08-22 01:47:18 +00:00
|
|
|
}
|
|
|
|
|
2024-12-11 09:40:47 +08:00
|
|
|
/// Add to the record the first template specialization from each module
|
|
|
|
/// file that provides a declaration of D. We store the DeclId and an
|
|
|
|
/// ODRHash of the template arguments of D which should provide enough
|
|
|
|
/// information to load D only if the template instantiator needs it.
|
|
|
|
void AddFirstSpecializationDeclFromEachModule(
|
|
|
|
const Decl *D, llvm::SmallVectorImpl<const Decl *> &SpecsInMap,
|
|
|
|
llvm::SmallVectorImpl<const Decl *> &PartialSpecsInMap) {
|
|
|
|
assert((isa<ClassTemplateSpecializationDecl>(D) ||
|
|
|
|
isa<VarTemplateSpecializationDecl>(D) || isa<FunctionDecl>(D)) &&
|
|
|
|
"Must not be called with other decls");
|
|
|
|
llvm::MapVector<ModuleFile *, const Decl *> Firsts;
|
|
|
|
CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts);
|
|
|
|
|
|
|
|
for (const auto &F : Firsts) {
|
|
|
|
if (isa<ClassTemplatePartialSpecializationDecl,
|
|
|
|
VarTemplatePartialSpecializationDecl>(F.second))
|
|
|
|
PartialSpecsInMap.push_back(F.second);
|
|
|
|
else
|
|
|
|
SpecsInMap.push_back(F.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-27 23:05:10 +00:00
|
|
|
/// Get the specialization decl from an entry in the specialization list.
|
|
|
|
template <typename EntryType>
|
|
|
|
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
|
|
|
|
getSpecializationDecl(EntryType &T) {
|
|
|
|
return RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::getDecl(&T);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the list of partial specializations from a template's common ptr.
|
|
|
|
template<typename T>
|
|
|
|
decltype(T::PartialSpecializations) &getPartialSpecializations(T *Common) {
|
|
|
|
return Common->PartialSpecializations;
|
|
|
|
}
|
2024-12-11 09:40:47 +08:00
|
|
|
MutableArrayRef<FunctionTemplateSpecializationInfo>
|
|
|
|
getPartialSpecializations(FunctionTemplateDecl::Common *) {
|
|
|
|
return std::nullopt;
|
2015-02-27 23:05:10 +00:00
|
|
|
}
|
|
|
|
|
2016-02-24 21:59:10 +00:00
|
|
|
template<typename DeclTy>
|
|
|
|
void AddTemplateSpecializations(DeclTy *D) {
|
2015-02-27 23:05:10 +00:00
|
|
|
auto *Common = D->getCommonPtr();
|
|
|
|
|
|
|
|
// If we have any lazy specializations, and the external AST source is
|
|
|
|
// our chained AST reader, we can just write out the DeclIDs. Otherwise,
|
|
|
|
// we need to resolve them to actual declarations.
|
2024-11-07 14:40:21 -08:00
|
|
|
if (Writer.Chain != Record.getASTContext().getExternalSource() &&
|
2024-12-11 09:40:47 +08:00
|
|
|
Writer.Chain && Writer.Chain->haveUnloadedSpecializations(D)) {
|
2015-02-27 23:05:10 +00:00
|
|
|
D->LoadLazySpecializations();
|
2024-12-11 09:40:47 +08:00
|
|
|
assert(!Writer.Chain->haveUnloadedSpecializations(D));
|
2015-02-27 23:05:10 +00:00
|
|
|
}
|
|
|
|
|
2024-12-11 09:40:47 +08:00
|
|
|
// AddFirstSpecializationDeclFromEachModule might trigger deserialization,
|
|
|
|
// invalidating *Specializations iterators.
|
|
|
|
llvm::SmallVector<const Decl *, 16> AllSpecs;
|
2016-02-24 21:59:10 +00:00
|
|
|
for (auto &Entry : Common->Specializations)
|
2024-12-11 09:40:47 +08:00
|
|
|
AllSpecs.push_back(getSpecializationDecl(Entry));
|
2016-02-24 21:59:10 +00:00
|
|
|
for (auto &Entry : getPartialSpecializations(Common))
|
2024-12-11 09:40:47 +08:00
|
|
|
AllSpecs.push_back(getSpecializationDecl(Entry));
|
2016-02-24 21:59:10 +00:00
|
|
|
|
2024-12-11 09:40:47 +08:00
|
|
|
llvm::SmallVector<const Decl *, 16> Specs;
|
|
|
|
llvm::SmallVector<const Decl *, 16> PartialSpecs;
|
|
|
|
for (auto *D : AllSpecs) {
|
2015-02-27 23:05:10 +00:00
|
|
|
assert(D->isCanonicalDecl() && "non-canonical decl in set");
|
2024-12-11 09:40:47 +08:00
|
|
|
AddFirstSpecializationDeclFromEachModule(D, Specs, PartialSpecs);
|
|
|
|
}
|
|
|
|
|
|
|
|
Record.AddOffset(Writer.WriteSpecializationInfoLookupTable(
|
|
|
|
D, Specs, /*IsPartial=*/false));
|
|
|
|
|
|
|
|
// Function Template Decl doesn't have partial decls.
|
|
|
|
if (isa<FunctionTemplateDecl>(D)) {
|
|
|
|
assert(PartialSpecs.empty());
|
|
|
|
return;
|
2015-02-27 23:05:10 +00:00
|
|
|
}
|
2015-08-22 01:47:18 +00:00
|
|
|
|
2024-12-11 09:40:47 +08:00
|
|
|
Record.AddOffset(Writer.WriteSpecializationInfoLookupTable(
|
|
|
|
D, PartialSpecs, /*IsPartial=*/true));
|
2015-08-22 01:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Ensure that this template specialization is associated with the specified
|
|
|
|
/// template on reload.
|
|
|
|
void RegisterTemplateSpecialization(const Decl *Template,
|
|
|
|
const Decl *Specialization) {
|
|
|
|
Template = Template->getCanonicalDecl();
|
|
|
|
|
|
|
|
// If the canonical template is local, we'll write out this specialization
|
|
|
|
// when we emit it.
|
|
|
|
// FIXME: We can do the same thing if there is any local declaration of
|
|
|
|
// the template, to avoid emitting an update record.
|
|
|
|
if (!Template->isFromASTFile())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We only need to associate the first local declaration of the
|
|
|
|
// specialization. The other declarations will get pulled in by it.
|
|
|
|
if (Writer.getFirstLocalDecl(Specialization) != Specialization)
|
|
|
|
return;
|
|
|
|
|
2024-12-11 09:40:47 +08:00
|
|
|
if (isa<ClassTemplatePartialSpecializationDecl,
|
|
|
|
VarTemplatePartialSpecializationDecl>(Specialization))
|
|
|
|
Writer.PartialSpecializationsUpdates[cast<NamedDecl>(Template)]
|
|
|
|
.push_back(cast<NamedDecl>(Specialization));
|
|
|
|
else
|
|
|
|
Writer.SpecializationsUpdates[cast<NamedDecl>(Template)].push_back(
|
|
|
|
cast<NamedDecl>(Specialization));
|
2015-02-27 23:05:10 +00:00
|
|
|
}
|
2009-04-27 06:16:06 +00:00
|
|
|
};
|
2015-06-22 23:07:51 +00:00
|
|
|
}
|
2009-04-27 06:16:06 +00:00
|
|
|
|
2024-03-08 10:12:51 +08:00
|
|
|
bool clang::CanElideDeclDef(const Decl *D) {
|
|
|
|
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
if (FD->isInlined() || FD->isConstexpr())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (FD->isDependentContext())
|
|
|
|
return false;
|
2024-03-14 15:06:54 +08:00
|
|
|
|
|
|
|
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
|
|
|
|
return false;
|
2024-03-08 10:12:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
if (!VD->getDeclContext()->getRedeclContext()->isFileContext() ||
|
2024-03-14 15:06:54 +08:00
|
|
|
VD->isInline() || VD->isConstexpr() || isa<ParmVarDecl>(VD) ||
|
|
|
|
// Constant initialized variable may not affect the ABI, but they
|
|
|
|
// may be used in constant evaluation in the frontend, so we have
|
|
|
|
// to remain them.
|
|
|
|
VD->hasConstantInitialization())
|
2024-03-08 10:12:51 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::Visit(Decl *D) {
|
|
|
|
DeclVisitor<ASTDeclWriter>::Visit(D);
|
2010-07-02 15:58:43 +00:00
|
|
|
|
2011-06-03 23:11:16 +00:00
|
|
|
// Source locations require array (variable-length) abbreviations. The
|
|
|
|
// abbreviation infrastructure requires that arrays are encoded last, so
|
|
|
|
// we handle it here in the case of those classes derived from DeclaratorDecl
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
|
2018-06-29 20:46:25 +00:00
|
|
|
if (auto *TInfo = DD->getTypeSourceInfo())
|
|
|
|
Record.AddTypeLoc(TInfo->getTypeLoc());
|
2011-06-03 23:11:16 +00:00
|
|
|
}
|
|
|
|
|
2010-07-02 15:58:43 +00:00
|
|
|
// Handle FunctionDecl's body here and write it after all other Stmts/Exprs
|
|
|
|
// have been written. We want it last because we will not read it back when
|
2018-07-30 19:24:48 +00:00
|
|
|
// retrieving it from the AST, we'll just lazily set the offset.
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
|
2024-03-08 10:12:51 +08:00
|
|
|
if (!GeneratingReducedBMI || !CanElideDeclDef(FD)) {
|
|
|
|
Record.push_back(FD->doesThisDeclarationHaveABody());
|
|
|
|
if (FD->doesThisDeclarationHaveABody())
|
|
|
|
Record.AddFunctionDefinition(FD);
|
|
|
|
} else
|
|
|
|
Record.push_back(0);
|
2010-07-02 15:58:43 +00:00
|
|
|
}
|
2016-04-13 02:12:03 +00:00
|
|
|
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
// Similar to FunctionDecls, handle VarDecl's initializer here and write it
|
|
|
|
// after all other Stmts/Exprs. We will not read the initializer until after
|
|
|
|
// we have finished recursive deserialization, because it can recursively
|
|
|
|
// refer back to the variable.
|
|
|
|
if (auto *VD = dyn_cast<VarDecl>(D)) {
|
2024-03-08 10:12:51 +08:00
|
|
|
if (!GeneratingReducedBMI || !CanElideDeclDef(VD))
|
|
|
|
Record.AddVarDeclInit(VD);
|
|
|
|
else
|
|
|
|
Record.push_back(0);
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
}
|
|
|
|
|
2023-04-05 14:28:57 -07:00
|
|
|
// And similarly for FieldDecls. We already serialized whether there is a
|
|
|
|
// default member initializer.
|
|
|
|
if (auto *FD = dyn_cast<FieldDecl>(D)) {
|
|
|
|
if (FD->hasInClassInitializer()) {
|
|
|
|
if (Expr *Init = FD->getInClassInitializer()) {
|
|
|
|
Record.push_back(1);
|
|
|
|
Record.AddStmt(Init);
|
|
|
|
} else {
|
|
|
|
Record.push_back(0);
|
|
|
|
// Initializer has not been instantiated yet.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-13 02:12:03 +00:00
|
|
|
// If this declaration is also a DeclContext, write blocks for the
|
|
|
|
// declarations that lexically stored inside its context and those
|
|
|
|
// declarations that are visible from its context.
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
if (auto *DC = dyn_cast<DeclContext>(D))
|
2016-04-13 02:12:03 +00:00
|
|
|
VisitDeclContext(DC);
|
2010-07-02 15:58:43 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitDecl(Decl *D) {
|
2023-11-03 21:59:44 +08:00
|
|
|
BitsPacker DeclBits;
|
2023-12-21 16:35:20 +08:00
|
|
|
|
|
|
|
// The order matters here. It will be better to put the bit with higher
|
|
|
|
// probability to be 0 in the end of the bits.
|
|
|
|
//
|
|
|
|
// Since we're using VBR6 format to store it.
|
|
|
|
// It will be pretty effient if all the higher bits are 0.
|
|
|
|
// For example, if we need to pack 8 bits into a value and the stored value
|
|
|
|
// is 0xf0, the actual stored value will be 0b000111'110000, which takes 12
|
|
|
|
// bits actually. However, if we changed the order to be 0x0f, then we can
|
|
|
|
// store it as 0b001111, which takes 6 bits only now.
|
|
|
|
DeclBits.addBits((uint64_t)D->getModuleOwnershipKind(), /*BitWidth=*/3);
|
|
|
|
DeclBits.addBit(D->isReferenced());
|
|
|
|
DeclBits.addBit(D->isUsed(false));
|
|
|
|
DeclBits.addBits(D->getAccess(), /*BitWidth=*/2);
|
|
|
|
DeclBits.addBit(D->isImplicit());
|
2023-12-07 17:01:06 +08:00
|
|
|
DeclBits.addBit(D->getDeclContext() != D->getLexicalDeclContext());
|
2023-11-03 21:59:44 +08:00
|
|
|
DeclBits.addBit(D->hasAttrs());
|
|
|
|
DeclBits.addBit(D->isTopLevelDeclInObjCContainer());
|
2023-12-21 16:35:20 +08:00
|
|
|
DeclBits.addBit(D->isInvalidDecl());
|
2023-11-03 21:59:44 +08:00
|
|
|
Record.push_back(DeclBits);
|
|
|
|
|
2023-12-07 17:01:06 +08:00
|
|
|
Record.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()));
|
|
|
|
if (D->getDeclContext() != D->getLexicalDeclContext())
|
|
|
|
Record.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()));
|
|
|
|
|
2010-10-18 19:20:11 +00:00
|
|
|
if (D->hasAttrs())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddAttributes(D->getAttrs());
|
2023-11-03 21:59:44 +08:00
|
|
|
|
2017-05-18 02:29:20 +00:00
|
|
|
Record.push_back(Writer.getSubmoduleID(D->getOwningModule()));
|
2014-03-23 02:30:01 +00:00
|
|
|
|
|
|
|
// If this declaration injected a name into a context different from its
|
|
|
|
// lexical context, and that context is an imported namespace, we need to
|
|
|
|
// update its visible declarations to include this name.
|
|
|
|
//
|
|
|
|
// This happens when we instantiate a class with a friend declaration or a
|
|
|
|
// function with a local extern declaration, for instance.
|
2015-07-12 23:43:21 +00:00
|
|
|
//
|
|
|
|
// FIXME: Can we handle this in AddedVisibleDecl instead?
|
2014-03-23 02:30:01 +00:00
|
|
|
if (D->isOutOfLine()) {
|
2014-03-23 20:41:56 +00:00
|
|
|
auto *DC = D->getDeclContext();
|
|
|
|
while (auto *NS = dyn_cast<NamespaceDecl>(DC->getRedeclContext())) {
|
|
|
|
if (!NS->isFromASTFile())
|
|
|
|
break;
|
2015-03-26 04:27:10 +00:00
|
|
|
Writer.UpdatedDeclContexts.insert(NS->getPrimaryContext());
|
2014-03-23 20:41:56 +00:00
|
|
|
if (!NS->isInlineNamespace())
|
|
|
|
break;
|
|
|
|
DC = NS->getParent();
|
|
|
|
}
|
2014-03-23 02:30:01 +00:00
|
|
|
}
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2016-03-02 17:28:48 +00:00
|
|
|
void ASTDeclWriter::VisitPragmaCommentDecl(PragmaCommentDecl *D) {
|
|
|
|
StringRef Arg = D->getArg();
|
|
|
|
Record.push_back(Arg.size());
|
|
|
|
VisitDecl(D);
|
2018-08-09 21:08:08 +00:00
|
|
|
Record.AddSourceLocation(D->getBeginLoc());
|
2016-03-02 17:28:48 +00:00
|
|
|
Record.push_back(D->getCommentKind());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddString(Arg);
|
2016-03-02 17:28:48 +00:00
|
|
|
Code = serialization::DECL_PRAGMA_COMMENT;
|
|
|
|
}
|
|
|
|
|
2016-03-02 19:28:54 +00:00
|
|
|
void ASTDeclWriter::VisitPragmaDetectMismatchDecl(
|
|
|
|
PragmaDetectMismatchDecl *D) {
|
|
|
|
StringRef Name = D->getName();
|
|
|
|
StringRef Value = D->getValue();
|
|
|
|
Record.push_back(Name.size() + 1 + Value.size());
|
|
|
|
VisitDecl(D);
|
2018-08-09 21:08:08 +00:00
|
|
|
Record.AddSourceLocation(D->getBeginLoc());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddString(Name);
|
|
|
|
Record.AddString(Value);
|
2016-03-02 19:28:54 +00:00
|
|
|
Code = serialization::DECL_PRAGMA_DETECT_MISMATCH;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
|
2011-08-12 00:15:20 +00:00
|
|
|
llvm_unreachable("Translation units aren't directly serialized");
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclarationName(D->getDeclName());
|
2015-02-07 03:11:11 +00:00
|
|
|
Record.push_back(needsAnonymousDeclarationNumber(D)
|
|
|
|
? Writer.getAnonymousDeclarationNumber(D)
|
|
|
|
: 0);
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitNamedDecl(D);
|
2018-08-09 21:08:08 +00:00
|
|
|
Record.AddSourceLocation(D->getBeginLoc());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeRef(QualType(D->getTypeForDecl(), 0));
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 14:40:25 +00:00
|
|
|
void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) {
|
Completely re-implement (de-)serialization of declaration
chains. The previous implementation relied heavily on the declaration
chain being stored as a (circular) linked list on disk, as it is in
memory. However, when deserializing from multiple modules, the
different chains could get mixed up, leading to broken declaration chains.
The new solution keeps track of the first and last declarations in the
chain for each module file. When we load a declaration, we search all
of the module files for redeclarations of that declaration, then
splice together all of the lists into a coherent whole (along with any
redeclarations that were actually parsed).
As a drive-by fix, (de-)serialize the redeclaration chains of
TypedefNameDecls, which had somehow gotten missed previously. Add a
test of this serialization.
This new scheme creates a redeclaration table that is fairly large in
the PCH file (on the order of 400k for Cocoa.h's 12MB PCH file). The
table is mmap'd in and searched via a binary search, but it's still
quite large. A future tweak will eliminate entries for declarations
that have no redeclarations anywhere, and should
drastically reduce the size of this table.
llvm-svn: 146841
2011-12-17 23:38:30 +00:00
|
|
|
VisitRedeclarable(D);
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitTypeDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeSourceInfo(D->getTypeSourceInfo());
|
2013-06-20 12:46:19 +00:00
|
|
|
Record.push_back(D->isModed());
|
|
|
|
if (D->isModed())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeRef(D->getUnderlyingType());
|
2017-01-26 22:39:55 +00:00
|
|
|
Record.AddDeclRef(D->getAnonDeclWithTypedefName(false));
|
2011-12-19 14:40:25 +00:00
|
|
|
}
|
2011-06-03 23:11:16 +00:00
|
|
|
|
2011-12-19 14:40:25 +00:00
|
|
|
void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
|
|
|
|
VisitTypedefNameDecl(D);
|
2015-12-11 22:41:00 +00:00
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() &&
|
|
|
|
!D->hasAttrs() &&
|
2011-06-03 23:11:16 +00:00
|
|
|
!D->isImplicit() &&
|
2013-10-17 15:37:26 +00:00
|
|
|
D->getFirstDecl() == D->getMostRecentDecl() &&
|
2011-06-03 23:11:16 +00:00
|
|
|
!D->isInvalidDecl() &&
|
2011-11-23 21:11:23 +00:00
|
|
|
!D->isTopLevelDeclInObjCContainer() &&
|
2011-09-09 02:06:17 +00:00
|
|
|
!D->isModulePrivate() &&
|
2014-08-28 01:33:39 +00:00
|
|
|
!needsAnonymousDeclarationNumber(D) &&
|
2011-06-03 23:11:16 +00:00
|
|
|
D->getDeclName().getNameKind() == DeclarationName::Identifier)
|
|
|
|
AbbrevToUse = Writer.getDeclTypedefAbbrev();
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_TYPEDEF;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2011-04-15 14:24:37 +00:00
|
|
|
void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) {
|
2011-12-19 14:40:25 +00:00
|
|
|
VisitTypedefNameDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getDescribedAliasTemplate());
|
2011-04-15 14:24:37 +00:00
|
|
|
Code = serialization::DECL_TYPEALIAS;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
|
2023-10-26 19:22:52 +04:00
|
|
|
static_assert(DeclContext::NumTagDeclBits == 23,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"TagDeclBits");
|
|
|
|
|
2010-08-03 17:30:10 +00:00
|
|
|
VisitRedeclarable(D);
|
2011-10-26 17:53:41 +00:00
|
|
|
VisitTypeDecl(D);
|
2010-09-08 19:31:22 +00:00
|
|
|
Record.push_back(D->getIdentifierNamespace());
|
2023-11-03 21:59:44 +08:00
|
|
|
|
|
|
|
BitsPacker TagDeclBits;
|
2023-11-03 21:45:39 +04:00
|
|
|
TagDeclBits.addBits(llvm::to_underlying(D->getTagKind()), /*BitWidth=*/3);
|
2023-11-03 21:59:44 +08:00
|
|
|
TagDeclBits.addBit(!isa<CXXRecordDecl>(D) ? D->isCompleteDefinition() : 0);
|
|
|
|
TagDeclBits.addBit(D->isEmbeddedInDeclarator());
|
|
|
|
TagDeclBits.addBit(D->isFreeStanding());
|
|
|
|
TagDeclBits.addBit(D->isCompleteDefinitionRequired());
|
2023-12-07 17:01:06 +08:00
|
|
|
TagDeclBits.addBits(
|
|
|
|
D->hasExtInfo() ? 1 : (D->getTypedefNameForAnonDecl() ? 2 : 0),
|
|
|
|
/*BitWidth=*/2);
|
2023-11-03 21:59:44 +08:00
|
|
|
Record.push_back(TagDeclBits);
|
|
|
|
|
2016-07-15 18:11:33 +00:00
|
|
|
Record.AddSourceRange(D->getBraceRange());
|
2014-08-30 00:04:23 +00:00
|
|
|
|
|
|
|
if (D->hasExtInfo()) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddQualifierInfo(*D->getExtInfo());
|
2014-08-30 00:04:23 +00:00
|
|
|
} else if (auto *TD = D->getTypedefNameForAnonDecl()) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(TD);
|
|
|
|
Record.AddIdentifierRef(TD->getDeclName().getAsIdentifierInfo());
|
2014-08-30 00:04:23 +00:00
|
|
|
}
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
|
2023-10-26 19:22:52 +04:00
|
|
|
static_assert(DeclContext::NumEnumDeclBits == 43,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"EnumDeclBits");
|
|
|
|
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitTagDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeSourceInfo(D->getIntegerTypeSourceInfo());
|
2010-10-08 23:50:27 +00:00
|
|
|
if (!D->getIntegerTypeSourceInfo())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeRef(D->getIntegerType());
|
|
|
|
Record.AddTypeRef(D->getPromotionType());
|
2023-11-03 21:59:44 +08:00
|
|
|
|
|
|
|
BitsPacker EnumDeclBits;
|
|
|
|
EnumDeclBits.addBits(D->getNumPositiveBits(), /*BitWidth=*/8);
|
|
|
|
EnumDeclBits.addBits(D->getNumNegativeBits(), /*BitWidth=*/8);
|
|
|
|
EnumDeclBits.addBit(D->isScoped());
|
|
|
|
EnumDeclBits.addBit(D->isScopedUsingClassTag());
|
|
|
|
EnumDeclBits.addBit(D->isFixed());
|
|
|
|
Record.push_back(EnumDeclBits);
|
|
|
|
|
[C++20] [Modules] Write ODRHash for decls in GMF
Previously, we skipped calculating ODRHash for decls in GMF when writing
them to .pcm files as an optimization. But actually, it is not
true that this will be a pure optimization. Whether or not it is
beneficial depends on the use cases. For example, if we're writing a
function `a` in module and there are 10 consumers of `a` in other TUs,
then the other TUs will pay for the cost to calculate the ODR hash for
`a` ten times. Then this optimization doesn't work. However, if all the
consumers of the module didn't touch `a`, then we can save the cost to
calculate the ODR hash of `a` for 1 times.
And the assumption to make it was: generally, the consumers of a module
may only consume a small part of the imported module. This is the reason
why we tried to load declarations, types and identifiers lazily. Then it
looks good to do the similar thing for calculating ODR hashs.
It works fine for a long time, until we started to look into the support
of modules in clangd. Then we meet multiple issue reports complaining
we're calculating ODR hash in the wrong place. To workaround these issue
reports, I decided to always write the ODRhash for decls in GMF. In my
local test, I only observed less than 1% compile time regression after
doing this. So it should be fine.
2024-07-18 11:24:02 +08:00
|
|
|
Record.push_back(D->getODRHash());
|
2018-07-25 22:52:05 +00:00
|
|
|
|
2012-03-14 23:13:10 +00:00
|
|
|
if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(MemberInfo->getInstantiatedFrom());
|
2012-03-14 23:13:10 +00:00
|
|
|
Record.push_back(MemberInfo->getTemplateSpecializationKind());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(MemberInfo->getPointOfInstantiation());
|
2012-03-14 23:13:10 +00:00
|
|
|
} else {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(nullptr);
|
2012-03-14 23:13:10 +00:00
|
|
|
}
|
2011-06-03 23:11:16 +00:00
|
|
|
|
2023-12-21 16:35:20 +08:00
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() &&
|
|
|
|
!D->isInvalidDecl() && !D->isImplicit() && !D->hasExtInfo() &&
|
2014-08-30 00:04:23 +00:00
|
|
|
!D->getTypedefNameForAnonDecl() &&
|
2013-10-17 15:37:26 +00:00
|
|
|
D->getFirstDecl() == D->getMostRecentDecl() &&
|
2011-11-23 21:11:23 +00:00
|
|
|
!D->isTopLevelDeclInObjCContainer() &&
|
2011-06-03 23:11:16 +00:00
|
|
|
!CXXRecordDecl::classofKind(D->getKind()) &&
|
2023-12-21 16:35:20 +08:00
|
|
|
!D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() &&
|
[C++20] [Modules] Write ODRHash for decls in GMF
Previously, we skipped calculating ODRHash for decls in GMF when writing
them to .pcm files as an optimization. But actually, it is not
true that this will be a pure optimization. Whether or not it is
beneficial depends on the use cases. For example, if we're writing a
function `a` in module and there are 10 consumers of `a` in other TUs,
then the other TUs will pay for the cost to calculate the ODR hash for
`a` ten times. Then this optimization doesn't work. However, if all the
consumers of the module didn't touch `a`, then we can save the cost to
calculate the ODR hash of `a` for 1 times.
And the assumption to make it was: generally, the consumers of a module
may only consume a small part of the imported module. This is the reason
why we tried to load declarations, types and identifiers lazily. Then it
looks good to do the similar thing for calculating ODR hashs.
It works fine for a long time, until we started to look into the support
of modules in clangd. Then we meet multiple issue reports complaining
we're calculating ODR hash in the wrong place. To workaround these issue
reports, I decided to always write the ODRhash for decls in GMF. In my
local test, I only observed less than 1% compile time regression after
doing this. So it should be fine.
2024-07-18 11:24:02 +08:00
|
|
|
!needsAnonymousDeclarationNumber(D) &&
|
2011-06-03 23:11:16 +00:00
|
|
|
D->getDeclName().getNameKind() == DeclarationName::Identifier)
|
|
|
|
AbbrevToUse = Writer.getDeclEnumAbbrev();
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_ENUM;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
|
2023-10-26 19:22:52 +04:00
|
|
|
static_assert(DeclContext::NumRecordDeclBits == 64,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"RecordDeclBits");
|
|
|
|
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitTagDecl(D);
|
2023-11-03 21:59:44 +08:00
|
|
|
|
|
|
|
BitsPacker RecordDeclBits;
|
|
|
|
RecordDeclBits.addBit(D->hasFlexibleArrayMember());
|
|
|
|
RecordDeclBits.addBit(D->isAnonymousStructOrUnion());
|
|
|
|
RecordDeclBits.addBit(D->hasObjectMember());
|
|
|
|
RecordDeclBits.addBit(D->hasVolatileMember());
|
|
|
|
RecordDeclBits.addBit(D->isNonTrivialToPrimitiveDefaultInitialize());
|
|
|
|
RecordDeclBits.addBit(D->isNonTrivialToPrimitiveCopy());
|
|
|
|
RecordDeclBits.addBit(D->isNonTrivialToPrimitiveDestroy());
|
|
|
|
RecordDeclBits.addBit(D->hasNonTrivialToPrimitiveDefaultInitializeCUnion());
|
|
|
|
RecordDeclBits.addBit(D->hasNonTrivialToPrimitiveDestructCUnion());
|
|
|
|
RecordDeclBits.addBit(D->hasNonTrivialToPrimitiveCopyCUnion());
|
2025-01-14 13:31:12 -05:00
|
|
|
RecordDeclBits.addBit(D->hasUninitializedExplicitInitFields());
|
2023-11-03 21:59:44 +08:00
|
|
|
RecordDeclBits.addBit(D->isParamDestroyedInCallee());
|
|
|
|
RecordDeclBits.addBits(llvm::to_underlying(D->getArgPassingRestrictions()), 2);
|
|
|
|
Record.push_back(RecordDeclBits);
|
|
|
|
|
2022-12-01 18:39:23 -08:00
|
|
|
// Only compute this for C/Objective-C, in C++ this is computed as part
|
|
|
|
// of CXXRecordDecl.
|
|
|
|
if (!isa<CXXRecordDecl>(D))
|
|
|
|
Record.push_back(D->getODRHash());
|
2011-06-03 02:27:19 +00:00
|
|
|
|
2023-12-21 16:35:20 +08:00
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() &&
|
|
|
|
!D->isImplicit() && !D->isInvalidDecl() && !D->hasExtInfo() &&
|
2014-08-30 00:04:23 +00:00
|
|
|
!D->getTypedefNameForAnonDecl() &&
|
2013-10-17 15:37:26 +00:00
|
|
|
D->getFirstDecl() == D->getMostRecentDecl() &&
|
2011-11-23 21:11:23 +00:00
|
|
|
!D->isTopLevelDeclInObjCContainer() &&
|
2011-06-03 02:27:19 +00:00
|
|
|
!CXXRecordDecl::classofKind(D->getKind()) &&
|
2014-08-28 01:33:39 +00:00
|
|
|
!needsAnonymousDeclarationNumber(D) &&
|
2011-06-03 02:27:19 +00:00
|
|
|
D->getDeclName().getNameKind() == DeclarationName::Identifier)
|
|
|
|
AbbrevToUse = Writer.getDeclRecordAbbrev();
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_RECORD;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitValueDecl(ValueDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitNamedDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeRef(D->getType());
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitValueDecl(D);
|
|
|
|
Record.push_back(D->getInitExpr()? 1 : 0);
|
|
|
|
if (D->getInitExpr())
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getInitExpr());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddAPSInt(D->getInitVal());
|
2011-06-03 02:27:19 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_ENUM_CONSTANT;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
2009-08-19 01:28:35 +00:00
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitValueDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getInnerLocStart());
|
2010-10-15 18:21:24 +00:00
|
|
|
Record.push_back(D->hasExtInfo());
|
2020-01-09 15:07:51 +02:00
|
|
|
if (D->hasExtInfo()) {
|
|
|
|
DeclaratorDecl::ExtInfo *Info = D->getExtInfo();
|
|
|
|
Record.AddQualifierInfo(*Info);
|
|
|
|
Record.AddStmt(Info->TrailingRequiresClause);
|
|
|
|
}
|
2018-06-29 20:46:25 +00:00
|
|
|
// The location information is deferred until the end of the record.
|
|
|
|
Record.AddTypeRef(D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType()
|
|
|
|
: QualType());
|
2009-08-19 01:28:35 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
2024-10-09 15:43:55 -06:00
|
|
|
static_assert(DeclContext::NumFunctionDeclBits == 44,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"FunctionDeclBits");
|
|
|
|
|
2010-09-08 19:31:22 +00:00
|
|
|
VisitRedeclarable(D);
|
2019-12-05 13:37:35 -08:00
|
|
|
|
2010-06-22 09:55:07 +00:00
|
|
|
Record.push_back(D->getTemplatedKind());
|
|
|
|
switch (D->getTemplatedKind()) {
|
|
|
|
case FunctionDecl::TK_NonTemplate:
|
|
|
|
break;
|
2022-07-22 12:30:47 -07:00
|
|
|
case FunctionDecl::TK_DependentNonTemplate:
|
|
|
|
Record.AddDeclRef(D->getInstantiatedFromDecl());
|
|
|
|
break;
|
2010-06-22 09:55:07 +00:00
|
|
|
case FunctionDecl::TK_FunctionTemplate:
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getDescribedFunctionTemplate());
|
2010-06-22 09:55:07 +00:00
|
|
|
break;
|
|
|
|
case FunctionDecl::TK_MemberSpecialization: {
|
|
|
|
MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo();
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(MemberInfo->getInstantiatedFrom());
|
2010-06-22 09:55:07 +00:00
|
|
|
Record.push_back(MemberInfo->getTemplateSpecializationKind());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(MemberInfo->getPointOfInstantiation());
|
2010-06-22 09:55:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FunctionDecl::TK_FunctionTemplateSpecialization: {
|
|
|
|
FunctionTemplateSpecializationInfo *
|
|
|
|
FTSInfo = D->getTemplateSpecializationInfo();
|
2015-08-22 01:47:18 +00:00
|
|
|
|
|
|
|
RegisterTemplateSpecialization(FTSInfo->getTemplate(), D);
|
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(FTSInfo->getTemplate());
|
2010-06-22 09:55:07 +00:00
|
|
|
Record.push_back(FTSInfo->getTemplateSpecializationKind());
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2010-06-22 09:55:07 +00:00
|
|
|
// Template arguments.
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateArgumentList(FTSInfo->TemplateArguments);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2010-06-22 09:55:07 +00:00
|
|
|
// Template args as written.
|
2014-05-22 05:54:18 +00:00
|
|
|
Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr);
|
2023-10-07 02:55:31 -04:00
|
|
|
if (FTSInfo->TemplateArgumentsAsWritten)
|
|
|
|
Record.AddASTTemplateArgumentListInfo(
|
|
|
|
FTSInfo->TemplateArgumentsAsWritten);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(FTSInfo->getPointOfInstantiation());
|
2010-09-13 11:45:48 +00:00
|
|
|
|
2019-05-02 00:49:14 +00:00
|
|
|
if (MemberSpecializationInfo *MemberInfo =
|
|
|
|
FTSInfo->getMemberSpecializationInfo()) {
|
|
|
|
Record.push_back(1);
|
|
|
|
Record.AddDeclRef(MemberInfo->getInstantiatedFrom());
|
|
|
|
Record.push_back(MemberInfo->getTemplateSpecializationKind());
|
|
|
|
Record.AddSourceLocation(MemberInfo->getPointOfInstantiation());
|
|
|
|
} else {
|
|
|
|
Record.push_back(0);
|
|
|
|
}
|
|
|
|
|
2010-09-13 11:45:48 +00:00
|
|
|
if (D->isCanonicalDecl()) {
|
|
|
|
// Write the template that contains the specializations set. We will
|
|
|
|
// add a FunctionTemplateSpecializationInfo to it when reading.
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(FTSInfo->getTemplate()->getCanonicalDecl());
|
2010-09-13 11:45:48 +00:00
|
|
|
}
|
2010-06-25 16:24:51 +00:00
|
|
|
break;
|
2010-06-22 09:55:07 +00:00
|
|
|
}
|
|
|
|
case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
|
|
|
|
DependentFunctionTemplateSpecializationInfo *
|
|
|
|
DFTSInfo = D->getDependentSpecializationInfo();
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2023-10-07 02:55:31 -04:00
|
|
|
// Candidates.
|
|
|
|
Record.push_back(DFTSInfo->getCandidates().size());
|
|
|
|
for (FunctionTemplateDecl *FTD : DFTSInfo->getCandidates())
|
|
|
|
Record.AddDeclRef(FTD);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2010-06-22 09:55:07 +00:00
|
|
|
// Templates args.
|
2023-10-07 02:55:31 -04:00
|
|
|
Record.push_back(DFTSInfo->TemplateArgumentsAsWritten != nullptr);
|
|
|
|
if (DFTSInfo->TemplateArgumentsAsWritten)
|
|
|
|
Record.AddASTTemplateArgumentListInfo(
|
|
|
|
DFTSInfo->TemplateArgumentsAsWritten);
|
2010-06-25 16:24:51 +00:00
|
|
|
break;
|
2010-06-22 09:55:07 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-07 21:43:38 +00:00
|
|
|
|
2022-08-14 13:48:18 +02:00
|
|
|
VisitDeclaratorDecl(D);
|
|
|
|
Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName());
|
|
|
|
Record.push_back(D->getIdentifierNamespace());
|
|
|
|
|
2023-12-21 16:35:20 +08:00
|
|
|
// The order matters here. It will be better to put the bit with higher
|
|
|
|
// probability to be 0 in the end of the bits. See the comments in VisitDecl
|
|
|
|
// for details.
|
2023-11-03 21:59:44 +08:00
|
|
|
BitsPacker FunctionDeclBits;
|
|
|
|
// FIXME: stable encoding
|
2023-12-21 16:35:20 +08:00
|
|
|
FunctionDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), 3);
|
2023-11-03 21:59:44 +08:00
|
|
|
FunctionDeclBits.addBits((uint32_t)D->getStorageClass(), /*BitWidth=*/3);
|
|
|
|
FunctionDeclBits.addBit(D->isInlineSpecified());
|
|
|
|
FunctionDeclBits.addBit(D->isInlined());
|
2023-12-21 16:35:20 +08:00
|
|
|
FunctionDeclBits.addBit(D->hasSkippedBody());
|
2023-11-03 21:59:44 +08:00
|
|
|
FunctionDeclBits.addBit(D->isVirtualAsWritten());
|
2024-01-18 15:30:58 +01:00
|
|
|
FunctionDeclBits.addBit(D->isPureVirtual());
|
2023-11-03 21:59:44 +08:00
|
|
|
FunctionDeclBits.addBit(D->hasInheritedPrototype());
|
|
|
|
FunctionDeclBits.addBit(D->hasWrittenPrototype());
|
|
|
|
FunctionDeclBits.addBit(D->isDeletedBit());
|
|
|
|
FunctionDeclBits.addBit(D->isTrivial());
|
|
|
|
FunctionDeclBits.addBit(D->isTrivialForCall());
|
|
|
|
FunctionDeclBits.addBit(D->isDefaulted());
|
|
|
|
FunctionDeclBits.addBit(D->isExplicitlyDefaulted());
|
|
|
|
FunctionDeclBits.addBit(D->isIneligibleOrNotSelected());
|
|
|
|
FunctionDeclBits.addBits((uint64_t)(D->getConstexprKind()), /*BitWidth=*/2);
|
2023-12-21 16:35:20 +08:00
|
|
|
FunctionDeclBits.addBit(D->hasImplicitReturnZero());
|
2023-11-03 21:59:44 +08:00
|
|
|
FunctionDeclBits.addBit(D->isMultiVersion());
|
|
|
|
FunctionDeclBits.addBit(D->isLateTemplateParsed());
|
|
|
|
FunctionDeclBits.addBit(D->FriendConstraintRefersToEnclosingTemplate());
|
2023-12-21 16:35:20 +08:00
|
|
|
FunctionDeclBits.addBit(D->usesSEHTry());
|
2023-11-03 21:59:44 +08:00
|
|
|
Record.push_back(FunctionDeclBits);
|
|
|
|
|
2022-08-14 13:48:18 +02:00
|
|
|
Record.AddSourceLocation(D->getEndLoc());
|
2023-12-07 17:01:06 +08:00
|
|
|
if (D->isExplicitlyDefaulted())
|
|
|
|
Record.AddSourceLocation(D->getDefaultLoc());
|
2022-08-14 13:48:18 +02:00
|
|
|
|
[C++20] [Modules] Write ODRHash for decls in GMF
Previously, we skipped calculating ODRHash for decls in GMF when writing
them to .pcm files as an optimization. But actually, it is not
true that this will be a pure optimization. Whether or not it is
beneficial depends on the use cases. For example, if we're writing a
function `a` in module and there are 10 consumers of `a` in other TUs,
then the other TUs will pay for the cost to calculate the ODR hash for
`a` ten times. Then this optimization doesn't work. However, if all the
consumers of the module didn't touch `a`, then we can save the cost to
calculate the ODR hash of `a` for 1 times.
And the assumption to make it was: generally, the consumers of a module
may only consume a small part of the imported module. This is the reason
why we tried to load declarations, types and identifiers lazily. Then it
looks good to do the similar thing for calculating ODR hashs.
It works fine for a long time, until we started to look into the support
of modules in clangd. Then we meet multiple issue reports complaining
we're calculating ODR hash in the wrong place. To workaround these issue
reports, I decided to always write the ODRhash for decls in GMF. In my
local test, I only observed less than 1% compile time regression after
doing this. So it should be fine.
2024-07-18 11:24:02 +08:00
|
|
|
Record.push_back(D->getODRHash());
|
2022-08-14 13:48:18 +02:00
|
|
|
|
2024-04-14 12:30:01 +02:00
|
|
|
if (D->isDefaulted() || D->isDeletedAsWritten()) {
|
|
|
|
if (auto *FDI = D->getDefalutedOrDeletedInfo()) {
|
|
|
|
// Store both that there is an DefaultedOrDeletedInfo and whether it
|
|
|
|
// contains a DeletedMessage.
|
|
|
|
StringLiteral *DeletedMessage = FDI->getDeletedMessage();
|
|
|
|
Record.push_back(1 | (DeletedMessage ? 2 : 0));
|
|
|
|
if (DeletedMessage)
|
|
|
|
Record.AddStmt(DeletedMessage);
|
|
|
|
|
2022-08-14 13:48:18 +02:00
|
|
|
Record.push_back(FDI->getUnqualifiedLookups().size());
|
|
|
|
for (DeclAccessPair P : FDI->getUnqualifiedLookups()) {
|
|
|
|
Record.AddDeclRef(P.getDecl());
|
|
|
|
Record.push_back(P.getAccess());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Record.push_back(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-16 12:22:43 +00:00
|
|
|
if (D->getFriendObjectKind()) {
|
|
|
|
// For a function defined inline within a class template, we have to force
|
|
|
|
// the canonical definition to be the one inside the canonical definition of
|
|
|
|
// the template. Remember this relation to deserialize them together.
|
|
|
|
if (auto *RD = dyn_cast<CXXRecordDecl>(D->getLexicalParent()))
|
|
|
|
if (RD->isDependentContext() && RD->isThisDeclarationADefinition()) {
|
|
|
|
Writer.RelatedDeclsMap[Writer.GetDeclRef(RD)].push_back(
|
|
|
|
Writer.GetDeclRef(D));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-27 06:16:06 +00:00
|
|
|
Record.push_back(D->param_size());
|
2022-09-03 23:27:27 -07:00
|
|
|
for (auto *P : D->parameters())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(P);
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_FUNCTION;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2019-05-09 03:59:21 +00:00
|
|
|
static void addExplicitSpecifier(ExplicitSpecifier ES,
|
|
|
|
ASTRecordWriter &Record) {
|
|
|
|
uint64_t Kind = static_cast<uint64_t>(ES.getKind());
|
|
|
|
Kind = Kind << 1 | static_cast<bool>(ES.getExpr());
|
|
|
|
Record.push_back(Kind);
|
|
|
|
if (ES.getExpr()) {
|
|
|
|
Record.AddStmt(ES.getExpr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-17 20:05:37 +00:00
|
|
|
void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
|
2019-05-09 03:59:21 +00:00
|
|
|
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
|
2021-05-19 13:31:13 -07:00
|
|
|
Record.AddDeclRef(D->Ctor);
|
2017-02-17 20:05:37 +00:00
|
|
|
VisitFunctionDecl(D);
|
2022-11-30 18:44:10 -08:00
|
|
|
Record.push_back(static_cast<unsigned char>(D->getDeductionCandidateKind()));
|
2017-02-17 20:05:37 +00:00
|
|
|
Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
|
2023-10-26 19:22:52 +04:00
|
|
|
static_assert(DeclContext::NumObjCMethodDeclBits == 37,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"ObjCMethodDeclBits");
|
|
|
|
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitNamedDecl(D);
|
|
|
|
// FIXME: convert to LazyStmtPtr?
|
2009-09-09 15:08:12 +00:00
|
|
|
// Unlike C/C++, method bodies will never be in header files.
|
2019-12-06 14:24:37 -08:00
|
|
|
bool HasBodyStuff = D->getBody() != nullptr;
|
2010-08-09 10:54:37 +00:00
|
|
|
Record.push_back(HasBodyStuff);
|
|
|
|
if (HasBodyStuff) {
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getBody());
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
2019-12-06 14:24:37 -08:00
|
|
|
Record.AddDeclRef(D->getSelfDecl());
|
|
|
|
Record.AddDeclRef(D->getCmdDecl());
|
2009-04-27 06:16:06 +00:00
|
|
|
Record.push_back(D->isInstanceMethod());
|
|
|
|
Record.push_back(D->isVariadic());
|
2012-10-10 16:42:25 +00:00
|
|
|
Record.push_back(D->isPropertyAccessor());
|
2019-11-04 14:28:14 -08:00
|
|
|
Record.push_back(D->isSynthesizedAccessorStub());
|
2010-07-22 18:24:20 +00:00
|
|
|
Record.push_back(D->isDefined());
|
2018-08-01 21:31:08 +00:00
|
|
|
Record.push_back(D->isOverriding());
|
|
|
|
Record.push_back(D->hasSkippedBody());
|
2011-10-14 17:41:52 +00:00
|
|
|
|
2018-08-01 21:31:08 +00:00
|
|
|
Record.push_back(D->isRedeclaration());
|
|
|
|
Record.push_back(D->hasRedeclaration());
|
|
|
|
if (D->hasRedeclaration()) {
|
2024-11-07 14:40:21 -08:00
|
|
|
assert(Record.getASTContext().getObjCMethodRedeclaration(D));
|
|
|
|
Record.AddDeclRef(Record.getASTContext().getObjCMethodRedeclaration(D));
|
2011-10-14 17:41:52 +00:00
|
|
|
}
|
|
|
|
|
2009-04-27 06:16:06 +00:00
|
|
|
// FIXME: stable encoding for @required/@optional
|
2023-11-01 13:39:24 +03:00
|
|
|
Record.push_back(llvm::to_underlying(D->getImplementationControl()));
|
2015-06-19 18:14:38 +00:00
|
|
|
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway/nullability
|
2009-09-09 15:08:12 +00:00
|
|
|
Record.push_back(D->getObjCDeclQualifier());
|
2011-06-11 01:09:30 +00:00
|
|
|
Record.push_back(D->hasRelatedResultType());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeRef(D->getReturnType());
|
|
|
|
Record.AddTypeSourceInfo(D->getReturnTypeSourceInfo());
|
2018-08-09 21:09:38 +00:00
|
|
|
Record.AddSourceLocation(D->getEndLoc());
|
2009-04-27 06:16:06 +00:00
|
|
|
Record.push_back(D->param_size());
|
2016-06-24 04:05:48 +00:00
|
|
|
for (const auto *P : D->parameters())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(P);
|
2011-10-03 06:37:04 +00:00
|
|
|
|
2018-08-01 21:31:08 +00:00
|
|
|
Record.push_back(D->getSelLocsKind());
|
2011-10-03 06:37:04 +00:00
|
|
|
unsigned NumStoredSelLocs = D->getNumStoredSelLocs();
|
|
|
|
SourceLocation *SelLocs = D->getStoredSelLocs();
|
|
|
|
Record.push_back(NumStoredSelLocs);
|
|
|
|
for (unsigned i = 0; i != NumStoredSelLocs; ++i)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(SelLocs[i]);
|
2011-10-03 06:37:04 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_METHOD;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 03:57:15 +00:00
|
|
|
void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
|
|
|
|
VisitTypedefNameDecl(D);
|
2015-07-07 03:58:54 +00:00
|
|
|
Record.push_back(D->Variance);
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 03:57:53 +00:00
|
|
|
Record.push_back(D->Index);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->VarianceLoc);
|
|
|
|
Record.AddSourceLocation(D->ColonLoc);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 03:57:15 +00:00
|
|
|
|
|
|
|
Code = serialization::DECL_OBJC_TYPE_PARAM;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
|
2023-10-26 19:22:52 +04:00
|
|
|
static_assert(DeclContext::NumObjCContainerDeclBits == 64,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"ObjCContainerDeclBits");
|
|
|
|
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitNamedDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getAtStartLoc());
|
|
|
|
Record.AddSourceRange(D->getAtEndRange());
|
2010-08-18 23:57:32 +00:00
|
|
|
// Abstract class (no need to define a stable serialization::DECL code).
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
2011-12-15 18:03:09 +00:00
|
|
|
VisitRedeclarable(D);
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitObjCContainerDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeRef(QualType(D->getTypeForDecl(), 0));
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 03:57:15 +00:00
|
|
|
AddObjCTypeParamList(D->TypeParamList);
|
2010-09-01 01:21:15 +00:00
|
|
|
|
2012-01-15 18:17:48 +00:00
|
|
|
Record.push_back(D->isThisDeclarationADefinition());
|
|
|
|
if (D->isThisDeclarationADefinition()) {
|
2011-12-15 05:27:12 +00:00
|
|
|
// Write the DefinitionData
|
|
|
|
ObjCInterfaceDecl::DefinitionData &Data = D->data();
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeSourceInfo(D->getSuperClassTInfo());
|
|
|
|
Record.AddSourceLocation(D->getEndOfDefinitionLoc());
|
2013-12-03 21:11:30 +00:00
|
|
|
Record.push_back(Data.HasDesignatedInitializers);
|
2022-12-08 18:35:07 -08:00
|
|
|
Record.push_back(D->getODRHash());
|
2011-12-15 22:34:59 +00:00
|
|
|
|
2011-12-15 05:27:12 +00:00
|
|
|
// Write out the protocols that are directly referenced by the @interface.
|
|
|
|
Record.push_back(Data.ReferencedProtocols.size());
|
2014-03-13 20:29:09 +00:00
|
|
|
for (const auto *P : D->protocols())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(P);
|
2014-03-13 20:34:24 +00:00
|
|
|
for (const auto &PL : D->protocol_locs())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(PL);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2011-12-15 05:27:12 +00:00
|
|
|
// Write out the protocols that are transitively referenced.
|
|
|
|
Record.push_back(Data.AllReferencedProtocols.size());
|
|
|
|
for (ObjCList<ObjCProtocolDecl>::iterator
|
|
|
|
P = Data.AllReferencedProtocols.begin(),
|
|
|
|
PEnd = Data.AllReferencedProtocols.end();
|
|
|
|
P != PEnd; ++P)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(*P);
|
2013-01-16 23:00:23 +00:00
|
|
|
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2013-01-16 23:00:23 +00:00
|
|
|
if (ObjCCategoryDecl *Cat = D->getCategoryListRaw()) {
|
2012-01-27 01:47:08 +00:00
|
|
|
// Ensure that we write out the set of categories for this class.
|
|
|
|
Writer.ObjCClassesWithCategories.insert(D);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2012-01-27 01:47:08 +00:00
|
|
|
// Make sure that the categories get serialized.
|
2013-01-16 23:00:23 +00:00
|
|
|
for (; Cat; Cat = Cat->getNextClassCategoryRaw())
|
2012-01-27 01:47:08 +00:00
|
|
|
(void)Writer.GetDeclRef(Cat);
|
|
|
|
}
|
2018-07-30 19:24:48 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_INTERFACE;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitFieldDecl(D);
|
|
|
|
// FIXME: stable encoding for @public/@private/@protected/@package
|
2009-09-09 15:08:12 +00:00
|
|
|
Record.push_back(D->getAccessControl());
|
2010-07-17 18:35:47 +00:00
|
|
|
Record.push_back(D->getSynthesize());
|
2011-06-03 23:11:16 +00:00
|
|
|
|
2015-12-11 22:41:00 +00:00
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() &&
|
|
|
|
!D->hasAttrs() &&
|
2011-06-03 23:11:16 +00:00
|
|
|
!D->isImplicit() &&
|
|
|
|
!D->isUsed(false) &&
|
|
|
|
!D->isInvalidDecl() &&
|
|
|
|
!D->isReferenced() &&
|
2011-09-09 02:06:17 +00:00
|
|
|
!D->isModulePrivate() &&
|
2011-06-03 23:11:16 +00:00
|
|
|
!D->getBitWidth() &&
|
|
|
|
!D->hasExtInfo() &&
|
|
|
|
D->getDeclName())
|
|
|
|
AbbrevToUse = Writer.getDeclObjCIvarAbbrev();
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_IVAR;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
|
2012-01-01 19:51:50 +00:00
|
|
|
VisitRedeclarable(D);
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitObjCContainerDecl(D);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2012-01-15 18:17:48 +00:00
|
|
|
Record.push_back(D->isThisDeclarationADefinition());
|
|
|
|
if (D->isThisDeclarationADefinition()) {
|
2012-01-01 19:29:29 +00:00
|
|
|
Record.push_back(D->protocol_size());
|
2014-03-13 22:58:06 +00:00
|
|
|
for (const auto *I : D->protocols())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(I);
|
2014-03-14 12:38:50 +00:00
|
|
|
for (const auto &PL : D->protocol_locs())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(PL);
|
2022-10-17 16:21:59 -07:00
|
|
|
Record.push_back(D->getODRHash());
|
2012-01-01 19:29:29 +00:00
|
|
|
}
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_PROTOCOL;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitFieldDecl(D);
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_AT_DEFS_FIELD;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitObjCContainerDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getCategoryNameLoc());
|
|
|
|
Record.AddSourceLocation(D->getIvarLBraceLoc());
|
|
|
|
Record.AddSourceLocation(D->getIvarRBraceLoc());
|
|
|
|
Record.AddDeclRef(D->getClassInterface());
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 03:57:15 +00:00
|
|
|
AddObjCTypeParamList(D->TypeParamList);
|
2009-04-27 06:16:06 +00:00
|
|
|
Record.push_back(D->protocol_size());
|
2014-03-14 12:55:57 +00:00
|
|
|
for (const auto *I : D->protocols())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(I);
|
2014-03-14 13:03:32 +00:00
|
|
|
for (const auto &PL : D->protocol_locs())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(PL);
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_CATEGORY;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitNamedDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getClassInterface());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_COMPATIBLE_ALIAS;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitNamedDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getAtLoc());
|
|
|
|
Record.AddSourceLocation(D->getLParenLoc());
|
|
|
|
Record.AddTypeRef(D->getType());
|
|
|
|
Record.AddTypeSourceInfo(D->getTypeSourceInfo());
|
2009-04-27 06:16:06 +00:00
|
|
|
// FIXME: stable encoding
|
|
|
|
Record.push_back((unsigned)D->getPropertyAttributes());
|
2010-06-22 23:20:40 +00:00
|
|
|
Record.push_back((unsigned)D->getPropertyAttributesAsWritten());
|
2009-04-27 06:16:06 +00:00
|
|
|
// FIXME: stable encoding
|
|
|
|
Record.push_back((unsigned)D->getPropertyImplementation());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclarationName(D->getGetterName());
|
2017-03-16 18:25:40 +00:00
|
|
|
Record.AddSourceLocation(D->getGetterNameLoc());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclarationName(D->getSetterName());
|
2017-03-16 18:25:40 +00:00
|
|
|
Record.AddSourceLocation(D->getSetterNameLoc());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getGetterMethodDecl());
|
|
|
|
Record.AddDeclRef(D->getSetterMethodDecl());
|
|
|
|
Record.AddDeclRef(D->getPropertyIvarDecl());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_PROPERTY;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
|
2009-07-27 19:04:32 +00:00
|
|
|
VisitObjCContainerDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getClassInterface());
|
2010-08-18 23:57:32 +00:00
|
|
|
// Abstract class (no need to define a stable serialization::DECL code).
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitObjCImplDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getCategoryNameLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_CATEGORY_IMPL;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitObjCImplDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getSuperClass());
|
|
|
|
Record.AddSourceLocation(D->getSuperClassLoc());
|
|
|
|
Record.AddSourceLocation(D->getIvarLBraceLoc());
|
|
|
|
Record.AddSourceLocation(D->getIvarRBraceLoc());
|
2012-10-17 04:53:31 +00:00
|
|
|
Record.push_back(D->hasNonZeroConstructors());
|
|
|
|
Record.push_back(D->hasDestructors());
|
2015-03-24 06:36:48 +00:00
|
|
|
Record.push_back(D->NumIvarInitializers);
|
|
|
|
if (D->NumIvarInitializers)
|
2016-04-13 21:57:08 +00:00
|
|
|
Record.AddCXXCtorInitializers(
|
2023-01-06 16:56:23 +01:00
|
|
|
llvm::ArrayRef(D->init_begin(), D->init_end()));
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_IMPLEMENTATION;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitDecl(D);
|
2018-08-09 21:08:08 +00:00
|
|
|
Record.AddSourceLocation(D->getBeginLoc());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getPropertyDecl());
|
|
|
|
Record.AddDeclRef(D->getPropertyIvarDecl());
|
|
|
|
Record.AddSourceLocation(D->getPropertyIvarDeclLoc());
|
2019-11-04 14:28:14 -08:00
|
|
|
Record.AddDeclRef(D->getGetterMethodDecl());
|
|
|
|
Record.AddDeclRef(D->getSetterMethodDecl());
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getGetterCXXConstructor());
|
|
|
|
Record.AddStmt(D->getSetterCXXAssignment());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_OBJC_PROPERTY_IMPL;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
|
2009-08-19 01:28:35 +00:00
|
|
|
VisitDeclaratorDecl(D);
|
2009-04-27 06:16:06 +00:00
|
|
|
Record.push_back(D->isMutable());
|
2017-08-28 00:28:14 +00:00
|
|
|
|
2023-04-05 14:28:57 -07:00
|
|
|
Record.push_back((D->StorageKind << 1) | D->BitField);
|
|
|
|
if (D->StorageKind == FieldDecl::ISK_CapturedVLAType)
|
2017-08-28 00:28:14 +00:00
|
|
|
Record.AddTypeRef(QualType(D->getCapturedVLAType(), 0));
|
2023-04-05 14:28:57 -07:00
|
|
|
else if (D->BitField)
|
|
|
|
Record.AddStmt(D->getBitWidth());
|
2017-08-28 00:28:14 +00:00
|
|
|
|
2024-11-06 05:10:53 +01:00
|
|
|
if (!D->getDeclName() || D->isPlaceholderVar(Writer.getLangOpts()))
|
2024-11-07 14:40:21 -08:00
|
|
|
Record.AddDeclRef(
|
|
|
|
Record.getASTContext().getInstantiatedFromUnnamedFieldDecl(D));
|
2011-06-03 23:11:16 +00:00
|
|
|
|
2015-12-11 22:41:00 +00:00
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() &&
|
|
|
|
!D->hasAttrs() &&
|
2011-06-03 23:11:16 +00:00
|
|
|
!D->isImplicit() &&
|
|
|
|
!D->isUsed(false) &&
|
|
|
|
!D->isInvalidDecl() &&
|
|
|
|
!D->isReferenced() &&
|
2011-11-23 21:11:23 +00:00
|
|
|
!D->isTopLevelDeclInObjCContainer() &&
|
2011-09-09 02:06:17 +00:00
|
|
|
!D->isModulePrivate() &&
|
2011-06-03 23:11:16 +00:00
|
|
|
!D->getBitWidth() &&
|
2011-06-11 17:19:42 +00:00
|
|
|
!D->hasInClassInitializer() &&
|
2017-08-28 00:28:14 +00:00
|
|
|
!D->hasCapturedVLAType() &&
|
2011-06-03 23:11:16 +00:00
|
|
|
!D->hasExtInfo() &&
|
|
|
|
!ObjCIvarDecl::classofKind(D->getKind()) &&
|
|
|
|
!ObjCAtDefsFieldDecl::classofKind(D->getKind()) &&
|
|
|
|
D->getDeclName())
|
|
|
|
AbbrevToUse = Writer.getDeclFieldAbbrev();
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_FIELD;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2013-04-16 07:28:30 +00:00
|
|
|
void ASTDeclWriter::VisitMSPropertyDecl(MSPropertyDecl *D) {
|
|
|
|
VisitDeclaratorDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddIdentifierRef(D->getGetterId());
|
|
|
|
Record.AddIdentifierRef(D->getSetterId());
|
2013-04-16 07:28:30 +00:00
|
|
|
Code = serialization::DECL_MS_PROPERTY;
|
|
|
|
}
|
|
|
|
|
Rework how UuidAttr, CXXUuidofExpr, and GUID template arguments and constants are represented.
Summary:
Previously, we treated CXXUuidofExpr as quite a special case: it was the
only kind of expression that could be a canonical template argument, it
could be a constant lvalue base object, and so on. In addition, we
represented the UUID value as a string, whose source form we did not
preserve faithfully, and that we partially parsed in multiple different
places.
With this patch, we create an MSGuidDecl object to represent the
implicit object of type 'struct _GUID' created by a UuidAttr. Each
UuidAttr holds a pointer to its 'struct _GUID' and its original
(as-written) UUID string. A non-value-dependent CXXUuidofExpr behaves
like a DeclRefExpr denoting that MSGuidDecl object. We cache an APValue
representation of the GUID on the MSGuidDecl and use it from constant
evaluation where needed.
This allows removing a lot of the special-case logic to handle these
expressions. Unfortunately, many parts of Clang assume there are only
a couple of interesting kinds of ValueDecl, so the total amount of
special-case logic is not really reduced very much.
This fixes a few bugs and issues:
* PR38490: we now support reading from GUID objects returned from
__uuidof during constant evaluation.
* Our Itanium mangling for a non-instantiation-dependent template
argument involving __uuidof no longer depends on which CXXUuidofExpr
template argument we happened to see first.
* We now predeclare ::_GUID, and permit use of __uuidof without
any header inclusion, better matching MSVC's behavior. We do not
predefine ::__s_GUID, though; that seems like a step too far.
* Our IR representation for GUID constants now uses the correct IR type
wherever possible. We will still fall back to using the
{i32, i16, i16, [8 x i8]}
layout if a definition of struct _GUID is not available. This is not
ideal: in principle the two layouts could have different padding.
Reviewers: rnk, jdoerfert
Subscribers: arphaman, cfe-commits, aeubanks
Tags: #clang
Differential Revision: https://reviews.llvm.org/D78171
2020-04-11 22:15:29 -07:00
|
|
|
void ASTDeclWriter::VisitMSGuidDecl(MSGuidDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
|
|
|
MSGuidDecl::Parts Parts = D->getParts();
|
|
|
|
Record.push_back(Parts.Part1);
|
|
|
|
Record.push_back(Parts.Part2);
|
|
|
|
Record.push_back(Parts.Part3);
|
2022-03-18 01:15:43 +01:00
|
|
|
Record.append(std::begin(Parts.Part4And5), std::end(Parts.Part4And5));
|
Rework how UuidAttr, CXXUuidofExpr, and GUID template arguments and constants are represented.
Summary:
Previously, we treated CXXUuidofExpr as quite a special case: it was the
only kind of expression that could be a canonical template argument, it
could be a constant lvalue base object, and so on. In addition, we
represented the UUID value as a string, whose source form we did not
preserve faithfully, and that we partially parsed in multiple different
places.
With this patch, we create an MSGuidDecl object to represent the
implicit object of type 'struct _GUID' created by a UuidAttr. Each
UuidAttr holds a pointer to its 'struct _GUID' and its original
(as-written) UUID string. A non-value-dependent CXXUuidofExpr behaves
like a DeclRefExpr denoting that MSGuidDecl object. We cache an APValue
representation of the GUID on the MSGuidDecl and use it from constant
evaluation where needed.
This allows removing a lot of the special-case logic to handle these
expressions. Unfortunately, many parts of Clang assume there are only
a couple of interesting kinds of ValueDecl, so the total amount of
special-case logic is not really reduced very much.
This fixes a few bugs and issues:
* PR38490: we now support reading from GUID objects returned from
__uuidof during constant evaluation.
* Our Itanium mangling for a non-instantiation-dependent template
argument involving __uuidof no longer depends on which CXXUuidofExpr
template argument we happened to see first.
* We now predeclare ::_GUID, and permit use of __uuidof without
any header inclusion, better matching MSVC's behavior. We do not
predefine ::__s_GUID, though; that seems like a step too far.
* Our IR representation for GUID constants now uses the correct IR type
wherever possible. We will still fall back to using the
{i32, i16, i16, [8 x i8]}
layout if a definition of struct _GUID is not available. This is not
ideal: in principle the two layouts could have different padding.
Reviewers: rnk, jdoerfert
Subscribers: arphaman, cfe-commits, aeubanks
Tags: #clang
Differential Revision: https://reviews.llvm.org/D78171
2020-04-11 22:15:29 -07:00
|
|
|
Code = serialization::DECL_MS_GUID;
|
|
|
|
}
|
|
|
|
|
[Clang] Implement __builtin_source_location.
This builtin returns the address of a global instance of the
`std::source_location::__impl` type, which must be defined (with an
appropriate shape) before calling the builtin.
It will be used to implement std::source_location in libc++ in a
future change. The builtin is compatible with GCC's implementation,
and libstdc++'s usage. An intentional divergence is that GCC declares
the builtin's return type to be `const void*` (for
ease-of-implementation reasons), while Clang uses the actual type,
`const std::source_location::__impl*`.
In order to support this new functionality, I've also added a new
'UnnamedGlobalConstantDecl'. This artificial Decl is modeled after
MSGuidDecl, and is used to represent a generic concept of an lvalue
constant with global scope, deduplicated by its value. It's possible
that MSGuidDecl itself, or some of the other similar sorts of things
in Clang might be able to be refactored onto this more-generic
concept, but there's enough special-case weirdness in MSGuidDecl that
I gave up attempting to share code there, at least for now.
Finally, for compatibility with libstdc++'s <source_location> header,
I've added a second exception to the "cannot cast from void* to T* in
constant evaluation" rule. This seems a bit distasteful, but feels
like the best available option.
Reviewers: aaron.ballman, erichkeane
Differential Revision: https://reviews.llvm.org/D120159
2022-03-28 18:27:18 -04:00
|
|
|
void ASTDeclWriter::VisitUnnamedGlobalConstantDecl(
|
|
|
|
UnnamedGlobalConstantDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
|
|
|
Record.AddAPValue(D->getValue());
|
|
|
|
Code = serialization::DECL_UNNAMED_GLOBAL_CONSTANT;
|
|
|
|
}
|
|
|
|
|
2020-09-20 23:16:08 -07:00
|
|
|
void ASTDeclWriter::VisitTemplateParamObjectDecl(TemplateParamObjectDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
|
|
|
Record.AddAPValue(D->getValue());
|
|
|
|
Code = serialization::DECL_TEMPLATE_PARAM_OBJECT;
|
|
|
|
}
|
|
|
|
|
2010-11-21 06:08:52 +00:00
|
|
|
void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
|
|
|
Record.push_back(D->getChainingSize());
|
|
|
|
|
2014-03-07 18:36:15 +00:00
|
|
|
for (const auto *P : D->chain())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(P);
|
2010-11-21 06:08:52 +00:00
|
|
|
Code = serialization::DECL_INDIRECTFIELD;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
2010-09-08 19:31:22 +00:00
|
|
|
VisitRedeclarable(D);
|
2011-10-26 17:53:41 +00:00
|
|
|
VisitDeclaratorDecl(D);
|
2023-11-03 21:59:44 +08:00
|
|
|
|
2023-12-21 16:35:20 +08:00
|
|
|
// The order matters here. It will be better to put the bit with higher
|
|
|
|
// probability to be 0 in the end of the bits. See the comments in VisitDecl
|
|
|
|
// for details.
|
2023-11-03 21:59:44 +08:00
|
|
|
BitsPacker VarDeclBits;
|
2023-12-21 16:35:20 +08:00
|
|
|
VarDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()),
|
|
|
|
/*BitWidth=*/3);
|
|
|
|
|
|
|
|
bool ModulesCodegen = false;
|
|
|
|
if (Writer.WritingModule && D->getStorageDuration() == SD_Static &&
|
|
|
|
!D->getDescribedVarTemplate()) {
|
|
|
|
// When building a C++20 module interface unit or a partition unit, a
|
|
|
|
// strong definition in the module interface is provided by the
|
|
|
|
// compilation of that unit, not by its users. (Inline variables are still
|
|
|
|
// emitted in module users.)
|
2024-11-07 14:40:21 -08:00
|
|
|
ModulesCodegen = (Writer.WritingModule->isInterfaceOrPartition() ||
|
|
|
|
(D->hasAttr<DLLExportAttr>() &&
|
|
|
|
Writer.getLangOpts().BuildingPCHWithObjectFile)) &&
|
|
|
|
Record.getASTContext().GetGVALinkageForVariable(D) >=
|
|
|
|
GVA_StrongExternal;
|
2023-12-21 16:35:20 +08:00
|
|
|
}
|
|
|
|
VarDeclBits.addBit(ModulesCodegen);
|
|
|
|
|
2023-11-03 21:59:44 +08:00
|
|
|
VarDeclBits.addBits(D->getStorageClass(), /*BitWidth=*/3);
|
|
|
|
VarDeclBits.addBits(D->getTSCSpec(), /*BitWidth=*/2);
|
|
|
|
VarDeclBits.addBits(D->getInitStyle(), /*BitWidth=*/2);
|
|
|
|
VarDeclBits.addBit(D->isARCPseudoStrong());
|
|
|
|
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
bool HasDeducedType = false;
|
2015-05-19 00:57:16 +00:00
|
|
|
if (!isa<ParmVarDecl>(D)) {
|
2023-11-03 21:59:44 +08:00
|
|
|
VarDeclBits.addBit(D->isThisDeclarationADemotedDefinition());
|
|
|
|
VarDeclBits.addBit(D->isExceptionVariable());
|
|
|
|
VarDeclBits.addBit(D->isNRVOVariable());
|
|
|
|
VarDeclBits.addBit(D->isCXXForRangeDecl());
|
2023-12-21 16:35:20 +08:00
|
|
|
|
2023-11-03 21:59:44 +08:00
|
|
|
VarDeclBits.addBit(D->isInline());
|
|
|
|
VarDeclBits.addBit(D->isInlineSpecified());
|
|
|
|
VarDeclBits.addBit(D->isConstexpr());
|
|
|
|
VarDeclBits.addBit(D->isInitCapture());
|
|
|
|
VarDeclBits.addBit(D->isPreviousDeclInSameBlockScope());
|
|
|
|
|
2023-12-21 16:35:20 +08:00
|
|
|
VarDeclBits.addBit(D->isEscapingByref());
|
|
|
|
HasDeducedType = D->getType()->getContainedDeducedType();
|
|
|
|
VarDeclBits.addBit(HasDeducedType);
|
|
|
|
|
2017-06-09 13:40:18 +00:00
|
|
|
if (const auto *IPD = dyn_cast<ImplicitParamDecl>(D))
|
2023-11-06 12:00:40 +03:00
|
|
|
VarDeclBits.addBits(llvm::to_underlying(IPD->getParameterKind()),
|
|
|
|
/*Width=*/3);
|
2017-06-09 13:40:18 +00:00
|
|
|
else
|
2023-11-03 21:59:44 +08:00
|
|
|
VarDeclBits.addBits(0, /*Width=*/3);
|
|
|
|
|
2023-12-21 16:35:20 +08:00
|
|
|
VarDeclBits.addBit(D->isObjCForDecl());
|
2017-09-06 20:01:14 +00:00
|
|
|
}
|
2023-11-03 21:59:44 +08:00
|
|
|
|
|
|
|
Record.push_back(VarDeclBits);
|
|
|
|
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
if (ModulesCodegen)
|
2024-04-25 11:43:13 +08:00
|
|
|
Writer.AddDeclRef(D, Writer.ModularCodegenDecls);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2023-11-03 21:59:44 +08:00
|
|
|
if (D->hasAttr<BlocksAttr>()) {
|
2024-11-07 14:40:21 -08:00
|
|
|
BlockVarCopyInit Init = Record.getASTContext().getBlockVarCopyInit(D);
|
2023-11-03 21:59:44 +08:00
|
|
|
Record.AddStmt(Init.getCopyExpr());
|
|
|
|
if (Init.getCopyExpr())
|
|
|
|
Record.push_back(Init.canThrow());
|
|
|
|
}
|
|
|
|
|
2013-08-14 03:09:19 +00:00
|
|
|
enum {
|
|
|
|
VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
|
|
|
|
};
|
|
|
|
if (VarTemplateDecl *TemplD = D->getDescribedVarTemplate()) {
|
|
|
|
Record.push_back(VarTemplate);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(TemplD);
|
2013-08-14 03:09:19 +00:00
|
|
|
} else if (MemberSpecializationInfo *SpecInfo
|
|
|
|
= D->getMemberSpecializationInfo()) {
|
|
|
|
Record.push_back(StaticDataMemberSpecialization);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(SpecInfo->getInstantiatedFrom());
|
2010-07-04 21:44:00 +00:00
|
|
|
Record.push_back(SpecInfo->getTemplateSpecializationKind());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(SpecInfo->getPointOfInstantiation());
|
2013-08-14 03:09:19 +00:00
|
|
|
} else {
|
|
|
|
Record.push_back(VarNotTemplate);
|
2010-07-04 21:44:00 +00:00
|
|
|
}
|
|
|
|
|
2023-12-21 16:35:20 +08:00
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() &&
|
2011-11-23 21:11:23 +00:00
|
|
|
!D->isTopLevelDeclInObjCContainer() &&
|
2014-08-28 01:33:39 +00:00
|
|
|
!needsAnonymousDeclarationNumber(D) &&
|
2011-06-03 23:11:16 +00:00
|
|
|
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
|
2023-12-21 16:35:20 +08:00
|
|
|
!D->hasExtInfo() && D->getFirstDecl() == D->getMostRecentDecl() &&
|
|
|
|
D->getKind() == Decl::Var && !D->isInline() && !D->isConstexpr() &&
|
|
|
|
!D->isInitCapture() && !D->isPreviousDeclInSameBlockScope() &&
|
|
|
|
!D->isEscapingByref() && !HasDeducedType &&
|
|
|
|
D->getStorageDuration() != SD_Static && !D->getDescribedVarTemplate() &&
|
|
|
|
!D->getMemberSpecializationInfo() && !D->isObjCForDecl() &&
|
|
|
|
!isa<ImplicitParamDecl>(D) && !D->isEscapingByref())
|
2011-06-03 23:11:16 +00:00
|
|
|
AbbrevToUse = Writer.getDeclVarAbbrev();
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_VAR;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitVarDecl(D);
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_IMPLICIT_PARAM;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitVarDecl(D);
|
2023-11-03 21:59:44 +08:00
|
|
|
|
2023-12-28 11:04:08 +08:00
|
|
|
// See the implementation of `ParmVarDecl::getParameterIndex()`, which may
|
|
|
|
// exceed the size of the normal bitfield. So it may be better to not pack
|
|
|
|
// these bits.
|
|
|
|
Record.push_back(D->getFunctionScopeIndex());
|
|
|
|
|
2023-11-03 21:59:44 +08:00
|
|
|
BitsPacker ParmVarDeclBits;
|
|
|
|
ParmVarDeclBits.addBit(D->isObjCMethodParameter());
|
|
|
|
ParmVarDeclBits.addBits(D->getFunctionScopeDepth(), /*BitsWidth=*/7);
|
2023-12-07 17:01:06 +08:00
|
|
|
// FIXME: stable encoding
|
|
|
|
ParmVarDeclBits.addBits(D->getObjCDeclQualifier(), /*BitsWidth=*/7);
|
2023-11-03 21:59:44 +08:00
|
|
|
ParmVarDeclBits.addBit(D->isKNRPromoted());
|
|
|
|
ParmVarDeclBits.addBit(D->hasInheritedDefaultArg());
|
|
|
|
ParmVarDeclBits.addBit(D->hasUninstantiatedDefaultArg());
|
2023-12-07 17:01:06 +08:00
|
|
|
ParmVarDeclBits.addBit(D->getExplicitObjectParamThisLoc().isValid());
|
2023-11-03 21:59:44 +08:00
|
|
|
Record.push_back(ParmVarDeclBits);
|
|
|
|
|
2010-07-04 21:44:07 +00:00
|
|
|
if (D->hasUninstantiatedDefaultArg())
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getUninstantiatedDefaultArg());
|
2023-12-07 17:01:06 +08:00
|
|
|
if (D->getExplicitObjectParamThisLoc().isValid())
|
|
|
|
Record.AddSourceLocation(D->getExplicitObjectParamThisLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_PARM_VAR;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-04-27 07:35:58 +00:00
|
|
|
// If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here
|
|
|
|
// we dynamically check for the properties that we optimize for, but don't
|
|
|
|
// know are true of all PARM_VAR_DECLs.
|
2022-01-27 13:55:08 +01:00
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() &&
|
2023-12-21 16:35:20 +08:00
|
|
|
!D->hasExtInfo() && D->getStorageClass() == 0 && !D->isInvalidDecl() &&
|
|
|
|
!D->isTopLevelDeclInObjCContainer() &&
|
Represent C++ direct initializers as ParenListExprs before semantic analysis
instead of having a special-purpose function.
- ActOnCXXDirectInitializer, which was mostly duplication of
AddInitializerToDecl (leading e.g. to PR10620, which Eli fixed a few days
ago), is dropped completely.
- MultiInitializer, which was an ugly hack I added, is dropped again.
- We now have the infrastructure in place to distinguish between
int x = {1};
int x({1});
int x{1};
-- VarDecl now has getInitStyle(), which indicates which of the above was used.
-- CXXConstructExpr now has a flag to indicate that it represents list-
initialization, although this is not yet used.
- InstantiateInitializer was renamed to SubstInitializer and simplified.
- ActOnParenOrParenListExpr has been replaced by ActOnParenListExpr, which
always produces a ParenListExpr. Placed that so far failed to convert that
back to a ParenExpr containing comma operators have been fixed. I'm pretty
sure I could have made a crashing test case before this.
The end result is a (I hope) considerably cleaner design of initializers.
More importantly, the fact that I can now distinguish between the various
initialization kinds means that I can get the tricky generalized initializer
test cases Johannes Schaub supplied to work. (This is not yet done.)
This commit passed self-host, with the resulting compiler passing the tests. I
hope it doesn't break more complicated code. It's a pretty big change, but one
that I feel is necessary.
llvm-svn: 150318
2012-02-11 23:51:47 +00:00
|
|
|
D->getInitStyle() == VarDecl::CInit && // Can params have anything else?
|
2023-12-21 10:30:12 +08:00
|
|
|
D->getInit() == nullptr) // No default expr.
|
2011-06-03 23:11:16 +00:00
|
|
|
AbbrevToUse = Writer.getDeclParmVarAbbrev();
|
2009-04-27 07:35:58 +00:00
|
|
|
|
|
|
|
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
|
|
|
|
// just us assuming it.
|
2013-05-04 08:27:07 +00:00
|
|
|
assert(!D->getTSCSpec() && "PARM_VAR_DECL can't use TLS");
|
2016-10-14 21:41:24 +00:00
|
|
|
assert(!D->isThisDeclarationADemotedDefinition()
|
|
|
|
&& "PARM_VAR_DECL can't be demoted definition.");
|
2009-04-27 07:35:58 +00:00
|
|
|
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
|
2010-05-03 18:51:14 +00:00
|
|
|
assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
|
2014-05-22 05:54:18 +00:00
|
|
|
assert(D->getPreviousDecl() == nullptr && "PARM_VAR_DECL can't be redecl");
|
2010-07-04 21:44:00 +00:00
|
|
|
assert(!D->isStaticDataMember() &&
|
|
|
|
"PARM_VAR_DECL can't be static data member");
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 02:21:25 +00:00
|
|
|
void ASTDeclWriter::VisitDecompositionDecl(DecompositionDecl *D) {
|
|
|
|
// Record the number of bindings first to simplify deserialization.
|
|
|
|
Record.push_back(D->bindings().size());
|
|
|
|
|
|
|
|
VisitVarDecl(D);
|
|
|
|
for (auto *B : D->bindings())
|
|
|
|
Record.AddDeclRef(B);
|
|
|
|
Code = serialization::DECL_DECOMPOSITION;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTDeclWriter::VisitBindingDecl(BindingDecl *D) {
|
|
|
|
VisitValueDecl(D);
|
|
|
|
Record.AddStmt(D->getBinding());
|
|
|
|
Code = serialization::DECL_BINDING;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitDecl(D);
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getAsmString());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getRParenLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_FILE_SCOPE_ASM;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2022-06-08 09:59:40 +00:00
|
|
|
void ASTDeclWriter::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) {
|
|
|
|
VisitDecl(D);
|
|
|
|
Record.AddStmt(D->getStmt());
|
|
|
|
Code = serialization::DECL_TOP_LEVEL_STMT_DECL;
|
|
|
|
}
|
|
|
|
|
2013-02-22 17:15:32 +00:00
|
|
|
void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) {
|
|
|
|
VisitDecl(D);
|
|
|
|
Code = serialization::DECL_EMPTY;
|
|
|
|
}
|
|
|
|
|
2019-11-17 11:41:55 +01:00
|
|
|
void ASTDeclWriter::VisitLifetimeExtendedTemporaryDecl(
|
|
|
|
LifetimeExtendedTemporaryDecl *D) {
|
|
|
|
VisitDecl(D);
|
|
|
|
Record.AddDeclRef(D->getExtendingDecl());
|
|
|
|
Record.AddStmt(D->getTemporaryExpr());
|
|
|
|
Record.push_back(static_cast<bool>(D->getValue()));
|
|
|
|
if (D->getValue())
|
|
|
|
Record.AddAPValue(*D->getValue());
|
|
|
|
Record.push_back(D->getManglingNumber());
|
|
|
|
Code = serialization::DECL_LIFETIME_EXTENDED_TEMPORARY;
|
|
|
|
}
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
|
2009-04-27 06:16:06 +00:00
|
|
|
VisitDecl(D);
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getBody());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeSourceInfo(D->getSignatureAsWritten());
|
2009-04-27 06:16:06 +00:00
|
|
|
Record.push_back(D->param_size());
|
2016-06-24 05:33:44 +00:00
|
|
|
for (ParmVarDecl *P : D->parameters())
|
|
|
|
Record.AddDeclRef(P);
|
2012-04-13 17:33:29 +00:00
|
|
|
Record.push_back(D->isVariadic());
|
|
|
|
Record.push_back(D->blockMissingReturnType());
|
|
|
|
Record.push_back(D->isConversionFromLambda());
|
2018-08-01 23:51:53 +00:00
|
|
|
Record.push_back(D->doesNotEscape());
|
2019-02-27 18:17:16 +00:00
|
|
|
Record.push_back(D->canAvoidCopyToHeap());
|
2011-02-02 13:00:07 +00:00
|
|
|
Record.push_back(D->capturesCXXThis());
|
2011-02-07 10:33:21 +00:00
|
|
|
Record.push_back(D->getNumCaptures());
|
2014-03-14 18:34:04 +00:00
|
|
|
for (const auto &capture : D->captures()) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(capture.getVariable());
|
2011-02-07 10:33:21 +00:00
|
|
|
|
|
|
|
unsigned flags = 0;
|
|
|
|
if (capture.isByRef()) flags |= 1;
|
|
|
|
if (capture.isNested()) flags |= 2;
|
|
|
|
if (capture.hasCopyExpr()) flags |= 4;
|
|
|
|
Record.push_back(flags);
|
|
|
|
|
2016-04-06 17:06:00 +00:00
|
|
|
if (capture.hasCopyExpr()) Record.AddStmt(capture.getCopyExpr());
|
2011-02-07 10:33:21 +00:00
|
|
|
}
|
2011-02-02 13:00:07 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_BLOCK;
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2013-05-03 19:20:19 +00:00
|
|
|
void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *CD) {
|
|
|
|
Record.push_back(CD->getNumParams());
|
|
|
|
VisitDecl(CD);
|
2014-05-06 10:08:46 +00:00
|
|
|
Record.push_back(CD->getContextParamPosition());
|
|
|
|
Record.push_back(CD->isNothrow() ? 1 : 0);
|
2013-05-03 19:20:19 +00:00
|
|
|
// Body is stored by VisitCapturedStmt.
|
2014-05-06 10:08:46 +00:00
|
|
|
for (unsigned I = 0; I < CD->getNumParams(); ++I)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(CD->getParam(I));
|
2013-05-03 19:20:19 +00:00
|
|
|
Code = serialization::DECL_CAPTURED;
|
2013-04-16 19:37:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
|
2023-10-26 19:22:52 +04:00
|
|
|
static_assert(DeclContext::NumLinkageSpecDeclBits == 17,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the"
|
|
|
|
"LinkageSpecDeclBits");
|
|
|
|
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitDecl(D);
|
2023-11-01 16:43:18 +03:00
|
|
|
Record.push_back(llvm::to_underlying(D->getLanguage()));
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getExternLoc());
|
|
|
|
Record.AddSourceLocation(D->getRBraceLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_LINKAGE_SPEC;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2016-09-08 23:14:54 +00:00
|
|
|
void ASTDeclWriter::VisitExportDecl(ExportDecl *D) {
|
|
|
|
VisitDecl(D);
|
|
|
|
Record.AddSourceLocation(D->getRBraceLoc());
|
|
|
|
Code = serialization::DECL_EXPORT;
|
|
|
|
}
|
|
|
|
|
2011-02-17 07:39:24 +00:00
|
|
|
void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
2018-08-09 21:08:08 +00:00
|
|
|
Record.AddSourceLocation(D->getBeginLoc());
|
2011-02-17 07:39:24 +00:00
|
|
|
Code = serialization::DECL_LABEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
|
2012-01-07 09:11:48 +00:00
|
|
|
VisitRedeclarable(D);
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitNamedDecl(D);
|
2023-11-03 21:59:44 +08:00
|
|
|
|
|
|
|
BitsPacker NamespaceDeclBits;
|
|
|
|
NamespaceDeclBits.addBit(D->isInline());
|
|
|
|
NamespaceDeclBits.addBit(D->isNested());
|
|
|
|
Record.push_back(NamespaceDeclBits);
|
|
|
|
|
2018-08-09 21:08:08 +00:00
|
|
|
Record.AddSourceLocation(D->getBeginLoc());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getRBraceLoc());
|
2010-05-07 21:43:38 +00:00
|
|
|
|
2024-07-15 13:57:56 -04:00
|
|
|
if (D->isFirstDecl())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getAnonymousNamespace());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_NAMESPACE;
|
2010-08-05 21:22:19 +00:00
|
|
|
|
2018-07-30 19:24:48 +00:00
|
|
|
if (Writer.hasChain() && D->isAnonymousNamespace() &&
|
2012-01-14 16:38:05 +00:00
|
|
|
D == D->getMostRecentDecl()) {
|
2011-04-24 16:28:21 +00:00
|
|
|
// This is a most recent reopening of the anonymous namespace. If its parent
|
|
|
|
// is in a previous PCH (or is the TU), mark that parent for update, because
|
|
|
|
// the original namespace always points to the latest re-opening of its
|
|
|
|
// anonymous namespace.
|
|
|
|
Decl *Parent = cast<Decl>(
|
|
|
|
D->getParent()->getRedeclContext()->getPrimaryContext());
|
2011-09-09 23:01:35 +00:00
|
|
|
if (Parent->isFromASTFile() || isa<TranslationUnitDecl>(Parent)) {
|
2014-03-20 21:02:00 +00:00
|
|
|
Writer.DeclUpdates[Parent].push_back(
|
2014-03-21 15:22:56 +00:00
|
|
|
ASTWriter::DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, D));
|
2011-04-24 16:28:13 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
|
2014-09-03 23:11:22 +00:00
|
|
|
VisitRedeclarable(D);
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitNamedDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getNamespaceLoc());
|
|
|
|
Record.AddSourceLocation(D->getTargetNameLoc());
|
|
|
|
Record.AddNestedNameSpecifierLoc(D->getQualifierLoc());
|
|
|
|
Record.AddDeclRef(D->getNamespace());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_NAMESPACE_ALIAS;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) {
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitNamedDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getUsingLoc());
|
|
|
|
Record.AddNestedNameSpecifierLoc(D->getQualifierLoc());
|
|
|
|
Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName());
|
|
|
|
Record.AddDeclRef(D->FirstUsingShadow.getPointer());
|
2013-07-22 10:54:09 +00:00
|
|
|
Record.push_back(D->hasTypename());
|
2024-11-07 14:40:21 -08:00
|
|
|
Record.AddDeclRef(Record.getASTContext().getInstantiatedFromUsingDecl(D));
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_USING;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 08:55:02 -07:00
|
|
|
void ASTDeclWriter::VisitUsingEnumDecl(UsingEnumDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
|
|
|
Record.AddSourceLocation(D->getUsingLoc());
|
|
|
|
Record.AddSourceLocation(D->getEnumLoc());
|
2022-09-20 21:39:47 +02:00
|
|
|
Record.AddTypeSourceInfo(D->getEnumType());
|
2021-05-05 08:55:02 -07:00
|
|
|
Record.AddDeclRef(D->FirstUsingShadow.getPointer());
|
2024-11-07 14:40:21 -08:00
|
|
|
Record.AddDeclRef(Record.getASTContext().getInstantiatedFromUsingEnumDecl(D));
|
2021-05-05 08:55:02 -07:00
|
|
|
Code = serialization::DECL_USING_ENUM;
|
|
|
|
}
|
|
|
|
|
2016-12-20 21:35:28 +00:00
|
|
|
void ASTDeclWriter::VisitUsingPackDecl(UsingPackDecl *D) {
|
|
|
|
Record.push_back(D->NumExpansions);
|
|
|
|
VisitNamedDecl(D);
|
|
|
|
Record.AddDeclRef(D->getInstantiatedFromUsingDecl());
|
|
|
|
for (auto *E : D->expansions())
|
|
|
|
Record.AddDeclRef(E);
|
|
|
|
Code = serialization::DECL_USING_PACK;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
|
2013-10-23 02:17:46 +00:00
|
|
|
VisitRedeclarable(D);
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitNamedDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getTargetDecl());
|
2018-01-06 01:07:05 +00:00
|
|
|
Record.push_back(D->getIdentifierNamespace());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->UsingOrNextShadow);
|
2024-11-07 14:40:21 -08:00
|
|
|
Record.AddDeclRef(
|
|
|
|
Record.getASTContext().getInstantiatedFromUsingShadowDecl(D));
|
2023-12-21 10:30:12 +08:00
|
|
|
|
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() &&
|
|
|
|
D->getFirstDecl() == D->getMostRecentDecl() && !D->hasAttrs() &&
|
|
|
|
!needsAnonymousDeclarationNumber(D) &&
|
|
|
|
D->getDeclName().getNameKind() == DeclarationName::Identifier)
|
|
|
|
AbbrevToUse = Writer.getDeclUsingShadowAbbrev();
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_USING_SHADOW;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
P0136R1, DR1573, DR1645, DR1715, DR1736, DR1903, DR1941, DR1959, DR1991:
Replace inheriting constructors implementation with new approach, voted into
C++ last year as a DR against C++11.
Instead of synthesizing a set of derived class constructors for each inherited
base class constructor, we make the constructors of the base class visible to
constructor lookup in the derived class, using the normal rules for
using-declarations.
For constructors, UsingShadowDecl now has a ConstructorUsingShadowDecl derived
class that tracks the requisite additional information. We create shadow
constructors (not found by name lookup) in the derived class to model the
actual initialization, and have a new expression node,
CXXInheritedCtorInitExpr, to model the initialization of a base class from such
a constructor. (This initialization is special because it performs real perfect
forwarding of arguments.)
In cases where argument forwarding is not possible (for inalloca calls,
variadic calls, and calls with callee parameter cleanup), the shadow inheriting
constructor is not emitted and instead we directly emit the initialization code
into the caller of the inherited constructor.
Note that this new model is not perfectly compatible with the old model in some
corner cases. In particular:
* if B inherits a private constructor from A, and C uses that constructor to
construct a B, then we previously required that A befriends B and B
befriends C, but the new rules require A to befriend C directly, and
* if a derived class has its own constructors (and so its implicit default
constructor is suppressed), it may still inherit a default constructor from
a base class
llvm-svn: 274049
2016-06-28 19:03:57 +00:00
|
|
|
void ASTDeclWriter::VisitConstructorUsingShadowDecl(
|
|
|
|
ConstructorUsingShadowDecl *D) {
|
|
|
|
VisitUsingShadowDecl(D);
|
|
|
|
Record.AddDeclRef(D->NominatedBaseClassShadowDecl);
|
|
|
|
Record.AddDeclRef(D->ConstructedBaseClassShadowDecl);
|
|
|
|
Record.push_back(D->IsVirtual);
|
|
|
|
Code = serialization::DECL_CONSTRUCTOR_USING_SHADOW;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitNamedDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getUsingLoc());
|
|
|
|
Record.AddSourceLocation(D->getNamespaceKeyLocation());
|
|
|
|
Record.AddNestedNameSpecifierLoc(D->getQualifierLoc());
|
|
|
|
Record.AddDeclRef(D->getNominatedNamespace());
|
|
|
|
Record.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()));
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_USING_DIRECTIVE;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitValueDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getUsingLoc());
|
|
|
|
Record.AddNestedNameSpecifierLoc(D->getQualifierLoc());
|
|
|
|
Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName());
|
2016-12-20 21:35:28 +00:00
|
|
|
Record.AddSourceLocation(D->getEllipsisLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_UNRESOLVED_USING_VALUE;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl(
|
2010-05-07 21:43:38 +00:00
|
|
|
UnresolvedUsingTypenameDecl *D) {
|
|
|
|
VisitTypeDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getTypenameLoc());
|
|
|
|
Record.AddNestedNameSpecifierLoc(D->getQualifierLoc());
|
2016-12-20 21:35:28 +00:00
|
|
|
Record.AddSourceLocation(D->getEllipsisLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_UNRESOLVED_USING_TYPENAME;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2021-05-31 11:24:52 -04:00
|
|
|
void ASTDeclWriter::VisitUnresolvedUsingIfExistsDecl(
|
|
|
|
UnresolvedUsingIfExistsDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
|
|
|
Code = serialization::DECL_UNRESOLVED_USING_IF_EXISTS;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitRecordDecl(D);
|
2010-07-02 11:55:32 +00:00
|
|
|
|
2010-06-19 19:28:53 +00:00
|
|
|
enum {
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
CXXRecNotTemplate = 0,
|
|
|
|
CXXRecTemplate,
|
|
|
|
CXXRecMemberSpecialization,
|
|
|
|
CXXLambda
|
2010-06-19 19:28:53 +00:00
|
|
|
};
|
|
|
|
if (ClassTemplateDecl *TemplD = D->getDescribedClassTemplate()) {
|
|
|
|
Record.push_back(CXXRecTemplate);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(TemplD);
|
2010-06-19 19:28:53 +00:00
|
|
|
} else if (MemberSpecializationInfo *MSInfo
|
|
|
|
= D->getMemberSpecializationInfo()) {
|
|
|
|
Record.push_back(CXXRecMemberSpecialization);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(MSInfo->getInstantiatedFrom());
|
2010-06-19 19:28:53 +00:00
|
|
|
Record.push_back(MSInfo->getTemplateSpecializationKind());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(MSInfo->getPointOfInstantiation());
|
PR60985: Fix merging of lambda closure types across modules.
Previously, distinct lambdas would get merged, and multiple definitions
of the same lambda would not get merged, because we attempted to
identify lambdas by their ordinal position within their lexical
DeclContext. This failed for lambdas within namespace-scope variables
and within variable templates, where the lexical position in the context
containing the variable didn't uniquely identify the lambda.
In this patch, we instead identify lambda closure types by index within
their context declaration, which does uniquely identify them in a way
that's consistent across modules.
This change causes a deserialization cycle between the type of a
variable with deduced type and a lambda appearing as the initializer of
the variable -- reading the variable's type requires reading and merging
the lambda, and reading the lambda requires reading and merging the
variable. This is addressed by deferring loading the deduced type of a
variable until after we finish recursive deserialization.
This also exposes a pre-existing subtle issue where loading a
variable declaration would trigger immediate loading of its initializer,
which could recursively refer back to properties of the variable. This
particularly causes problems if the initializer contains a
lambda-expression, but can be problematic in general. That is addressed
by switching to lazily loading the initializers of variables rather than
always loading them with the variable declaration. As well as fixing a
deserialization cycle, that should improve laziness of deserialization
in general.
LambdaDefinitionData had 63 spare bits in it, presumably caused by an
off-by-one-error in some previous change. This change claims 32 of those bits
as a counter for the lambda within its context. We could probably move the
numbering to separate storage, like we do for the device-side mangling number,
to optimize the likely-common case where all three numbers (host-side mangling
number, device-side mangling number, and index within the context declaration)
are zero, but that's not done in this change.
Fixes #60985.
Reviewed By: #clang-language-wg, aaron.ballman
Differential Revision: https://reviews.llvm.org/D145737
2023-03-30 14:21:31 -07:00
|
|
|
} else if (D->isLambda()) {
|
|
|
|
// For a lambda, we need some information early for merging.
|
|
|
|
Record.push_back(CXXLambda);
|
|
|
|
if (auto *Context = D->getLambdaContextDecl()) {
|
|
|
|
Record.AddDeclRef(Context);
|
|
|
|
Record.push_back(D->getLambdaIndexInContext());
|
|
|
|
} else {
|
|
|
|
Record.push_back(0);
|
|
|
|
}
|
[C++20][Modules] Fix crash when function and lambda inside loaded from different modules (#109167)
Summary:
Because AST loading code is lazy and happens in unpredictable order, it
is possible that a function and lambda inside the function can be loaded
from different modules. As a result, the captured DeclRefExpr won’t
match the corresponding VarDecl inside the function. This situation is
reflected in the AST as follows:
```
FunctionDecl 0x555564f4aff0 <Conv.h:33:1, line:41:1> line:33:35 imported in ./thrift_cpp2_base.h hidden tryTo 'Expected<Tgt, const char *> ()' inline
|-also in ./folly-conv.h
`-CompoundStmt 0x555564f7cfc8 <col:43, line:41:1>
|-DeclStmt 0x555564f7ced8 <line:34:3, col:17>
| `-VarDecl 0x555564f7cef8 <col:3, col:16> col:7 imported in ./thrift_cpp2_base.h hidden referenced result 'Tgt' cinit
| `-IntegerLiteral 0x555564f7d080 <col:16> 'int' 0
|-CallExpr 0x555564f7cea8 <line:39:3, col:76> '<dependent type>'
| |-UnresolvedLookupExpr 0x555564f7bea0 <col:3, col:19> '<overloaded function type>' lvalue (no ADL) = 'then_' 0x555564f7bef0
| |-CXXTemporaryObjectExpr 0x555564f7bcb0 <col:25, col:45> 'Expected<bool, int>':'folly::Expected<bool, int>' 'void () noexcept' zeroing
| `-LambdaExpr 0x555564f7bc88 <col:48, col:75> '(lambda at Conv.h:39:48)'
| |-CXXRecordDecl 0x555564f76b88 <col:48> col:48 imported in ./folly-conv.h hidden implicit <undeserialized declarations> class definition
| | |-also in ./thrift_cpp2_base.h
| | `-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init
| | |-DefaultConstructor defaulted_is_constexpr
| | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveConstructor exists simple trivial needs_implicit
| | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveAssignment
| | `-Destructor simple irrelevant trivial constexpr needs_implicit
| `-CompoundStmt 0x555564f7d1a8 <col:58, col:75>
| `-ReturnStmt 0x555564f7d198 <col:60, col:67>
| `-DeclRefExpr 0x555564f7d0a0 <col:67> 'Tgt' lvalue Var 0x555564f7d0c8 'result' 'Tgt' refers_to_enclosing_variable_or_capture
`-ReturnStmt 0x555564f7bc78 <line:40:3, col:11>
`-InitListExpr 0x555564f7bc38 <col:10, col:11> 'void'
```
This diff modifies the AST deserialization process to load lambdas
within the canonical function declaration sooner, immediately following
the function, ensuring that they are loaded from the same module.
Re-land https://github.com/llvm/llvm-project/pull/104512 Added test case
that caused crash due to multiple enclosed lambdas deserialization.
Test Plan: check-clang
2024-09-25 08:31:49 +01:00
|
|
|
// For lambdas inside canonical FunctionDecl remember the mapping.
|
|
|
|
if (auto FD = llvm::dyn_cast_or_null<FunctionDecl>(D->getDeclContext());
|
|
|
|
FD && FD->isCanonicalDecl()) {
|
2024-12-16 12:22:43 +00:00
|
|
|
Writer.RelatedDeclsMap[Writer.GetDeclRef(FD)].push_back(
|
2024-09-27 07:33:59 +01:00
|
|
|
Writer.GetDeclRef(D));
|
[C++20][Modules] Fix crash when function and lambda inside loaded from different modules (#109167)
Summary:
Because AST loading code is lazy and happens in unpredictable order, it
is possible that a function and lambda inside the function can be loaded
from different modules. As a result, the captured DeclRefExpr won’t
match the corresponding VarDecl inside the function. This situation is
reflected in the AST as follows:
```
FunctionDecl 0x555564f4aff0 <Conv.h:33:1, line:41:1> line:33:35 imported in ./thrift_cpp2_base.h hidden tryTo 'Expected<Tgt, const char *> ()' inline
|-also in ./folly-conv.h
`-CompoundStmt 0x555564f7cfc8 <col:43, line:41:1>
|-DeclStmt 0x555564f7ced8 <line:34:3, col:17>
| `-VarDecl 0x555564f7cef8 <col:3, col:16> col:7 imported in ./thrift_cpp2_base.h hidden referenced result 'Tgt' cinit
| `-IntegerLiteral 0x555564f7d080 <col:16> 'int' 0
|-CallExpr 0x555564f7cea8 <line:39:3, col:76> '<dependent type>'
| |-UnresolvedLookupExpr 0x555564f7bea0 <col:3, col:19> '<overloaded function type>' lvalue (no ADL) = 'then_' 0x555564f7bef0
| |-CXXTemporaryObjectExpr 0x555564f7bcb0 <col:25, col:45> 'Expected<bool, int>':'folly::Expected<bool, int>' 'void () noexcept' zeroing
| `-LambdaExpr 0x555564f7bc88 <col:48, col:75> '(lambda at Conv.h:39:48)'
| |-CXXRecordDecl 0x555564f76b88 <col:48> col:48 imported in ./folly-conv.h hidden implicit <undeserialized declarations> class definition
| | |-also in ./thrift_cpp2_base.h
| | `-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init
| | |-DefaultConstructor defaulted_is_constexpr
| | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveConstructor exists simple trivial needs_implicit
| | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param
| | |-MoveAssignment
| | `-Destructor simple irrelevant trivial constexpr needs_implicit
| `-CompoundStmt 0x555564f7d1a8 <col:58, col:75>
| `-ReturnStmt 0x555564f7d198 <col:60, col:67>
| `-DeclRefExpr 0x555564f7d0a0 <col:67> 'Tgt' lvalue Var 0x555564f7d0c8 'result' 'Tgt' refers_to_enclosing_variable_or_capture
`-ReturnStmt 0x555564f7bc78 <line:40:3, col:11>
`-InitListExpr 0x555564f7bc38 <col:10, col:11> 'void'
```
This diff modifies the AST deserialization process to load lambdas
within the canonical function declaration sooner, immediately following
the function, ensuring that they are loaded from the same module.
Re-land https://github.com/llvm/llvm-project/pull/104512 Added test case
that caused crash due to multiple enclosed lambdas deserialization.
Test Plan: check-clang
2024-09-25 08:31:49 +01:00
|
|
|
}
|
2010-06-19 19:28:53 +00:00
|
|
|
} else {
|
|
|
|
Record.push_back(CXXRecNotTemplate);
|
|
|
|
}
|
|
|
|
|
2014-04-19 03:48:30 +00:00
|
|
|
Record.push_back(D->isThisDeclarationADefinition());
|
|
|
|
if (D->isThisDeclarationADefinition())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddCXXDefinitionData(D);
|
2014-04-19 03:48:30 +00:00
|
|
|
|
2024-08-08 13:14:09 +08:00
|
|
|
if (D->isCompleteDefinition() && D->isInNamedModule())
|
|
|
|
Writer.AddDeclRef(D, Writer.ModularCodegenDecls);
|
|
|
|
|
2013-01-25 22:31:03 +00:00
|
|
|
// Store (what we currently believe to be) the key function to avoid
|
|
|
|
// deserializing every method so we can compute it.
|
2024-08-08 13:14:09 +08:00
|
|
|
//
|
|
|
|
// FIXME: Avoid adding the key function if the class is defined in
|
|
|
|
// module purview since in that case the key function is meaningless.
|
2018-08-01 20:48:16 +00:00
|
|
|
if (D->isCompleteDefinition())
|
2024-11-07 14:40:21 -08:00
|
|
|
Record.AddDeclRef(Record.getASTContext().getCurrentKeyFunction(D));
|
2010-10-14 20:14:38 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_CXX_RECORD;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitFunctionDecl(D);
|
2012-10-12 05:31:40 +00:00
|
|
|
if (D->isCanonicalDecl()) {
|
|
|
|
Record.push_back(D->size_overridden_methods());
|
2017-12-17 23:52:45 +00:00
|
|
|
for (const CXXMethodDecl *MD : D->overridden_methods())
|
|
|
|
Record.AddDeclRef(MD);
|
2012-10-12 05:31:40 +00:00
|
|
|
} else {
|
|
|
|
// We only need to record overridden methods once for the canonical decl.
|
|
|
|
Record.push_back(0);
|
|
|
|
}
|
2014-07-26 06:37:51 +00:00
|
|
|
|
2015-12-11 22:41:00 +00:00
|
|
|
if (D->getDeclContext() == D->getLexicalDeclContext() &&
|
2022-08-14 13:48:18 +02:00
|
|
|
D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() &&
|
|
|
|
!D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() &&
|
2014-07-26 06:37:51 +00:00
|
|
|
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
|
[C++20] [Modules] Write ODRHash for decls in GMF
Previously, we skipped calculating ODRHash for decls in GMF when writing
them to .pcm files as an optimization. But actually, it is not
true that this will be a pure optimization. Whether or not it is
beneficial depends on the use cases. For example, if we're writing a
function `a` in module and there are 10 consumers of `a` in other TUs,
then the other TUs will pay for the cost to calculate the ODR hash for
`a` ten times. Then this optimization doesn't work. However, if all the
consumers of the module didn't touch `a`, then we can save the cost to
calculate the ODR hash of `a` for 1 times.
And the assumption to make it was: generally, the consumers of a module
may only consume a small part of the imported module. This is the reason
why we tried to load declarations, types and identifiers lazily. Then it
looks good to do the similar thing for calculating ODR hashs.
It works fine for a long time, until we started to look into the support
of modules in clangd. Then we meet multiple issue reports complaining
we're calculating ODR hash in the wrong place. To workaround these issue
reports, I decided to always write the ODRhash for decls in GMF. In my
local test, I only observed less than 1% compile time regression after
doing this. So it should be fine.
2024-07-18 11:24:02 +08:00
|
|
|
!D->hasExtInfo() && !D->isExplicitlyDefaulted()) {
|
2023-12-21 10:30:12 +08:00
|
|
|
if (D->getTemplatedKind() == FunctionDecl::TK_NonTemplate ||
|
|
|
|
D->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate ||
|
|
|
|
D->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
|
|
|
|
D->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate)
|
|
|
|
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
|
|
|
|
else if (D->getTemplatedKind() ==
|
|
|
|
FunctionDecl::TK_FunctionTemplateSpecialization) {
|
|
|
|
FunctionTemplateSpecializationInfo *FTSInfo =
|
|
|
|
D->getTemplateSpecializationInfo();
|
|
|
|
|
|
|
|
if (FTSInfo->TemplateArguments->size() == 1) {
|
|
|
|
const TemplateArgument &TA = FTSInfo->TemplateArguments->get(0);
|
|
|
|
if (TA.getKind() == TemplateArgument::Type &&
|
|
|
|
!FTSInfo->TemplateArgumentsAsWritten &&
|
|
|
|
!FTSInfo->getMemberSpecializationInfo())
|
|
|
|
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
|
|
|
|
}
|
|
|
|
} else if (D->getTemplatedKind() ==
|
|
|
|
FunctionDecl::TK_DependentFunctionTemplateSpecialization) {
|
|
|
|
DependentFunctionTemplateSpecializationInfo *DFTSInfo =
|
|
|
|
D->getDependentSpecializationInfo();
|
|
|
|
if (!DFTSInfo->TemplateArgumentsAsWritten)
|
|
|
|
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
|
|
|
|
}
|
|
|
|
}
|
2014-07-26 06:37:51 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_CXX_METHOD;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
|
2023-10-26 19:22:52 +04:00
|
|
|
static_assert(DeclContext::NumCXXConstructorDeclBits == 64,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"CXXConstructorDeclBits");
|
|
|
|
|
2021-05-03 05:00:26 -07:00
|
|
|
Record.push_back(D->getTrailingAllocKind());
|
2019-05-09 03:59:21 +00:00
|
|
|
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
|
P0136R1, DR1573, DR1645, DR1715, DR1736, DR1903, DR1941, DR1959, DR1991:
Replace inheriting constructors implementation with new approach, voted into
C++ last year as a DR against C++11.
Instead of synthesizing a set of derived class constructors for each inherited
base class constructor, we make the constructors of the base class visible to
constructor lookup in the derived class, using the normal rules for
using-declarations.
For constructors, UsingShadowDecl now has a ConstructorUsingShadowDecl derived
class that tracks the requisite additional information. We create shadow
constructors (not found by name lookup) in the derived class to model the
actual initialization, and have a new expression node,
CXXInheritedCtorInitExpr, to model the initialization of a base class from such
a constructor. (This initialization is special because it performs real perfect
forwarding of arguments.)
In cases where argument forwarding is not possible (for inalloca calls,
variadic calls, and calls with callee parameter cleanup), the shadow inheriting
constructor is not emitted and instead we directly emit the initialization code
into the caller of the inherited constructor.
Note that this new model is not perfectly compatible with the old model in some
corner cases. In particular:
* if B inherits a private constructor from A, and C uses that constructor to
construct a B, then we previously required that A befriends B and B
befriends C, but the new rules require A to befriend C directly, and
* if a derived class has its own constructors (and so its implicit default
constructor is suppressed), it may still inherit a default constructor from
a base class
llvm-svn: 274049
2016-06-28 19:03:57 +00:00
|
|
|
if (auto Inherited = D->getInheritedConstructor()) {
|
|
|
|
Record.AddDeclRef(Inherited.getShadowDecl());
|
|
|
|
Record.AddDeclRef(Inherited.getConstructor());
|
|
|
|
}
|
|
|
|
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitCXXMethodDecl(D);
|
2019-05-09 03:59:21 +00:00
|
|
|
Code = serialization::DECL_CXX_CONSTRUCTOR;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitCXXMethodDecl(D);
|
2010-07-02 15:58:43 +00:00
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getOperatorDelete());
|
2017-10-13 01:55:36 +00:00
|
|
|
if (D->getOperatorDelete())
|
|
|
|
Record.AddStmt(D->getOperatorDeleteThisArg());
|
2010-07-02 15:58:43 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_CXX_DESTRUCTOR;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
|
2019-05-09 03:59:21 +00:00
|
|
|
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
|
2010-05-07 21:43:38 +00:00
|
|
|
VisitCXXMethodDecl(D);
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_CXX_CONVERSION;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2011-12-02 23:23:56 +00:00
|
|
|
void ASTDeclWriter::VisitImportDecl(ImportDecl *D) {
|
|
|
|
VisitDecl(D);
|
2012-10-03 01:58:45 +00:00
|
|
|
Record.push_back(Writer.getSubmoduleID(D->getImportedModule()));
|
2011-12-02 23:23:56 +00:00
|
|
|
ArrayRef<SourceLocation> IdentifierLocs = D->getIdentifierLocs();
|
|
|
|
Record.push_back(!IdentifierLocs.empty());
|
|
|
|
if (IdentifierLocs.empty()) {
|
2018-08-09 21:09:38 +00:00
|
|
|
Record.AddSourceLocation(D->getEndLoc());
|
2011-12-02 23:23:56 +00:00
|
|
|
Record.push_back(1);
|
|
|
|
} else {
|
|
|
|
for (unsigned I = 0, N = IdentifierLocs.size(); I != N; ++I)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(IdentifierLocs[I]);
|
2011-12-02 23:23:56 +00:00
|
|
|
Record.push_back(IdentifierLocs.size());
|
|
|
|
}
|
|
|
|
// Note: the number of source locations must always be the last element in
|
|
|
|
// the record.
|
|
|
|
Code = serialization::DECL_IMPORT;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) {
|
2010-06-05 05:09:32 +00:00
|
|
|
VisitDecl(D);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getColonLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_ACCESS_SPEC;
|
2010-06-05 05:09:32 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
|
2013-01-31 09:54:08 +00:00
|
|
|
// Record the number of friend type template parameter lists here
|
|
|
|
// so as to simplify memory allocation during deserialization.
|
|
|
|
Record.push_back(D->NumTPLists);
|
2010-07-05 10:38:01 +00:00
|
|
|
VisitDecl(D);
|
2024-12-09 09:47:38 -08:00
|
|
|
bool hasFriendDecl = isa<NamedDecl *>(D->Friend);
|
2013-01-31 09:54:08 +00:00
|
|
|
Record.push_back(hasFriendDecl);
|
|
|
|
if (hasFriendDecl)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getFriendDecl());
|
2010-06-29 22:47:00 +00:00
|
|
|
else
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeSourceInfo(D->getFriendType());
|
2013-01-31 09:54:08 +00:00
|
|
|
for (unsigned i = 0; i < D->NumTPLists; ++i)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i));
|
|
|
|
Record.AddDeclRef(D->getNextFriend());
|
2010-10-16 06:59:13 +00:00
|
|
|
Record.push_back(D->UnsupportedFriend);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->FriendLoc);
|
2024-08-15 21:16:30 +02:00
|
|
|
Record.AddSourceLocation(D->EllipsisLoc);
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_FRIEND;
|
2010-06-29 22:47:00 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
|
2010-07-22 16:04:10 +00:00
|
|
|
VisitDecl(D);
|
|
|
|
Record.push_back(D->getNumTemplateParameters());
|
|
|
|
for (unsigned i = 0, e = D->getNumTemplateParameters(); i != e; ++i)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateParameterList(D->getTemplateParameterList(i));
|
2014-05-22 05:54:18 +00:00
|
|
|
Record.push_back(D->getFriendDecl() != nullptr);
|
2010-07-22 16:04:10 +00:00
|
|
|
if (D->getFriendDecl())
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getFriendDecl());
|
2010-07-22 16:04:10 +00:00
|
|
|
else
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeSourceInfo(D->getFriendType());
|
|
|
|
Record.AddSourceLocation(D->getFriendLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_FRIEND_TEMPLATE;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitTemplateDecl(TemplateDecl *D) {
|
2010-06-19 19:28:53 +00:00
|
|
|
VisitNamedDecl(D);
|
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateParameterList(D->getTemplateParameters());
|
2022-08-14 13:48:18 +02:00
|
|
|
Record.AddDeclRef(D->getTemplatedDecl());
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 21:25:49 +00:00
|
|
|
void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {
|
|
|
|
VisitTemplateDecl(D);
|
|
|
|
Record.AddStmt(D->getConstraintExpr());
|
|
|
|
Code = serialization::DECL_CONCEPT;
|
|
|
|
}
|
|
|
|
|
2022-10-24 12:20:36 -07:00
|
|
|
void ASTDeclWriter::VisitImplicitConceptSpecializationDecl(
|
|
|
|
ImplicitConceptSpecializationDecl *D) {
|
|
|
|
Record.push_back(D->getTemplateArguments().size());
|
|
|
|
VisitDecl(D);
|
|
|
|
for (const TemplateArgument &Arg : D->getTemplateArguments())
|
|
|
|
Record.AddTemplateArgument(Arg);
|
|
|
|
Code = serialization::DECL_IMPLICIT_CONCEPT_SPECIALIZATION;
|
|
|
|
}
|
|
|
|
|
2020-01-18 09:11:43 +02:00
|
|
|
void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
|
|
|
|
Code = serialization::DECL_REQUIRES_EXPR_BODY;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
|
2012-01-14 15:13:49 +00:00
|
|
|
VisitRedeclarable(D);
|
|
|
|
|
2010-09-08 19:31:22 +00:00
|
|
|
// Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
|
|
|
|
// getCommonPtr() can be used while this is still initializing.
|
2024-11-06 07:25:29 -07:00
|
|
|
if (D->isFirstDecl()) {
|
2011-12-19 18:19:24 +00:00
|
|
|
// This declaration owns the 'common' pointer, so serialize that data now.
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getInstantiatedFromMemberTemplate());
|
2024-11-06 07:25:29 -07:00
|
|
|
if (D->getInstantiatedFromMemberTemplate())
|
|
|
|
Record.push_back(D->isMemberSpecialization());
|
|
|
|
}
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2010-09-08 19:31:22 +00:00
|
|
|
VisitTemplateDecl(D);
|
|
|
|
Record.push_back(D->getIdentifierNamespace());
|
2010-07-29 16:11:51 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
2010-07-29 16:11:51 +00:00
|
|
|
VisitRedeclarableTemplateDecl(D);
|
|
|
|
|
2015-02-27 23:05:10 +00:00
|
|
|
if (D->isFirstDecl())
|
|
|
|
AddTemplateSpecializations(D);
|
2024-04-12 12:51:58 +08:00
|
|
|
|
|
|
|
// Force emitting the corresponding deduction guide in reduced BMI mode.
|
|
|
|
// Otherwise, the deduction guide may be optimized out incorrectly.
|
|
|
|
if (Writer.isGeneratingReducedBMI()) {
|
2024-11-07 14:40:21 -08:00
|
|
|
auto Name =
|
|
|
|
Record.getASTContext().DeclarationNames.getCXXDeductionGuideName(D);
|
2024-04-12 12:51:58 +08:00
|
|
|
for (auto *DG : D->getDeclContext()->noload_lookup(Name))
|
2024-06-03 14:37:47 +08:00
|
|
|
Writer.GetDeclRef(DG->getCanonicalDecl());
|
2024-04-12 12:51:58 +08:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_CLASS_TEMPLATE;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
|
2010-05-07 21:43:38 +00:00
|
|
|
ClassTemplateSpecializationDecl *D) {
|
2015-08-22 01:47:18 +00:00
|
|
|
RegisterTemplateSpecialization(D->getSpecializedTemplate(), D);
|
|
|
|
|
2010-06-23 13:48:30 +00:00
|
|
|
VisitCXXRecordDecl(D);
|
|
|
|
|
|
|
|
llvm::PointerUnion<ClassTemplateDecl *,
|
|
|
|
ClassTemplatePartialSpecializationDecl *> InstFrom
|
|
|
|
= D->getSpecializedTemplateOrPartial();
|
2011-08-17 21:35:28 +00:00
|
|
|
if (Decl *InstFromD = InstFrom.dyn_cast<ClassTemplateDecl *>()) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(InstFromD);
|
2010-06-23 13:48:30 +00:00
|
|
|
} else {
|
2024-12-09 09:47:38 -08:00
|
|
|
Record.AddDeclRef(cast<ClassTemplatePartialSpecializationDecl *>(InstFrom));
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateArgumentList(&D->getTemplateInstantiationArgs());
|
2010-06-23 13:48:30 +00:00
|
|
|
}
|
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateArgumentList(&D->getTemplateArgs());
|
|
|
|
Record.AddSourceLocation(D->getPointOfInstantiation());
|
2010-06-23 13:48:30 +00:00
|
|
|
Record.push_back(D->getSpecializationKind());
|
2012-10-01 07:34:47 +00:00
|
|
|
Record.push_back(D->isCanonicalDecl());
|
2010-06-23 13:48:30 +00:00
|
|
|
|
2010-07-20 13:59:40 +00:00
|
|
|
if (D->isCanonicalDecl()) {
|
2018-07-30 19:24:48 +00:00
|
|
|
// When reading, we'll add it to the folding set of the following template.
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl());
|
2010-07-09 21:11:43 +00:00
|
|
|
}
|
|
|
|
|
2024-05-14 16:09:57 -04:00
|
|
|
bool ExplicitInstantiation =
|
|
|
|
D->getTemplateSpecializationKind() ==
|
|
|
|
TSK_ExplicitInstantiationDeclaration ||
|
|
|
|
D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
|
|
|
|
Record.push_back(ExplicitInstantiation);
|
|
|
|
if (ExplicitInstantiation) {
|
|
|
|
Record.AddSourceLocation(D->getExternKeywordLoc());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getTemplateKeywordLoc());
|
2013-09-09 16:55:27 +00:00
|
|
|
}
|
|
|
|
|
2024-05-14 16:09:57 -04:00
|
|
|
const ASTTemplateArgumentListInfo *ArgsWritten =
|
|
|
|
D->getTemplateArgsAsWritten();
|
|
|
|
Record.push_back(!!ArgsWritten);
|
|
|
|
if (ArgsWritten)
|
|
|
|
Record.AddASTTemplateArgumentListInfo(ArgsWritten);
|
|
|
|
|
2024-09-27 14:23:02 +08:00
|
|
|
// Mention the implicitly generated C++ deduction guide to make sure the
|
|
|
|
// deduction guide will be rewritten as expected.
|
|
|
|
//
|
|
|
|
// FIXME: Would it be more efficient to add a callback register function
|
|
|
|
// in sema to register the deduction guide?
|
|
|
|
if (Writer.isWritingStdCXXNamedModules()) {
|
2024-11-07 14:40:21 -08:00
|
|
|
auto Name =
|
|
|
|
Record.getASTContext().DeclarationNames.getCXXDeductionGuideName(
|
|
|
|
D->getSpecializedTemplate());
|
2024-09-27 14:23:02 +08:00
|
|
|
for (auto *DG : D->getDeclContext()->noload_lookup(Name))
|
|
|
|
Writer.GetDeclRef(DG->getCanonicalDecl());
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_CLASS_TEMPLATE_SPECIALIZATION;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
|
2010-05-07 21:43:38 +00:00
|
|
|
ClassTemplatePartialSpecializationDecl *D) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateParameterList(D->getTemplateParameters());
|
2010-06-23 13:48:30 +00:00
|
|
|
|
2019-12-23 08:37:35 +02:00
|
|
|
VisitClassTemplateSpecializationDecl(D);
|
|
|
|
|
2010-06-23 13:48:30 +00:00
|
|
|
// These are read/set from/to the first declaration.
|
2024-11-06 07:25:29 -07:00
|
|
|
if (D->getPreviousDecl() == nullptr) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getInstantiatedFromMember());
|
2024-11-06 07:25:29 -07:00
|
|
|
Record.push_back(D->isMemberSpecialization());
|
|
|
|
}
|
2010-06-23 13:48:30 +00:00
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 01:03:05 +00:00
|
|
|
void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) {
|
|
|
|
VisitRedeclarableTemplateDecl(D);
|
|
|
|
|
2015-02-27 23:05:10 +00:00
|
|
|
if (D->isFirstDecl())
|
|
|
|
AddTemplateSpecializations(D);
|
2013-08-06 01:03:05 +00:00
|
|
|
Code = serialization::DECL_VAR_TEMPLATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
|
|
|
|
VarTemplateSpecializationDecl *D) {
|
2015-08-22 01:47:18 +00:00
|
|
|
RegisterTemplateSpecialization(D->getSpecializedTemplate(), D);
|
|
|
|
|
2013-08-06 01:03:05 +00:00
|
|
|
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
|
|
|
|
InstFrom = D->getSpecializedTemplateOrPartial();
|
|
|
|
if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(InstFromD);
|
2013-08-06 01:03:05 +00:00
|
|
|
} else {
|
2024-12-09 09:47:38 -08:00
|
|
|
Record.AddDeclRef(cast<VarTemplatePartialSpecializationDecl *>(InstFrom));
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateArgumentList(&D->getTemplateInstantiationArgs());
|
2013-08-06 01:03:05 +00:00
|
|
|
}
|
|
|
|
|
2024-05-14 16:09:57 -04:00
|
|
|
bool ExplicitInstantiation =
|
|
|
|
D->getTemplateSpecializationKind() ==
|
|
|
|
TSK_ExplicitInstantiationDeclaration ||
|
|
|
|
D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
|
|
|
|
Record.push_back(ExplicitInstantiation);
|
|
|
|
if (ExplicitInstantiation) {
|
|
|
|
Record.AddSourceLocation(D->getExternKeywordLoc());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getTemplateKeywordLoc());
|
2013-08-06 01:03:05 +00:00
|
|
|
}
|
|
|
|
|
2024-05-14 16:09:57 -04:00
|
|
|
const ASTTemplateArgumentListInfo *ArgsWritten =
|
|
|
|
D->getTemplateArgsAsWritten();
|
|
|
|
Record.push_back(!!ArgsWritten);
|
|
|
|
if (ArgsWritten)
|
|
|
|
Record.AddASTTemplateArgumentListInfo(ArgsWritten);
|
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateArgumentList(&D->getTemplateArgs());
|
|
|
|
Record.AddSourceLocation(D->getPointOfInstantiation());
|
2013-08-06 01:03:05 +00:00
|
|
|
Record.push_back(D->getSpecializationKind());
|
2017-12-02 02:48:42 +00:00
|
|
|
Record.push_back(D->IsCompleteDefinition);
|
2022-08-14 13:48:18 +02:00
|
|
|
|
|
|
|
VisitVarDecl(D);
|
|
|
|
|
2013-08-06 01:03:05 +00:00
|
|
|
Record.push_back(D->isCanonicalDecl());
|
|
|
|
|
|
|
|
if (D->isCanonicalDecl()) {
|
|
|
|
// When reading, we'll add it to the folding set of the following template.
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl());
|
2013-08-06 01:03:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Code = serialization::DECL_VAR_TEMPLATE_SPECIALIZATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
|
|
|
|
VarTemplatePartialSpecializationDecl *D) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateParameterList(D->getTemplateParameters());
|
2013-08-06 01:03:05 +00:00
|
|
|
|
2019-12-23 08:37:35 +02:00
|
|
|
VisitVarTemplateSpecializationDecl(D);
|
|
|
|
|
2013-08-06 01:03:05 +00:00
|
|
|
// These are read/set from/to the first declaration.
|
2024-11-06 07:25:29 -07:00
|
|
|
if (D->getPreviousDecl() == nullptr) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getInstantiatedFromMember());
|
2024-11-06 07:25:29 -07:00
|
|
|
Record.push_back(D->isMemberSpecialization());
|
|
|
|
}
|
2013-08-06 01:03:05 +00:00
|
|
|
|
|
|
|
Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
|
2010-07-29 16:11:51 +00:00
|
|
|
VisitRedeclarableTemplateDecl(D);
|
2010-06-22 09:55:07 +00:00
|
|
|
|
2015-02-27 23:05:10 +00:00
|
|
|
if (D->isFirstDecl())
|
|
|
|
AddTemplateSpecializations(D);
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_FUNCTION_TEMPLATE;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
|
2020-01-15 02:48:42 +02:00
|
|
|
Record.push_back(D->hasTypeConstraint());
|
2010-06-19 19:28:53 +00:00
|
|
|
VisitTypeDecl(D);
|
|
|
|
|
|
|
|
Record.push_back(D->wasDeclaredWithTypename());
|
2020-01-15 02:48:42 +02:00
|
|
|
|
|
|
|
const TypeConstraint *TC = D->getTypeConstraint();
|
2025-01-08 19:40:16 +08:00
|
|
|
if (D->hasTypeConstraint())
|
|
|
|
Record.push_back(/*TypeConstraintInitialized=*/TC != nullptr);
|
2020-01-15 02:48:42 +02:00
|
|
|
if (TC) {
|
2023-08-02 14:00:16 +02:00
|
|
|
auto *CR = TC->getConceptReference();
|
|
|
|
Record.push_back(CR != nullptr);
|
|
|
|
if (CR)
|
|
|
|
Record.AddConceptReference(CR);
|
2020-01-15 02:48:42 +02:00
|
|
|
Record.AddStmt(TC->getImmediatelyDeclaredConstraint());
|
|
|
|
Record.push_back(D->isExpandedParameterPack());
|
|
|
|
if (D->isExpandedParameterPack())
|
|
|
|
Record.push_back(D->getNumExpansionParameters());
|
|
|
|
}
|
|
|
|
|
2015-06-10 01:47:58 +00:00
|
|
|
bool OwnsDefaultArg = D->hasDefaultArgument() &&
|
|
|
|
!D->defaultArgumentWasInherited();
|
|
|
|
Record.push_back(OwnsDefaultArg);
|
|
|
|
if (OwnsDefaultArg)
|
2024-05-21 20:27:50 -03:00
|
|
|
Record.AddTemplateArgumentLoc(D->getDefaultArgument());
|
2010-06-19 19:28:53 +00:00
|
|
|
|
2025-01-08 19:40:16 +08:00
|
|
|
if (!D->hasTypeConstraint() && !OwnsDefaultArg &&
|
2023-12-21 10:30:12 +08:00
|
|
|
D->getDeclContext() == D->getLexicalDeclContext() &&
|
|
|
|
!D->isInvalidDecl() && !D->hasAttrs() &&
|
2023-12-21 16:35:20 +08:00
|
|
|
!D->isTopLevelDeclInObjCContainer() && !D->isImplicit() &&
|
2023-12-21 10:30:12 +08:00
|
|
|
D->getDeclName().getNameKind() == DeclarationName::Identifier)
|
|
|
|
AbbrevToUse = Writer.getDeclTemplateTypeParmAbbrev();
|
|
|
|
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_TEMPLATE_TYPE_PARM;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
2011-01-19 20:10:05 +00:00
|
|
|
// For an expanded parameter pack, record the number of expansion types here
|
2012-09-07 02:06:42 +00:00
|
|
|
// so that it's easier for deserialization to allocate the right amount of
|
|
|
|
// memory.
|
2020-01-22 02:03:05 +02:00
|
|
|
Expr *TypeConstraint = D->getPlaceholderTypeConstraint();
|
|
|
|
Record.push_back(!!TypeConstraint);
|
2011-01-19 20:10:05 +00:00
|
|
|
if (D->isExpandedParameterPack())
|
|
|
|
Record.push_back(D->getNumExpansionTypes());
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2011-02-09 01:13:10 +00:00
|
|
|
VisitDeclaratorDecl(D);
|
2010-06-25 16:25:09 +00:00
|
|
|
// TemplateParmPosition.
|
|
|
|
Record.push_back(D->getDepth());
|
|
|
|
Record.push_back(D->getPosition());
|
2020-01-22 02:03:05 +02:00
|
|
|
if (TypeConstraint)
|
|
|
|
Record.AddStmt(TypeConstraint);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2011-01-19 20:10:05 +00:00
|
|
|
if (D->isExpandedParameterPack()) {
|
|
|
|
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTypeRef(D->getExpansionType(I));
|
|
|
|
Record.AddTypeSourceInfo(D->getExpansionTypeSourceInfo(I));
|
2011-01-19 20:10:05 +00:00
|
|
|
}
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2011-01-19 20:10:05 +00:00
|
|
|
Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK;
|
|
|
|
} else {
|
|
|
|
// Rest of NonTypeTemplateParmDecl.
|
|
|
|
Record.push_back(D->isParameterPack());
|
2015-06-10 01:47:58 +00:00
|
|
|
bool OwnsDefaultArg = D->hasDefaultArgument() &&
|
|
|
|
!D->defaultArgumentWasInherited();
|
|
|
|
Record.push_back(OwnsDefaultArg);
|
|
|
|
if (OwnsDefaultArg)
|
2024-05-22 12:18:44 -03:00
|
|
|
Record.AddTemplateArgumentLoc(D->getDefaultArgument());
|
2011-01-19 20:10:05 +00:00
|
|
|
Code = serialization::DECL_NON_TYPE_TEMPLATE_PARM;
|
2010-06-25 16:25:09 +00:00
|
|
|
}
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
|
2012-09-07 02:06:42 +00:00
|
|
|
// For an expanded parameter pack, record the number of expansion types here
|
|
|
|
// so that it's easier for deserialization to allocate the right amount of
|
|
|
|
// memory.
|
|
|
|
if (D->isExpandedParameterPack())
|
|
|
|
Record.push_back(D->getNumExpansionTemplateParameters());
|
|
|
|
|
2010-07-08 17:12:57 +00:00
|
|
|
VisitTemplateDecl(D);
|
2024-04-11 13:20:05 -04:00
|
|
|
Record.push_back(D->wasDeclaredWithTypename());
|
2010-07-08 17:12:57 +00:00
|
|
|
// TemplateParmPosition.
|
|
|
|
Record.push_back(D->getDepth());
|
|
|
|
Record.push_back(D->getPosition());
|
2012-09-07 02:06:42 +00:00
|
|
|
|
|
|
|
if (D->isExpandedParameterPack()) {
|
|
|
|
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
|
|
|
|
I != N; ++I)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I));
|
2012-09-07 02:06:42 +00:00
|
|
|
Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
|
|
|
|
} else {
|
|
|
|
// Rest of TemplateTemplateParmDecl.
|
|
|
|
Record.push_back(D->isParameterPack());
|
2015-06-10 01:47:58 +00:00
|
|
|
bool OwnsDefaultArg = D->hasDefaultArgument() &&
|
|
|
|
!D->defaultArgumentWasInherited();
|
|
|
|
Record.push_back(OwnsDefaultArg);
|
|
|
|
if (OwnsDefaultArg)
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddTemplateArgumentLoc(D->getDefaultArgument());
|
2012-09-07 02:06:42 +00:00
|
|
|
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
|
|
|
|
}
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2011-05-05 21:57:07 +00:00
|
|
|
void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
|
|
|
|
VisitRedeclarableTemplateDecl(D);
|
|
|
|
Code = serialization::DECL_TYPE_ALIAS_TEMPLATE;
|
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
|
2010-07-22 17:28:12 +00:00
|
|
|
VisitDecl(D);
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getAssertExpr());
|
2012-07-11 22:37:56 +00:00
|
|
|
Record.push_back(D->isFailed());
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getMessage());
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddSourceLocation(D->getRParenLoc());
|
2010-08-18 23:57:32 +00:00
|
|
|
Code = serialization::DECL_STATIC_ASSERT;
|
2010-05-07 21:43:38 +00:00
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Emit the DeclContext part of a declaration context decl.
|
2016-04-13 02:12:03 +00:00
|
|
|
void ASTDeclWriter::VisitDeclContext(DeclContext *DC) {
|
2023-02-03 14:29:14 +08:00
|
|
|
static_assert(DeclContext::NumDeclContextBits == 13,
|
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"DeclContextBits");
|
|
|
|
|
2024-04-12 12:51:58 +08:00
|
|
|
uint64_t LexicalOffset = 0;
|
|
|
|
uint64_t VisibleOffset = 0;
|
|
|
|
|
|
|
|
if (Writer.isGeneratingReducedBMI() && isa<NamespaceDecl>(DC) &&
|
|
|
|
cast<NamespaceDecl>(DC)->isFromExplicitGlobalModule()) {
|
|
|
|
// In reduced BMI, delay writing lexical and visible block for namespace
|
|
|
|
// in the global module fragment. See the comments of DelayedNamespace for
|
|
|
|
// details.
|
|
|
|
Writer.DelayedNamespace.push_back(cast<NamespaceDecl>(DC));
|
|
|
|
} else {
|
2024-11-07 14:40:21 -08:00
|
|
|
LexicalOffset =
|
|
|
|
Writer.WriteDeclContextLexicalBlock(Record.getASTContext(), DC);
|
2025-01-16 10:12:03 +08:00
|
|
|
VisibleOffset =
|
|
|
|
Writer.WriteDeclContextVisibleBlock(Record.getASTContext(), DC);
|
2024-04-12 12:51:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Record.AddOffset(LexicalOffset);
|
|
|
|
Record.AddOffset(VisibleOffset);
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
|
|
|
|
2015-08-22 01:47:18 +00:00
|
|
|
const Decl *ASTWriter::getFirstLocalDecl(const Decl *D) {
|
2015-09-11 02:22:03 +00:00
|
|
|
assert(IsLocalDecl(D) && "expected a local declaration");
|
2015-08-22 01:47:18 +00:00
|
|
|
|
|
|
|
const Decl *Canon = D->getCanonicalDecl();
|
2015-09-11 02:22:03 +00:00
|
|
|
if (IsLocalDecl(Canon))
|
2015-08-22 01:47:18 +00:00
|
|
|
return Canon;
|
|
|
|
|
|
|
|
const Decl *&CacheEntry = FirstLocalDeclCache[Canon];
|
|
|
|
if (CacheEntry)
|
|
|
|
return CacheEntry;
|
|
|
|
|
|
|
|
for (const Decl *Redecl = D; Redecl; Redecl = Redecl->getPreviousDecl())
|
2015-09-11 02:22:03 +00:00
|
|
|
if (IsLocalDecl(Redecl))
|
2015-08-22 01:47:18 +00:00
|
|
|
D = Redecl;
|
|
|
|
return CacheEntry = D;
|
2015-07-12 23:43:21 +00:00
|
|
|
}
|
|
|
|
|
2010-08-03 17:30:10 +00:00
|
|
|
template <typename T>
|
2010-08-18 23:56:27 +00:00
|
|
|
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
|
2013-10-17 15:37:26 +00:00
|
|
|
T *First = D->getFirstDecl();
|
2015-02-06 02:42:59 +00:00
|
|
|
T *MostRecent = First->getMostRecentDecl();
|
2015-08-22 01:47:18 +00:00
|
|
|
T *DAsT = static_cast<T *>(D);
|
2015-02-06 02:42:59 +00:00
|
|
|
if (MostRecent != First) {
|
2015-08-22 01:47:18 +00:00
|
|
|
assert(isRedeclarableDeclKind(DAsT->getKind()) &&
|
2013-01-21 16:16:40 +00:00
|
|
|
"Not considered redeclarable?");
|
2015-02-06 02:42:59 +00:00
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(First);
|
2015-03-05 23:24:12 +00:00
|
|
|
|
2015-08-22 01:47:18 +00:00
|
|
|
// Write out a list of local redeclarations of this declaration if it's the
|
|
|
|
// first local declaration in the chain.
|
|
|
|
const Decl *FirstLocal = Writer.getFirstLocalDecl(DAsT);
|
|
|
|
if (DAsT == FirstLocal) {
|
|
|
|
// Emit a list of all imported first declarations so that we can be sure
|
|
|
|
// that all redeclarations visible to this module are before D in the
|
|
|
|
// redecl chain.
|
|
|
|
unsigned I = Record.size();
|
|
|
|
Record.push_back(0);
|
|
|
|
if (Writer.Chain)
|
|
|
|
AddFirstDeclFromEachModule(DAsT, /*IncludeLocal*/false);
|
|
|
|
// This is the number of imported first declarations + 1.
|
|
|
|
Record[I] = Record.size() - I;
|
2015-08-22 20:13:39 +00:00
|
|
|
|
|
|
|
// Collect the set of local redeclarations of this declaration, from
|
|
|
|
// newest to oldest.
|
2016-04-01 22:52:03 +00:00
|
|
|
ASTWriter::RecordData LocalRedecls;
|
|
|
|
ASTRecordWriter LocalRedeclWriter(Record, LocalRedecls);
|
2015-08-22 20:13:39 +00:00
|
|
|
for (const Decl *Prev = FirstLocal->getMostRecentDecl();
|
|
|
|
Prev != FirstLocal; Prev = Prev->getPreviousDecl())
|
|
|
|
if (!Prev->isFromASTFile())
|
2016-04-01 22:52:03 +00:00
|
|
|
LocalRedeclWriter.AddDeclRef(Prev);
|
2015-08-22 20:13:39 +00:00
|
|
|
|
|
|
|
// If we have any redecls, write them now as a separate record preceding
|
|
|
|
// the declaration itself.
|
|
|
|
if (LocalRedecls.empty())
|
|
|
|
Record.push_back(0);
|
2016-04-13 02:12:03 +00:00
|
|
|
else
|
|
|
|
Record.AddOffset(LocalRedeclWriter.Emit(LOCAL_REDECLARATIONS));
|
2015-08-22 01:47:18 +00:00
|
|
|
} else {
|
|
|
|
Record.push_back(0);
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(FirstLocal);
|
2015-03-05 23:24:12 +00:00
|
|
|
}
|
2012-01-15 16:58:34 +00:00
|
|
|
|
2018-07-30 19:24:48 +00:00
|
|
|
// Make sure that we serialize both the previous and the most-recent
|
2012-01-15 16:58:34 +00:00
|
|
|
// declarations, which (transitively) ensures that all declarations in the
|
|
|
|
// chain get serialized.
|
2015-02-06 02:42:59 +00:00
|
|
|
//
|
|
|
|
// FIXME: This is not correct; when we reach an imported declaration we
|
|
|
|
// won't emit its previous declaration.
|
2015-07-12 23:43:21 +00:00
|
|
|
(void)Writer.GetDeclRef(D->getPreviousDecl());
|
2015-02-06 02:42:59 +00:00
|
|
|
(void)Writer.GetDeclRef(MostRecent);
|
2012-01-15 16:58:34 +00:00
|
|
|
} else {
|
|
|
|
// We use the sentinel value 0 to indicate an only declaration.
|
|
|
|
Record.push_back(0);
|
2011-12-19 18:19:24 +00:00
|
|
|
}
|
2010-08-03 17:30:10 +00:00
|
|
|
}
|
2009-04-27 06:16:06 +00:00
|
|
|
|
2022-07-15 10:45:57 -07:00
|
|
|
void ASTDeclWriter::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
|
|
|
|
VisitNamedDecl(D);
|
|
|
|
VisitDeclContext(D);
|
|
|
|
Record.push_back(D->isCBuffer());
|
|
|
|
Record.AddSourceLocation(D->getLocStart());
|
|
|
|
Record.AddSourceLocation(D->getLBraceLoc());
|
|
|
|
Record.AddSourceLocation(D->getRBraceLoc());
|
|
|
|
|
|
|
|
Code = serialization::DECL_HLSL_BUFFER;
|
|
|
|
}
|
|
|
|
|
2013-03-22 06:34:35 +00:00
|
|
|
void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
|
[OPENMP]Redesign of OMPExecutableDirective/OMPDeclarativeDirective representation.
Summary:
Introduced OMPChildren class to handle all associated clauses, statement
and child expressions/statements. It allows to represent some directives
more correctly (like flush, depobj etc. with pseudo clauses, ordered
depend directives, which are standalone, and target data directives).
Also, it will make easier to avoid using of CapturedStmt in directives,
if required (atomic, tile etc. directives).
Also, it simplifies serialization/deserialization of the
executable/declarative directives.
Reduces number of allocation operations for mapper declarations.
Reviewers: jdoerfert
Subscribers: yaxunl, guansong, jfb, cfe-commits, sstefan1, aaron.ballman, caomhin
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83261
2020-06-26 17:42:31 -04:00
|
|
|
Record.writeOMPChildren(D->Data);
|
2013-03-22 06:34:35 +00:00
|
|
|
VisitDecl(D);
|
|
|
|
Code = serialization::DECL_OMP_THREADPRIVATE;
|
|
|
|
}
|
|
|
|
|
2019-03-07 17:54:44 +00:00
|
|
|
void ASTDeclWriter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
|
[OPENMP]Redesign of OMPExecutableDirective/OMPDeclarativeDirective representation.
Summary:
Introduced OMPChildren class to handle all associated clauses, statement
and child expressions/statements. It allows to represent some directives
more correctly (like flush, depobj etc. with pseudo clauses, ordered
depend directives, which are standalone, and target data directives).
Also, it will make easier to avoid using of CapturedStmt in directives,
if required (atomic, tile etc. directives).
Also, it simplifies serialization/deserialization of the
executable/declarative directives.
Reduces number of allocation operations for mapper declarations.
Reviewers: jdoerfert
Subscribers: yaxunl, guansong, jfb, cfe-commits, sstefan1, aaron.ballman, caomhin
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83261
2020-06-26 17:42:31 -04:00
|
|
|
Record.writeOMPChildren(D->Data);
|
2019-03-07 17:54:44 +00:00
|
|
|
VisitDecl(D);
|
|
|
|
Code = serialization::DECL_OMP_ALLOCATE;
|
|
|
|
}
|
|
|
|
|
2018-09-26 04:28:39 +00:00
|
|
|
void ASTDeclWriter::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
|
[OPENMP]Redesign of OMPExecutableDirective/OMPDeclarativeDirective representation.
Summary:
Introduced OMPChildren class to handle all associated clauses, statement
and child expressions/statements. It allows to represent some directives
more correctly (like flush, depobj etc. with pseudo clauses, ordered
depend directives, which are standalone, and target data directives).
Also, it will make easier to avoid using of CapturedStmt in directives,
if required (atomic, tile etc. directives).
Also, it simplifies serialization/deserialization of the
executable/declarative directives.
Reduces number of allocation operations for mapper declarations.
Reviewers: jdoerfert
Subscribers: yaxunl, guansong, jfb, cfe-commits, sstefan1, aaron.ballman, caomhin
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83261
2020-06-26 17:42:31 -04:00
|
|
|
Record.writeOMPChildren(D->Data);
|
2018-09-26 04:28:39 +00:00
|
|
|
VisitDecl(D);
|
|
|
|
Code = serialization::DECL_OMP_REQUIRES;
|
|
|
|
}
|
|
|
|
|
2016-03-03 05:21:39 +00:00
|
|
|
void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
|
2023-10-26 19:22:52 +04:00
|
|
|
static_assert(DeclContext::NumOMPDeclareReductionDeclBits == 15,
|
2023-02-03 14:29:14 +08:00
|
|
|
"You need to update the serializer after you change the "
|
|
|
|
"NumOMPDeclareReductionDeclBits");
|
|
|
|
|
2016-03-04 09:22:22 +00:00
|
|
|
VisitValueDecl(D);
|
2018-08-09 21:08:08 +00:00
|
|
|
Record.AddSourceLocation(D->getBeginLoc());
|
2018-09-13 16:54:05 +00:00
|
|
|
Record.AddStmt(D->getCombinerIn());
|
|
|
|
Record.AddStmt(D->getCombinerOut());
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getCombiner());
|
2018-09-13 16:54:05 +00:00
|
|
|
Record.AddStmt(D->getInitOrig());
|
|
|
|
Record.AddStmt(D->getInitPriv());
|
2016-04-06 17:06:00 +00:00
|
|
|
Record.AddStmt(D->getInitializer());
|
2023-11-01 12:39:33 +03:00
|
|
|
Record.push_back(llvm::to_underlying(D->getInitializerKind()));
|
2016-04-01 22:52:03 +00:00
|
|
|
Record.AddDeclRef(D->getPrevDeclInScope());
|
2016-03-03 05:21:39 +00:00
|
|
|
Code = serialization::DECL_OMP_DECLARE_REDUCTION;
|
|
|
|
}
|
|
|
|
|
2019-02-01 20:25:04 +00:00
|
|
|
void ASTDeclWriter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
|
[OPENMP]Redesign of OMPExecutableDirective/OMPDeclarativeDirective representation.
Summary:
Introduced OMPChildren class to handle all associated clauses, statement
and child expressions/statements. It allows to represent some directives
more correctly (like flush, depobj etc. with pseudo clauses, ordered
depend directives, which are standalone, and target data directives).
Also, it will make easier to avoid using of CapturedStmt in directives,
if required (atomic, tile etc. directives).
Also, it simplifies serialization/deserialization of the
executable/declarative directives.
Reduces number of allocation operations for mapper declarations.
Reviewers: jdoerfert
Subscribers: yaxunl, guansong, jfb, cfe-commits, sstefan1, aaron.ballman, caomhin
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83261
2020-06-26 17:42:31 -04:00
|
|
|
Record.writeOMPChildren(D->Data);
|
2019-02-01 20:25:04 +00:00
|
|
|
VisitValueDecl(D);
|
|
|
|
Record.AddDeclarationName(D->getVarName());
|
|
|
|
Record.AddDeclRef(D->getPrevDeclInScope());
|
|
|
|
Code = serialization::DECL_OMP_DECLARE_MAPPER;
|
|
|
|
}
|
|
|
|
|
2016-02-11 05:35:55 +00:00
|
|
|
void ASTDeclWriter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
|
2016-02-08 09:29:13 +00:00
|
|
|
VisitVarDecl(D);
|
2016-02-11 05:35:55 +00:00
|
|
|
Code = serialization::DECL_OMP_CAPTUREDEXPR;
|
2016-02-08 09:29:13 +00:00
|
|
|
}
|
|
|
|
|
2009-04-27 06:16:06 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2010-08-18 23:56:21 +00:00
|
|
|
// ASTWriter Implementation
|
2009-04-27 06:16:06 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2023-12-21 10:30:12 +08:00
|
|
|
namespace {
|
|
|
|
template <FunctionDecl::TemplatedKind Kind>
|
|
|
|
std::shared_ptr<llvm::BitCodeAbbrev>
|
|
|
|
getFunctionDeclAbbrev(serialization::DeclCode Code) {
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
auto Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(Code));
|
|
|
|
// RedeclarableDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(Kind));
|
|
|
|
if constexpr (Kind == FunctionDecl::TK_NonTemplate) {
|
|
|
|
|
|
|
|
} else if constexpr (Kind == FunctionDecl::TK_FunctionTemplate) {
|
|
|
|
// DescribedFunctionTemplate
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
|
|
|
|
} else if constexpr (Kind == FunctionDecl::TK_DependentNonTemplate) {
|
|
|
|
// Instantiated From Decl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
|
|
|
|
} else if constexpr (Kind == FunctionDecl::TK_MemberSpecialization) {
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedFrom
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
|
|
|
3)); // TemplateSpecializationKind
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Specialized Location
|
|
|
|
} else if constexpr (Kind ==
|
|
|
|
FunctionDecl::TK_FunctionTemplateSpecialization) {
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Template
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
|
|
|
3)); // TemplateSpecializationKind
|
|
|
|
Abv->Add(BitCodeAbbrevOp(1)); // Template Argument Size
|
|
|
|
Abv->Add(BitCodeAbbrevOp(TemplateArgument::Type)); // Template Argument Kind
|
|
|
|
Abv->Add(
|
|
|
|
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Template Argument Type
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Is Defaulted
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0));
|
|
|
|
Abv->Add(
|
|
|
|
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Canonical Decl of template
|
|
|
|
} else if constexpr (Kind == FunctionDecl::
|
|
|
|
TK_DependentFunctionTemplateSpecialization) {
|
|
|
|
// Candidates of specialization
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
|
|
|
|
} else {
|
|
|
|
llvm_unreachable("Unknown templated kind?");
|
|
|
|
}
|
|
|
|
// Decl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
2023-12-21 16:35:20 +08:00
|
|
|
8)); // Packed DeclBits: ModuleOwnershipKind,
|
|
|
|
// isUsed, isReferenced, AccessSpecifier,
|
|
|
|
// isImplicit
|
|
|
|
//
|
|
|
|
// The following bits should be 0:
|
|
|
|
// HasStandaloneLexicalDC, HasAttrs,
|
|
|
|
// TopLevelDeclInObjCContainer,
|
|
|
|
// isInvalidDecl
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
|
|
|
|
// ValueDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// DeclaratorDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerLocStart
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // HasExtInfo
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType
|
|
|
|
// FunctionDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // IDNS
|
|
|
|
Abv->Add(BitCodeAbbrevOp(
|
|
|
|
BitCodeAbbrevOp::Fixed,
|
[Serialization] Record whether the ODR is skipped (#82302)
Close https://github.com/llvm/llvm-project/issues/80570.
In
https://github.com/llvm/llvm-project/commit/a0b6747804e46665ecfd00295b60432bfe1775b6,
we skipped ODR checks for decls in GMF. Then it should be natural to
skip storing the ODR values in BMI.
Generally it should be fine as long as the writer and the reader keep
consistent.
However, the use of preamble in clangd shows the tricky part.
For,
```
// test.cpp
module;
// any one off these is enough to crash clangd
// #include <iostream>
// #include <string_view>
// #include <cmath>
// #include <system_error>
// #include <new>
// #include <bit>
// probably many more
// only ok with libc++, not the system provided libstdc++ 13.2.1
// these are ok
export module test;
```
clangd will store the headers as preamble to speedup the parsing and the
preamble reuses the serialization techniques. (Generally we'd call the
preamble as PCH. However it is not true strictly. I've tested the PCH
wouldn't be problematic.) However, the tricky part is that the preamble
is not modules. It literally serialiaze and deserialize things. So
before clangd parsing the above test module, clangd will serialize the
headers into the preamble. Note that there is no concept like GMF now.
So the ODR bits are stored. However, when clangd parse the file
actually, the decls from preamble are thought as in GMF literally, then
hte ODR bits are skipped. Then mismatch happens.
To solve the problem, this patch adds another bit for decls to record
whether or not the ODR bits are skipped.
2024-02-20 13:31:28 +08:00
|
|
|
28)); // Packed Function Bits: StorageClass, Inline, InlineSpecified,
|
2023-12-21 10:30:12 +08:00
|
|
|
// VirtualAsWritten, Pure, HasInheritedProto, HasWrittenProto,
|
|
|
|
// Deleted, Trivial, TrivialForCall, Defaulted, ExplicitlyDefaulted,
|
|
|
|
// IsIneligibleOrNotSelected, ImplicitReturnZero, Constexpr,
|
|
|
|
// UsesSEHTry, SkippedBody, MultiVersion, LateParsed,
|
[Serialization] Record whether the ODR is skipped (#82302)
Close https://github.com/llvm/llvm-project/issues/80570.
In
https://github.com/llvm/llvm-project/commit/a0b6747804e46665ecfd00295b60432bfe1775b6,
we skipped ODR checks for decls in GMF. Then it should be natural to
skip storing the ODR values in BMI.
Generally it should be fine as long as the writer and the reader keep
consistent.
However, the use of preamble in clangd shows the tricky part.
For,
```
// test.cpp
module;
// any one off these is enough to crash clangd
// #include <iostream>
// #include <string_view>
// #include <cmath>
// #include <system_error>
// #include <new>
// #include <bit>
// probably many more
// only ok with libc++, not the system provided libstdc++ 13.2.1
// these are ok
export module test;
```
clangd will store the headers as preamble to speedup the parsing and the
preamble reuses the serialization techniques. (Generally we'd call the
preamble as PCH. However it is not true strictly. I've tested the PCH
wouldn't be problematic.) However, the tricky part is that the preamble
is not modules. It literally serialiaze and deserialize things. So
before clangd parsing the above test module, clangd will serialize the
headers into the preamble. Note that there is no concept like GMF now.
So the ODR bits are stored. However, when clangd parse the file
actually, the decls from preamble are thought as in GMF literally, then
hte ODR bits are skipped. Then mismatch happens.
To solve the problem, this patch adds another bit for decls to record
whether or not the ODR bits are skipped.
2024-02-20 13:31:28 +08:00
|
|
|
// FriendConstraintRefersToEnclosingTemplate, Linkage,
|
|
|
|
// ShouldSkipCheckingODR
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // ODRHash
|
|
|
|
// This Array slurps the rest of the record. Fortunately we want to encode
|
|
|
|
// (nearly) all the remaining (variable number of) fields in the same way.
|
|
|
|
//
|
|
|
|
// This is:
|
|
|
|
// NumParams and Params[] from FunctionDecl, and
|
|
|
|
// NumOverriddenMethods, OverriddenMethods[] from CXXMethodDecl.
|
|
|
|
//
|
|
|
|
// Add an AbbrevOp for 'size then elements' and use it here.
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
|
2023-12-21 10:30:12 +08:00
|
|
|
return Abv;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <FunctionDecl::TemplatedKind Kind>
|
|
|
|
std::shared_ptr<llvm::BitCodeAbbrev> getCXXMethodAbbrev() {
|
2023-12-21 16:35:20 +08:00
|
|
|
return getFunctionDeclAbbrev<Kind>(serialization::DECL_CXX_METHOD);
|
2023-12-21 10:30:12 +08:00
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2014-07-26 06:37:51 +00:00
|
|
|
void ASTWriter::WriteDeclAbbrevs() {
|
2009-04-27 07:35:58 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2017-01-04 22:36:43 +00:00
|
|
|
std::shared_ptr<BitCodeAbbrev> Abv;
|
2011-06-03 02:27:19 +00:00
|
|
|
|
2011-06-03 23:11:16 +00:00
|
|
|
// Abbreviation for DECL_FIELD
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD));
|
2011-06-03 02:27:19 +00:00
|
|
|
// Decl
|
2023-12-07 17:01:06 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
2023-12-21 16:35:20 +08:00
|
|
|
7)); // Packed DeclBits: ModuleOwnershipKind,
|
|
|
|
// isUsed, isReferenced, AccessSpecifier,
|
|
|
|
//
|
|
|
|
// The following bits should be 0:
|
|
|
|
// isImplicit, HasStandaloneLexicalDC, HasAttrs,
|
|
|
|
// TopLevelDeclInObjCContainer,
|
|
|
|
// isInvalidDecl
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
2011-12-01 02:07:58 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
2011-06-03 23:11:16 +00:00
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
2015-02-07 03:11:11 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
|
2011-06-03 23:11:16 +00:00
|
|
|
// ValueDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// DeclaratorDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
|
2018-06-29 20:46:25 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType
|
2011-06-03 23:11:16 +00:00
|
|
|
// FieldDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
|
2023-04-05 14:28:57 -07:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // StorageKind
|
2011-06-03 23:11:16 +00:00
|
|
|
// Type Source Info
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclFieldAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 23:11:16 +00:00
|
|
|
|
|
|
|
// Abbreviation for DECL_OBJC_IVAR
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR));
|
|
|
|
// Decl
|
2023-12-07 17:01:06 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
|
|
|
12)); // Packed DeclBits: HasStandaloneLexicalDC,
|
|
|
|
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
|
|
|
|
// isReferenced, TopLevelDeclInObjCContainer,
|
|
|
|
// AccessSpecifier, ModuleOwnershipKind
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
2011-12-01 02:07:58 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
2011-06-03 02:27:19 +00:00
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
2015-02-07 03:11:11 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
|
2011-06-03 02:27:19 +00:00
|
|
|
// ValueDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
2011-06-03 23:11:16 +00:00
|
|
|
// DeclaratorDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
|
2018-06-29 20:46:25 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType
|
2011-06-03 23:11:16 +00:00
|
|
|
// FieldDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
|
2017-08-28 00:28:14 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // InitStyle
|
2011-06-03 23:11:16 +00:00
|
|
|
// ObjC Ivar
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize
|
|
|
|
// Type Source Info
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclObjCIvarAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 23:11:16 +00:00
|
|
|
|
|
|
|
// Abbreviation for DECL_ENUM
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM));
|
2011-10-26 17:53:41 +00:00
|
|
|
// Redeclarable
|
2011-12-19 15:27:36 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
|
2011-06-03 23:11:16 +00:00
|
|
|
// Decl
|
2023-12-07 17:01:06 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
2023-12-21 16:35:20 +08:00
|
|
|
7)); // Packed DeclBits: ModuleOwnershipKind,
|
|
|
|
// isUsed, isReferenced, AccessSpecifier,
|
|
|
|
//
|
|
|
|
// The following bits should be 0:
|
|
|
|
// isImplicit, HasStandaloneLexicalDC, HasAttrs,
|
|
|
|
// TopLevelDeclInObjCContainer,
|
|
|
|
// isInvalidDecl
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
2011-12-01 02:07:58 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
2011-06-03 23:11:16 +00:00
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
2015-02-07 03:11:11 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
|
2011-06-03 23:11:16 +00:00
|
|
|
// TypeDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
|
|
|
|
// TagDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
|
2023-11-03 21:59:44 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(
|
|
|
|
BitCodeAbbrevOp::Fixed,
|
2023-12-07 17:01:06 +08:00
|
|
|
9)); // Packed Tag Decl Bits: getTagKind, isCompleteDefinition,
|
|
|
|
// EmbeddedInDeclarator, IsFreeStanding,
|
|
|
|
// isCompleteDefinitionRequired, ExtInfoKind
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
|
2016-07-15 18:11:33 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
|
2011-06-03 23:11:16 +00:00
|
|
|
// EnumDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddTypeRef
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IntegerType
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getPromotionType
|
[Serialization] Record whether the ODR is skipped (#82302)
Close https://github.com/llvm/llvm-project/issues/80570.
In
https://github.com/llvm/llvm-project/commit/a0b6747804e46665ecfd00295b60432bfe1775b6,
we skipped ODR checks for decls in GMF. Then it should be natural to
skip storing the ODR values in BMI.
Generally it should be fine as long as the writer and the reader keep
consistent.
However, the use of preamble in clangd shows the tricky part.
For,
```
// test.cpp
module;
// any one off these is enough to crash clangd
// #include <iostream>
// #include <string_view>
// #include <cmath>
// #include <system_error>
// #include <new>
// #include <bit>
// probably many more
// only ok with libc++, not the system provided libstdc++ 13.2.1
// these are ok
export module test;
```
clangd will store the headers as preamble to speedup the parsing and the
preamble reuses the serialization techniques. (Generally we'd call the
preamble as PCH. However it is not true strictly. I've tested the PCH
wouldn't be problematic.) However, the tricky part is that the preamble
is not modules. It literally serialiaze and deserialize things. So
before clangd parsing the above test module, clangd will serialize the
headers into the preamble. Note that there is no concept like GMF now.
So the ODR bits are stored. However, when clangd parse the file
actually, the decls from preamble are thought as in GMF literally, then
hte ODR bits are skipped. Then mismatch happens.
To solve the problem, this patch adds another bit for decls to record
whether or not the ODR bits are skipped.
2024-02-20 13:31:28 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 20)); // Enum Decl Bits
|
2018-07-25 22:52:05 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));// ODRHash
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedMembEnum
|
|
|
|
// DC
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclEnumAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 02:27:19 +00:00
|
|
|
|
|
|
|
// Abbreviation for DECL_RECORD
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD));
|
2011-10-26 17:53:41 +00:00
|
|
|
// Redeclarable
|
2011-12-19 15:27:36 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
|
2011-06-03 02:27:19 +00:00
|
|
|
// Decl
|
2023-12-07 17:01:06 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
2023-12-21 16:35:20 +08:00
|
|
|
7)); // Packed DeclBits: ModuleOwnershipKind,
|
|
|
|
// isUsed, isReferenced, AccessSpecifier,
|
|
|
|
//
|
|
|
|
// The following bits should be 0:
|
|
|
|
// isImplicit, HasStandaloneLexicalDC, HasAttrs,
|
|
|
|
// TopLevelDeclInObjCContainer,
|
|
|
|
// isInvalidDecl
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
2011-12-01 02:07:58 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
2011-06-03 02:27:19 +00:00
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
2015-02-07 03:11:11 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
|
2011-06-03 02:27:19 +00:00
|
|
|
// TypeDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
|
|
|
|
// TagDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
|
2023-11-03 21:59:44 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(
|
|
|
|
BitCodeAbbrevOp::Fixed,
|
2023-12-07 17:01:06 +08:00
|
|
|
9)); // Packed Tag Decl Bits: getTagKind, isCompleteDefinition,
|
|
|
|
// EmbeddedInDeclarator, IsFreeStanding,
|
|
|
|
// isCompleteDefinitionRequired, ExtInfoKind
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
|
2016-07-15 18:11:33 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
|
2011-06-03 02:27:19 +00:00
|
|
|
// RecordDecl
|
2023-11-03 21:59:44 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(
|
|
|
|
BitCodeAbbrevOp::Fixed,
|
|
|
|
13)); // Packed Record Decl Bits: FlexibleArrayMember,
|
|
|
|
// AnonymousStructUnion, hasObjectMember, hasVolatileMember,
|
|
|
|
// isNonTrivialToPrimitiveDefaultInitialize,
|
|
|
|
// isNonTrivialToPrimitiveCopy, isNonTrivialToPrimitiveDestroy,
|
|
|
|
// hasNonTrivialToPrimitiveDefaultInitializeCUnion,
|
|
|
|
// hasNonTrivialToPrimitiveDestructCUnion,
|
2025-01-14 13:31:12 -05:00
|
|
|
// hasNonTrivialToPrimitiveCopyCUnion,
|
|
|
|
// hasUninitializedExplicitInitFields, isParamDestroyedInCallee,
|
2023-11-03 21:59:44 +08:00
|
|
|
// getArgPassingRestrictions
|
2022-12-01 18:39:23 -08:00
|
|
|
// ODRHash
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 26));
|
2018-03-13 18:58:25 +00:00
|
|
|
|
2011-06-03 02:27:19 +00:00
|
|
|
// DC
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclRecordAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 02:27:19 +00:00
|
|
|
|
|
|
|
// Abbreviation for DECL_PARM_VAR
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
|
2011-10-26 17:53:41 +00:00
|
|
|
// Redeclarable
|
2011-12-19 15:27:36 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
|
2009-04-27 07:35:58 +00:00
|
|
|
// Decl
|
2023-12-07 17:01:06 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
2023-12-21 16:35:20 +08:00
|
|
|
8)); // Packed DeclBits: ModuleOwnershipKind, isUsed,
|
|
|
|
// isReferenced, AccessSpecifier,
|
|
|
|
// HasStandaloneLexicalDC, HasAttrs, isImplicit,
|
|
|
|
// TopLevelDeclInObjCContainer,
|
|
|
|
// isInvalidDecl,
|
2009-04-27 07:35:58 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
2011-12-01 02:07:58 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
2009-04-27 07:35:58 +00:00
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
2015-02-07 03:11:11 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
|
2009-04-27 07:35:58 +00:00
|
|
|
// ValueDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
2009-08-19 01:28:35 +00:00
|
|
|
// DeclaratorDecl
|
2011-03-08 08:55:46 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
|
2010-10-15 18:21:24 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
|
2018-06-29 20:46:25 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType
|
2009-04-27 07:35:58 +00:00
|
|
|
// VarDecl
|
2023-11-03 21:59:44 +08:00
|
|
|
Abv->Add(
|
|
|
|
BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
|
|
|
12)); // Packed Var Decl bits: SClass, TSCSpec, InitStyle,
|
|
|
|
// isARCPseudoStrong, Linkage, ModulesCodegen
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // VarKind (local enum)
|
2009-04-27 07:35:58 +00:00
|
|
|
// ParmVarDecl
|
2023-12-28 11:04:08 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ScopeIndex
|
2023-11-03 21:59:44 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(
|
|
|
|
BitCodeAbbrevOp::Fixed,
|
2023-12-28 11:04:08 +08:00
|
|
|
19)); // Packed Parm Var Decl bits: IsObjCMethodParameter, ScopeDepth,
|
|
|
|
// ObjCDeclQualifier, KNRPromoted,
|
2023-12-07 17:01:06 +08:00
|
|
|
// HasInheritedDefaultArg, HasUninstantiatedDefaultArg
|
2011-06-03 23:11:16 +00:00
|
|
|
// Type Source Info
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclParmVarAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2010-07-27 00:17:23 +00:00
|
|
|
|
2011-06-06 16:22:39 +00:00
|
|
|
// Abbreviation for DECL_TYPEDEF
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF));
|
Completely re-implement (de-)serialization of declaration
chains. The previous implementation relied heavily on the declaration
chain being stored as a (circular) linked list on disk, as it is in
memory. However, when deserializing from multiple modules, the
different chains could get mixed up, leading to broken declaration chains.
The new solution keeps track of the first and last declarations in the
chain for each module file. When we load a declaration, we search all
of the module files for redeclarations of that declaration, then
splice together all of the lists into a coherent whole (along with any
redeclarations that were actually parsed).
As a drive-by fix, (de-)serialize the redeclaration chains of
TypedefNameDecls, which had somehow gotten missed previously. Add a
test of this serialization.
This new scheme creates a redeclaration table that is fairly large in
the PCH file (on the order of 400k for Cocoa.h's 12MB PCH file). The
table is mmap'd in and searched via a binary search, but it's still
quite large. A future tweak will eliminate entries for declarations
that have no redeclarations anywhere, and should
drastically reduce the size of this table.
llvm-svn: 146841
2011-12-17 23:38:30 +00:00
|
|
|
// Redeclarable
|
2011-12-19 15:27:36 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
|
2011-06-03 23:11:16 +00:00
|
|
|
// Decl
|
2023-12-07 17:01:06 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
2023-12-21 16:35:20 +08:00
|
|
|
7)); // Packed DeclBits: ModuleOwnershipKind,
|
|
|
|
// isReferenced, isUsed, AccessSpecifier. Other
|
|
|
|
// higher bits should be 0: isImplicit,
|
|
|
|
// HasStandaloneLexicalDC, HasAttrs,
|
|
|
|
// TopLevelDeclInObjCContainer, isInvalidDecl
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
2011-12-01 02:07:58 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
2011-06-03 23:11:16 +00:00
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
2015-02-07 03:11:11 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
|
2011-06-03 23:11:16 +00:00
|
|
|
// TypeDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
|
|
|
|
// TypedefDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclTypedefAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 23:11:16 +00:00
|
|
|
|
2011-06-06 16:22:39 +00:00
|
|
|
// Abbreviation for DECL_VAR
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR));
|
2011-10-26 17:53:41 +00:00
|
|
|
// Redeclarable
|
2011-12-19 15:27:36 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
|
2011-06-03 23:11:16 +00:00
|
|
|
// Decl
|
2023-12-07 17:01:06 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
|
|
|
12)); // Packed DeclBits: HasStandaloneLexicalDC,
|
|
|
|
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
|
|
|
|
// isReferenced, TopLevelDeclInObjCContainer,
|
|
|
|
// AccessSpecifier, ModuleOwnershipKind
|
2011-06-03 23:11:16 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
2011-12-01 02:07:58 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
2011-06-03 23:11:16 +00:00
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
2015-02-07 03:11:11 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
|
2011-06-03 23:11:16 +00:00
|
|
|
// ValueDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// DeclaratorDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
|
2018-06-29 20:46:25 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType
|
2011-06-03 23:11:16 +00:00
|
|
|
// VarDecl
|
2023-11-03 21:59:44 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(
|
|
|
|
BitCodeAbbrevOp::Fixed,
|
2023-12-21 16:35:20 +08:00
|
|
|
21)); // Packed Var Decl bits: Linkage, ModulesCodegen,
|
|
|
|
// SClass, TSCSpec, InitStyle,
|
2023-11-03 21:59:44 +08:00
|
|
|
// isARCPseudoStrong, IsThisDeclarationADemotedDefinition,
|
|
|
|
// isExceptionVariable, isNRVOVariable, isCXXForRangeDecl,
|
2023-12-21 16:35:20 +08:00
|
|
|
// isInline, isInlineSpecified, isConstexpr,
|
|
|
|
// isInitCapture, isPrevDeclInSameScope,
|
|
|
|
// EscapingByref, HasDeducedType, ImplicitParamKind, isObjCForDecl
|
2023-05-30 15:05:41 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // VarKind (local enum)
|
2011-06-03 23:11:16 +00:00
|
|
|
// Type Source Info
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclVarAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 23:11:16 +00:00
|
|
|
|
2014-07-26 06:37:51 +00:00
|
|
|
// Abbreviation for DECL_CXX_METHOD
|
2023-12-21 10:30:12 +08:00
|
|
|
DeclCXXMethodAbbrev =
|
|
|
|
Stream.EmitAbbrev(getCXXMethodAbbrev<FunctionDecl::TK_NonTemplate>());
|
|
|
|
DeclTemplateCXXMethodAbbrev = Stream.EmitAbbrev(
|
|
|
|
getCXXMethodAbbrev<FunctionDecl::TK_FunctionTemplate>());
|
|
|
|
DeclDependentNonTemplateCXXMethodAbbrev = Stream.EmitAbbrev(
|
|
|
|
getCXXMethodAbbrev<FunctionDecl::TK_DependentNonTemplate>());
|
|
|
|
DeclMemberSpecializedCXXMethodAbbrev = Stream.EmitAbbrev(
|
|
|
|
getCXXMethodAbbrev<FunctionDecl::TK_MemberSpecialization>());
|
|
|
|
DeclTemplateSpecializedCXXMethodAbbrev = Stream.EmitAbbrev(
|
|
|
|
getCXXMethodAbbrev<FunctionDecl::TK_FunctionTemplateSpecialization>());
|
|
|
|
DeclDependentSpecializationCXXMethodAbbrev = Stream.EmitAbbrev(
|
|
|
|
getCXXMethodAbbrev<
|
|
|
|
FunctionDecl::TK_DependentFunctionTemplateSpecialization>());
|
|
|
|
|
|
|
|
// Abbreviation for DECL_TEMPLATE_TYPE_PARM
|
2023-12-15 10:49:57 +08:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_TEMPLATE_TYPE_PARM));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // hasTypeConstraint
|
2023-12-15 10:49:57 +08:00
|
|
|
// Decl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
2023-12-21 16:35:20 +08:00
|
|
|
7)); // Packed DeclBits: ModuleOwnershipKind,
|
|
|
|
// isReferenced, isUsed, AccessSpecifier. Other
|
|
|
|
// higher bits should be 0: isImplicit,
|
|
|
|
// HasStandaloneLexicalDC, HasAttrs,
|
|
|
|
// TopLevelDeclInObjCContainer, isInvalidDecl
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
2023-12-15 10:49:57 +08:00
|
|
|
// NamedDecl
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0));
|
|
|
|
// TypeDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
|
|
|
|
// TemplateTypeParmDecl
|
|
|
|
Abv->Add(
|
|
|
|
BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // wasDeclaredWithTypename
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // OwnsDefaultArg
|
|
|
|
DeclTemplateTypeParmAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
|
|
|
|
|
|
|
// Abbreviation for DECL_USING_SHADOW
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_USING_SHADOW));
|
|
|
|
// Redeclarable
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
|
|
|
|
// Decl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
|
|
|
12)); // Packed DeclBits: HasStandaloneLexicalDC,
|
|
|
|
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
|
|
|
|
// isReferenced, TopLevelDeclInObjCContainer,
|
|
|
|
// AccessSpecifier, ModuleOwnershipKind
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
|
|
|
|
// NamedDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0));
|
|
|
|
// UsingShadowDecl
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TargetDecl
|
2014-07-26 06:37:51 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // IDNS
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // UsingOrNextShadow
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR,
|
|
|
|
6)); // InstantiatedFromUsingShadowDecl
|
|
|
|
DeclUsingShadowAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2014-07-26 06:37:51 +00:00
|
|
|
|
2011-06-06 16:22:39 +00:00
|
|
|
// Abbreviation for EXPR_DECL_REF
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF));
|
2023-12-21 10:30:12 +08:00
|
|
|
// Stmt
|
|
|
|
// Expr
|
2023-12-21 16:35:20 +08:00
|
|
|
// PackingBits: DependenceKind, ValueKind. ObjectKind should be 0.
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7));
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
2023-12-21 10:30:12 +08:00
|
|
|
// DeclRefExpr
|
2023-12-21 16:35:20 +08:00
|
|
|
// Packing Bits: , HadMultipleCandidates, RefersToEnclosingVariableOrCapture,
|
|
|
|
// IsImmediateEscalating, NonOdrUseReason.
|
|
|
|
// GetDeclFound, HasQualifier and ExplicitTemplateArgs should be 0.
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5));
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclRefExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 02:27:19 +00:00
|
|
|
|
|
|
|
// Abbreviation for EXPR_INTEGER_LITERAL
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_INTEGER_LITERAL));
|
|
|
|
//Stmt
|
[clang][OpeMP] Model OpenMP structured-block in AST (PR40563)
Summary:
https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5.0.pdf, page 3:
```
structured block
For C/C++, an executable statement, possibly compound, with a single entry at the
top and a single exit at the bottom, or an OpenMP construct.
COMMENT: See Section 2.1 on page 38 for restrictions on structured
blocks.
```
```
2.1 Directive Format
Some executable directives include a structured block. A structured block:
• may contain infinite loops where the point of exit is never reached;
• may halt due to an IEEE exception;
• may contain calls to exit(), _Exit(), quick_exit(), abort() or functions with a
_Noreturn specifier (in C) or a noreturn attribute (in C/C++);
• may be an expression statement, iteration statement, selection statement, or try block, provided
that the corresponding compound statement obtained by enclosing it in { and } would be a
structured block; and
Restrictions
Restrictions to structured blocks are as follows:
• Entry to a structured block must not be the result of a branch.
• The point of exit cannot be a branch out of the structured block.
C / C++
• The point of entry to a structured block must not be a call to setjmp().
• longjmp() and throw() must not violate the entry/exit criteria.
```
Of particular note here is the fact that OpenMP structured blocks are as-if `noexcept`,
in the same sense as with the normal `noexcept` functions in C++.
I.e. if throw happens, and it attempts to travel out of the `noexcept` function
(here: out of the current structured-block), then the program terminates.
Now, one of course can say that since it is explicitly prohibited by the Specification,
then any and all programs that violate this Specification contain undefined behavior,
and are unspecified, and thus no one should care about them. Just don't write broken code /s
But i'm not sure this is a reasonable approach.
I have personally had oss-fuzz issues of this origin - exception thrown inside
of an OpenMP structured-block that is not caught, thus causing program termination.
This issue isn't all that hard to catch, it's not any particularly different from
diagnosing the same situation with the normal `noexcept` function.
Now, clang static analyzer does not presently model exceptions.
But clang-tidy has a simplisic [[ https://clang.llvm.org/extra/clang-tidy/checks/bugprone-exception-escape.html | bugprone-exception-escape ]] check,
and it is even refactored as a `ExceptionAnalyzer` class for reuse.
So it would be trivial to use that analyzer to check for
exceptions escaping out of OpenMP structured blocks. (D59466)
All that sounds too great to be true. Indeed, there is a caveat.
Presently, it's practically impossible to do. To check a OpenMP structured block
you need to somehow 'get' the OpenMP structured block, and you can't because
it's simply not modelled in AST. `CapturedStmt`/`CapturedDecl` is not it's representation.
Now, it is of course possible to write e.g. some AST matcher that would e.g.
match every OpenMP executable directive, and then return the whatever `Stmt` is
the structured block of said executable directive, if any.
But i said //practically//. This isn't practical for the following reasons:
1. This **will** bitrot. That matcher will need to be kept up-to-date,
and refreshed with every new OpenMP spec version.
2. Every single piece of code that would want that knowledge would need to
have such matcher. Well, okay, if it is an AST matcher, it could be shared.
But then you still have `RecursiveASTVisitor` and friends.
`2 > 1`, so now you have code duplication.
So it would be reasonable (and is fully within clang AST spirit) to not
force every single consumer to do that work, but instead store that knowledge
in the correct, and appropriate place - AST, class structure.
Now, there is another hoop we need to get through.
It isn't fully obvious //how// to model this.
The best solution would of course be to simply add a `OMPStructuredBlock` transparent
node. It would be optimal, it would give us two properties:
* Given this `OMPExecutableDirective`, what's it OpenMP structured block?
* It is trivial to check whether the `Stmt*` is a OpenMP structured block (`isa<OMPStructuredBlock>(ptr)`)
But OpenMP structured block isn't **necessarily** the first, direct child of `OMP*Directive`.
(even ignoring the clang's `CapturedStmt`/`CapturedDecl` that were inserted inbetween).
So i'm not sure whether or not we could re-create AST statements after they were already created?
There would be other costs to a new AST node: https://bugs.llvm.org/show_bug.cgi?id=40563#c12
```
1. You will need to break the representation of loops. The body should be replaced by the "structured block" entity.
2. You will need to support serialization/deserialization.
3. You will need to support template instantiation.
4. You will need to support codegen and take this new construct to account in each OpenMP directive.
```
Instead, there **is** an functionally-equivalent, alternative solution, consisting of two parts.
Part 1:
* Add a member function `isStandaloneDirective()` to the `OMPExecutableDirective` class,
that will tell whether this directive is stand-alone or not, as per the spec.
We need it because we can't just check for the existance of associated statements,
see code comment.
* Add a member function `getStructuredBlock()` to the OMPExecutableDirective` class itself,
that assert that this is not a stand-alone directive, and either return the correct loop body
if this is a loop-like directive, or the captured statement.
This way, given an `OMPExecutableDirective`, we can get it's structured block.
Also, since the knowledge is ingrained into the clang OpenMP implementation,
it will not cause any duplication, and //hopefully// won't bitrot.
Great we achieved 1 of 2 properties of `OMPStructuredBlock` approach.
Thus, there is a second part needed:
* How can we check whether a given `Stmt*` is `OMPStructuredBlock`?
Well, we can't really, in general. I can see this workaround:
```
class FunctionASTVisitor : public RecursiveASTVisitor<FunctionASTVisitor> {
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
public:
bool VisitOMPExecDir(OMPExecDir *D) {
OmpStructuredStmts.emplace_back(D.getStructuredStmt());
}
bool VisitSOMETHINGELSE(???) {
if(InOmpStructuredStmt)
HI!
}
bool TraverseStmt(Stmt *Node) {
if (!Node)
return Base::TraverseStmt(Node);
if (OmpStructuredStmts.back() == Node)
++InOmpStructuredStmt;
Base::TraverseStmt(Node);
if (OmpStructuredStmts.back() == Node) {
OmpStructuredStmts.pop_back();
--InOmpStructuredStmt;
}
return true;
}
std::vector<Stmt*> OmpStructuredStmts;
int InOmpStructuredStmt = 0;
};
```
But i really don't see using it in practice.
It's just too intrusive; and again, requires knowledge duplication.
.. but no. The solution lies right on the ground.
Why don't we simply store this `i'm a openmp structured block` in the bitfield of the `Stmt` itself?
This does not appear to have any impact on the memory footprint of the clang AST,
since it's just a single extra bit in the bitfield. At least the static assertions don't fail.
Thus, indeed, we can achieve both of the properties without a new AST node.
We can cheaply set that bit right in sema, at the end of `Sema::ActOnOpenMPExecutableDirective()`,
by just calling the `getStructuredBlock()` that we just added.
Test coverage that demonstrates all this has been added.
This isn't as great with serialization though. Most of it does not use abbrevs,
so we do end up paying the full price (4 bytes?) instead of a single bit.
That price, of course, can be reclaimed by using abbrevs.
In fact, i suspect that //might// not just reclaim these bytes, but pack these PCH significantly.
I'm not seeing a third solution. If there is one, it would be interesting to hear about it.
("just don't write code that would require `isa<OMPStructuredBlock>(ptr)`" is not a solution.)
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=40563 | PR40563 ]].
Reviewers: ABataev, rjmccall, hfinkel, rsmith, riccibruno, gribozavr
Reviewed By: ABataev, gribozavr
Subscribers: mgorny, aaron.ballman, steveire, guansong, jfb, jdoerfert, cfe-commits
Tags: #clang, #openmp
Differential Revision: https://reviews.llvm.org/D59214
llvm-svn: 356570
2019-03-20 16:32:36 +00:00
|
|
|
// Expr
|
2023-12-07 17:01:06 +08:00
|
|
|
// DependenceKind, ValueKind, ObjectKind
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// Integer Literal
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
|
|
|
|
Abv->Add(BitCodeAbbrevOp(32)); // Bit Width
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Value
|
2017-01-04 22:36:43 +00:00
|
|
|
IntegerLiteralAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 02:27:19 +00:00
|
|
|
|
|
|
|
// Abbreviation for EXPR_CHARACTER_LITERAL
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CHARACTER_LITERAL));
|
|
|
|
//Stmt
|
[clang][OpeMP] Model OpenMP structured-block in AST (PR40563)
Summary:
https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5.0.pdf, page 3:
```
structured block
For C/C++, an executable statement, possibly compound, with a single entry at the
top and a single exit at the bottom, or an OpenMP construct.
COMMENT: See Section 2.1 on page 38 for restrictions on structured
blocks.
```
```
2.1 Directive Format
Some executable directives include a structured block. A structured block:
• may contain infinite loops where the point of exit is never reached;
• may halt due to an IEEE exception;
• may contain calls to exit(), _Exit(), quick_exit(), abort() or functions with a
_Noreturn specifier (in C) or a noreturn attribute (in C/C++);
• may be an expression statement, iteration statement, selection statement, or try block, provided
that the corresponding compound statement obtained by enclosing it in { and } would be a
structured block; and
Restrictions
Restrictions to structured blocks are as follows:
• Entry to a structured block must not be the result of a branch.
• The point of exit cannot be a branch out of the structured block.
C / C++
• The point of entry to a structured block must not be a call to setjmp().
• longjmp() and throw() must not violate the entry/exit criteria.
```
Of particular note here is the fact that OpenMP structured blocks are as-if `noexcept`,
in the same sense as with the normal `noexcept` functions in C++.
I.e. if throw happens, and it attempts to travel out of the `noexcept` function
(here: out of the current structured-block), then the program terminates.
Now, one of course can say that since it is explicitly prohibited by the Specification,
then any and all programs that violate this Specification contain undefined behavior,
and are unspecified, and thus no one should care about them. Just don't write broken code /s
But i'm not sure this is a reasonable approach.
I have personally had oss-fuzz issues of this origin - exception thrown inside
of an OpenMP structured-block that is not caught, thus causing program termination.
This issue isn't all that hard to catch, it's not any particularly different from
diagnosing the same situation with the normal `noexcept` function.
Now, clang static analyzer does not presently model exceptions.
But clang-tidy has a simplisic [[ https://clang.llvm.org/extra/clang-tidy/checks/bugprone-exception-escape.html | bugprone-exception-escape ]] check,
and it is even refactored as a `ExceptionAnalyzer` class for reuse.
So it would be trivial to use that analyzer to check for
exceptions escaping out of OpenMP structured blocks. (D59466)
All that sounds too great to be true. Indeed, there is a caveat.
Presently, it's practically impossible to do. To check a OpenMP structured block
you need to somehow 'get' the OpenMP structured block, and you can't because
it's simply not modelled in AST. `CapturedStmt`/`CapturedDecl` is not it's representation.
Now, it is of course possible to write e.g. some AST matcher that would e.g.
match every OpenMP executable directive, and then return the whatever `Stmt` is
the structured block of said executable directive, if any.
But i said //practically//. This isn't practical for the following reasons:
1. This **will** bitrot. That matcher will need to be kept up-to-date,
and refreshed with every new OpenMP spec version.
2. Every single piece of code that would want that knowledge would need to
have such matcher. Well, okay, if it is an AST matcher, it could be shared.
But then you still have `RecursiveASTVisitor` and friends.
`2 > 1`, so now you have code duplication.
So it would be reasonable (and is fully within clang AST spirit) to not
force every single consumer to do that work, but instead store that knowledge
in the correct, and appropriate place - AST, class structure.
Now, there is another hoop we need to get through.
It isn't fully obvious //how// to model this.
The best solution would of course be to simply add a `OMPStructuredBlock` transparent
node. It would be optimal, it would give us two properties:
* Given this `OMPExecutableDirective`, what's it OpenMP structured block?
* It is trivial to check whether the `Stmt*` is a OpenMP structured block (`isa<OMPStructuredBlock>(ptr)`)
But OpenMP structured block isn't **necessarily** the first, direct child of `OMP*Directive`.
(even ignoring the clang's `CapturedStmt`/`CapturedDecl` that were inserted inbetween).
So i'm not sure whether or not we could re-create AST statements after they were already created?
There would be other costs to a new AST node: https://bugs.llvm.org/show_bug.cgi?id=40563#c12
```
1. You will need to break the representation of loops. The body should be replaced by the "structured block" entity.
2. You will need to support serialization/deserialization.
3. You will need to support template instantiation.
4. You will need to support codegen and take this new construct to account in each OpenMP directive.
```
Instead, there **is** an functionally-equivalent, alternative solution, consisting of two parts.
Part 1:
* Add a member function `isStandaloneDirective()` to the `OMPExecutableDirective` class,
that will tell whether this directive is stand-alone or not, as per the spec.
We need it because we can't just check for the existance of associated statements,
see code comment.
* Add a member function `getStructuredBlock()` to the OMPExecutableDirective` class itself,
that assert that this is not a stand-alone directive, and either return the correct loop body
if this is a loop-like directive, or the captured statement.
This way, given an `OMPExecutableDirective`, we can get it's structured block.
Also, since the knowledge is ingrained into the clang OpenMP implementation,
it will not cause any duplication, and //hopefully// won't bitrot.
Great we achieved 1 of 2 properties of `OMPStructuredBlock` approach.
Thus, there is a second part needed:
* How can we check whether a given `Stmt*` is `OMPStructuredBlock`?
Well, we can't really, in general. I can see this workaround:
```
class FunctionASTVisitor : public RecursiveASTVisitor<FunctionASTVisitor> {
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
public:
bool VisitOMPExecDir(OMPExecDir *D) {
OmpStructuredStmts.emplace_back(D.getStructuredStmt());
}
bool VisitSOMETHINGELSE(???) {
if(InOmpStructuredStmt)
HI!
}
bool TraverseStmt(Stmt *Node) {
if (!Node)
return Base::TraverseStmt(Node);
if (OmpStructuredStmts.back() == Node)
++InOmpStructuredStmt;
Base::TraverseStmt(Node);
if (OmpStructuredStmts.back() == Node) {
OmpStructuredStmts.pop_back();
--InOmpStructuredStmt;
}
return true;
}
std::vector<Stmt*> OmpStructuredStmts;
int InOmpStructuredStmt = 0;
};
```
But i really don't see using it in practice.
It's just too intrusive; and again, requires knowledge duplication.
.. but no. The solution lies right on the ground.
Why don't we simply store this `i'm a openmp structured block` in the bitfield of the `Stmt` itself?
This does not appear to have any impact on the memory footprint of the clang AST,
since it's just a single extra bit in the bitfield. At least the static assertions don't fail.
Thus, indeed, we can achieve both of the properties without a new AST node.
We can cheaply set that bit right in sema, at the end of `Sema::ActOnOpenMPExecutableDirective()`,
by just calling the `getStructuredBlock()` that we just added.
Test coverage that demonstrates all this has been added.
This isn't as great with serialization though. Most of it does not use abbrevs,
so we do end up paying the full price (4 bytes?) instead of a single bit.
That price, of course, can be reclaimed by using abbrevs.
In fact, i suspect that //might// not just reclaim these bytes, but pack these PCH significantly.
I'm not seeing a third solution. If there is one, it would be interesting to hear about it.
("just don't write code that would require `isa<OMPStructuredBlock>(ptr)`" is not a solution.)
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=40563 | PR40563 ]].
Reviewers: ABataev, rjmccall, hfinkel, rsmith, riccibruno, gribozavr
Reviewed By: ABataev, gribozavr
Subscribers: mgorny, aaron.ballman, steveire, guansong, jfb, jdoerfert, cfe-commits
Tags: #clang, #openmp
Differential Revision: https://reviews.llvm.org/D59214
llvm-svn: 356570
2019-03-20 16:32:36 +00:00
|
|
|
// Expr
|
2023-12-07 17:01:06 +08:00
|
|
|
// DependenceKind, ValueKind, ObjectKind
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// Character Literal
|
2011-06-03 02:27:19 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
|
2016-01-07 20:59:26 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // getKind
|
2017-01-04 22:36:43 +00:00
|
|
|
CharacterLiteralAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2011-06-03 02:27:19 +00:00
|
|
|
|
2014-07-27 04:19:32 +00:00
|
|
|
// Abbreviation for EXPR_IMPLICIT_CAST
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2014-07-27 04:19:32 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_IMPLICIT_CAST));
|
|
|
|
// Stmt
|
|
|
|
// Expr
|
2023-12-21 10:30:12 +08:00
|
|
|
// Packing Bits: DependenceKind, ValueKind, ObjectKind,
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
|
2014-07-27 04:19:32 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// CastExpr
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // PathSize
|
2023-12-21 16:35:20 +08:00
|
|
|
// Packing Bits: CastKind, StoredFPFeatures, isPartOfExplicitCast
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 9));
|
2014-07-27 04:19:32 +00:00
|
|
|
// ImplicitCastExpr
|
2017-01-04 22:36:43 +00:00
|
|
|
ExprImplicitCastAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2014-07-27 04:19:32 +00:00
|
|
|
|
2023-12-21 10:30:12 +08:00
|
|
|
// Abbreviation for EXPR_BINARY_OPERATOR
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_BINARY_OPERATOR));
|
|
|
|
// Stmt
|
|
|
|
// Expr
|
2023-12-21 16:35:20 +08:00
|
|
|
// Packing Bits: DependenceKind. ValueKind and ObjectKind should
|
|
|
|
// be 0 in this case.
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5));
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// BinaryOperator
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(
|
|
|
|
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpCode and HasFPFeatures
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
BinaryOperatorAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
|
|
|
|
|
|
|
// Abbreviation for EXPR_COMPOUND_ASSIGN_OPERATOR
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_COMPOUND_ASSIGN_OPERATOR));
|
|
|
|
// Stmt
|
|
|
|
// Expr
|
2023-12-21 16:35:20 +08:00
|
|
|
// Packing Bits: DependenceKind. ValueKind and ObjectKind should
|
|
|
|
// be 0 in this case.
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5));
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// BinaryOperator
|
2023-12-21 16:35:20 +08:00
|
|
|
// Packing Bits: OpCode. The HasFPFeatures bit should be 0
|
|
|
|
Abv->Add(
|
|
|
|
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpCode and HasFPFeatures
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
// CompoundAssignOperator
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHSType
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Result Type
|
|
|
|
CompoundAssignOperatorAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
|
|
|
|
|
|
|
// Abbreviation for EXPR_CALL
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CALL));
|
|
|
|
// Stmt
|
|
|
|
// Expr
|
|
|
|
// Packing Bits: DependenceKind, ValueKind, ObjectKind,
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// CallExpr
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // NumArgs
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // ADLCallKind
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
CallExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
|
|
|
|
|
|
|
// Abbreviation for EXPR_CXX_OPERATOR_CALL
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CXX_OPERATOR_CALL));
|
|
|
|
// Stmt
|
|
|
|
// Expr
|
|
|
|
// Packing Bits: DependenceKind, ValueKind, ObjectKind,
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// CallExpr
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // NumArgs
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // ADLCallKind
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
// CXXOperatorCallExpr
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Operator Kind
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
CXXOperatorCallExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
|
|
|
|
|
|
|
// Abbreviation for EXPR_CXX_MEMBER_CALL
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CXX_MEMBER_CALL));
|
|
|
|
// Stmt
|
|
|
|
// Expr
|
|
|
|
// Packing Bits: DependenceKind, ValueKind, ObjectKind,
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
|
|
|
|
// CallExpr
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // NumArgs
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // ADLCallKind
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
// CXXMemberCallExpr
|
|
|
|
CXXMemberCallExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
|
|
|
|
|
|
|
// Abbreviation for STMT_COMPOUND
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::STMT_COMPOUND));
|
|
|
|
// Stmt
|
|
|
|
// CompoundStmt
|
2023-12-21 16:35:20 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Num Stmts
|
|
|
|
Abv->Add(BitCodeAbbrevOp(0)); // hasStoredFPFeatures
|
2023-12-21 10:30:12 +08:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
|
|
|
|
CompoundStmtAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
|
|
|
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2010-08-18 23:57:32 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL));
|
2010-07-27 00:17:23 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclContextLexicalAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2010-08-20 16:04:35 +00:00
|
|
|
|
2017-01-04 22:36:43 +00:00
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
2010-08-20 16:04:35 +00:00
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
2017-01-04 22:36:43 +00:00
|
|
|
DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2024-12-11 09:40:47 +08:00
|
|
|
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_SPECIALIZATIONS));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
DeclSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
|
|
|
|
|
|
|
Abv = std::make_shared<BitCodeAbbrev>();
|
|
|
|
Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARTIAL_SPECIALIZATIONS));
|
|
|
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
|
|
|
DeclPartialSpecializationsAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
2009-04-27 07:35:58 +00:00
|
|
|
}
|
|
|
|
|
2009-09-17 03:06:51 +00:00
|
|
|
/// isRequiredDecl - Check if this is a "required" Decl, which must be seen by
|
|
|
|
/// consumers of the AST.
|
|
|
|
///
|
2010-08-18 23:56:27 +00:00
|
|
|
/// Such decls will always be deserialized from the AST file, so we would like
|
2009-09-17 03:06:51 +00:00
|
|
|
/// this to be as restrictive as possible. Currently the predicate is driven by
|
|
|
|
/// code generation requirements, if other clients have a different notion of
|
|
|
|
/// what is "required" then we may have to consider an alternate scheme where
|
|
|
|
/// clients can iterate over the top-level decls and get information on them,
|
|
|
|
/// without necessary deserializing them. We could explicitly require such
|
|
|
|
/// clients to use a separate API call to "realize" the decl. This should be
|
|
|
|
/// relatively painless since they would presumably only do it for top-level
|
|
|
|
/// decls.
|
2015-08-19 02:30:28 +00:00
|
|
|
static bool isRequiredDecl(const Decl *D, ASTContext &Context,
|
2023-04-06 11:01:58 +08:00
|
|
|
Module *WritingModule) {
|
|
|
|
// Named modules have different semantics than header modules. Every named
|
|
|
|
// module units owns a translation unit. So the importer of named modules
|
|
|
|
// doesn't need to deserilize everything ahead of time.
|
2023-11-09 17:15:55 +08:00
|
|
|
if (WritingModule && WritingModule->isNamedModule()) {
|
2023-04-06 11:01:58 +08:00
|
|
|
// The PragmaCommentDecl and PragmaDetectMismatchDecl are MSVC's extension.
|
|
|
|
// And the behavior of MSVC for such cases will leak this to the module
|
|
|
|
// users. Given pragma is not a standard thing, the compiler has the space
|
|
|
|
// to do their own decision. Let's follow MSVC here.
|
|
|
|
if (isa<PragmaCommentDecl, PragmaDetectMismatchDecl>(D))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-09-13 21:35:00 +00:00
|
|
|
// An ObjCMethodDecl is never considered as "required" because its
|
|
|
|
// implementation container always is.
|
|
|
|
|
2016-04-06 11:38:59 +00:00
|
|
|
// File scoped assembly or obj-c or OMP declare target implementation must be
|
|
|
|
// seen.
|
2022-06-08 09:59:40 +00:00
|
|
|
if (isa<FileScopeAsmDecl, TopLevelStmtDecl, ObjCImplDecl>(D))
|
2015-08-19 02:30:28 +00:00
|
|
|
return true;
|
|
|
|
|
2019-02-05 23:37:13 +00:00
|
|
|
if (WritingModule && isPartOfPerModuleInitializer(D)) {
|
2016-07-20 19:10:16 +00:00
|
|
|
// These declarations are part of the module initializer, and are emitted
|
|
|
|
// if and when the module is imported, rather than being emitted eagerly.
|
|
|
|
return false;
|
|
|
|
}
|
2009-09-17 03:06:51 +00:00
|
|
|
|
2017-04-11 20:46:34 +00:00
|
|
|
return Context.DeclMustBeEmitted(D);
|
2009-09-17 03:06:51 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 23:56:21 +00:00
|
|
|
void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
|
2018-03-23 00:07:18 +00:00
|
|
|
PrettyDeclStackTraceEntry CrashInfo(Context, D, SourceLocation(),
|
|
|
|
"serializing");
|
|
|
|
|
2012-03-22 16:08:04 +00:00
|
|
|
// Determine the ID for this declaration.
|
2024-04-25 11:43:13 +08:00
|
|
|
LocalDeclID ID;
|
2015-11-03 01:20:54 +00:00
|
|
|
assert(!D->isFromASTFile() && "should not be emitting imported decl");
|
2024-04-25 11:43:13 +08:00
|
|
|
LocalDeclID &IDR = DeclIDs[D];
|
|
|
|
if (IDR.isInvalid())
|
2015-11-03 01:20:54 +00:00
|
|
|
IDR = NextDeclID++;
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2015-11-03 01:20:54 +00:00
|
|
|
ID = IDR;
|
2012-03-22 16:08:04 +00:00
|
|
|
|
2016-03-27 05:52:25 +00:00
|
|
|
assert(ID >= FirstDeclID && "invalid decl ID");
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
RecordData Record;
|
2024-03-08 10:12:51 +08:00
|
|
|
ASTDeclWriter W(*this, Context, Record, GeneratingReducedBMI);
|
2016-04-01 22:52:03 +00:00
|
|
|
|
2015-08-22 20:13:39 +00:00
|
|
|
// Build a record for this declaration
|
|
|
|
W.Visit(D);
|
|
|
|
|
2016-04-01 22:52:03 +00:00
|
|
|
// Emit this declaration to the bitstream.
|
|
|
|
uint64_t Offset = W.Emit(D);
|
2015-08-22 20:13:39 +00:00
|
|
|
|
2016-03-27 05:52:25 +00:00
|
|
|
// Record the offset for this declaration
|
|
|
|
SourceLocation Loc = D->getLocation();
|
Reland "[Modules] No transitive source location change (#86912)"
This relands 6c31104.
The patch was reverted due to incorrectly introduced alignment. And the
patch was re-commited after fixing the alignment issue.
Following off are the original message:
This is part of "no transitive change" patch series, "no transitive
source location change". I talked this with @Bigcheese in the tokyo's
WG21 meeting.
The idea comes from @jyknight posted on LLVM discourse. That for:
```
// A.cppm
export module A;
...
// B.cppm
export module B;
import A;
...
//--- C.cppm
export module C;
import C;
```
Almost every time A.cppm changes, we need to recompile `B`. Due to we
think the source location is significant to the semantics. But it may be
good if we can avoid recompiling `C` if the change from `A` wouldn't
change the BMI of B.
This patch only cares source locations. So let's focus on source
location's example. We can see the full example from the attached test.
```
//--- A.cppm
export module A;
export template <class T>
struct C {
T func() {
return T(43);
}
};
export int funcA() {
return 43;
}
//--- A.v1.cppm
export module A;
export template <class T>
struct C {
T func() {
return T(43);
}
};
export int funcA() {
return 43;
}
//--- B.cppm
export module B;
import A;
export int funcB() {
return funcA();
}
//--- C.cppm
export module C;
import A;
export void testD() {
C<int> c;
c.func();
}
```
Here the only difference between `A.cppm` and `A.v1.cppm` is that
`A.v1.cppm` has an additional blank line. Then the test shows that two
BMI of `B.cppm`, one specified `-fmodule-file=A=A.pcm` and the other
specified `-fmodule-file=A=A.v1.pcm`, should have the bit-wise same
contents.
However, it is a different story for C, since C instantiates templates
from A, and the instantiation records the source information from module
A, which is different from `A` and `A.v1`, so it is expected that the
BMI `C.pcm` and `C.v1.pcm` can and should differ.
To fully understand the patch, we need to understand how we encodes
source locations and how we serialize and deserialize them.
For source locations, we encoded them as:
```
|
|
| _____ base offset of an imported module
|
|
|
|_____ base offset of another imported module
|
|
|
|
| ___ 0
```
As the diagram shows, we encode the local (unloaded) source location
from 0 to higher bits. And we allocate the space for source locations
from the loaded modules from high bits to 0. Then the source locations
from the loaded modules will be mapped to our source location space
according to the allocated offset.
For example, for,
```
// a.cppm
export module a;
...
// b.cppm
export module b;
import a;
...
```
Assuming the offset of a source location (let's name the location as
`S`) in a.cppm is 45 and we will record the value `45` into the BMI
`a.pcm`. Then in b.cppm, when we import a, the source manager will
allocate a space for module 'a' (according to the recorded number of
source locations) as the base offset of module 'a' in the current source
location spaces. Let's assume the allocated base offset as 90 in this
example. Then when we want to get the location in the current source
location space for `S`, we can get it simply by adding `45` to `90` to
`135`. Finally we can get the source location for `S` in module B as
`135`.
And when we want to write module `b`, we would also write the source
location of `S` as `135` directly in the BMI. And to clarify the
location `S` comes from module `a`, we also need to record the base
offset of module `a`, 90 in the BMI of `b`.
Then the problem comes. Since the base offset of module 'a' is computed
by the number source locations in module 'a'. In module 'b', the
recorded base offset of module 'a' will change every time the number of
source locations in module 'a' increase or decrease. In other words, the
contents of BMI of B will change every time the number of locations in
module 'a' changes. This is pretty sensitive. Almost every change will
change the number of locations. So this is the problem this patch want
to solve.
Let's continue with the existing design to understand what's going on.
Another interesting case is:
```
// c.cppm
export module c;
import whatever;
import a;
import b;
...
```
In `c.cppm`, when we import `a`, we still need to allocate a base
location offset for it, let's say the value becomes to `200` somehow.
Then when we reach the location `S` recorded in module `b`, we need to
translate it into the current source location space. The solution is
quite simple, we can get it by `135 + (200 - 90) = 245`. In another
word, the offset of a source location in current module can be computed
as `Recorded Offset + Base Offset of the its module file - Recorded Base
Offset`.
Then we're almost done about how we handle the offset of source
locations in serializers.
From the abstract level, what we want to do is to remove the hardcoded
base offset of imported modules and remain the ability to calculate the
source location in a new module unit. To achieve this, we need to be
able to find the module file owning a source location from the encoding
of the source location.
So in this patch, for each source location, we will store the local
offset of the location and the module file index. For the above example,
in `b.pcm`, the source location of `S` will be recorded as `135`
directly. And in the new design, the source location of `S` will be
recorded as `<1, 45>`. Here `1` stands for the module file index of `a`
in module `b`. And `45` means the offset of `S` to the base offset of
module `a`.
So the trade-off here is that, to make the BMI more independent, we need
to record more abstract information. And I feel it is worthy. The
recompilation problem of modules is really annoying and there are still
people complaining this. But if we can make this (including stopping
other changes transitively), I think this may be a killer feature for
modules. And from @Bigcheese , this should be helpful for clang explicit
modules too.
And the benchmarking side, I tested this patch against
https://github.com/alibaba/async_simple/tree/CXX20Modules. No
significant change on compilation time. The size of .pcm files becomes
to 204M from 200M. I think the trade-off is pretty fair.
I didn't use another slot to record the module file index. I tried to
use the higher 32 bits of the existing source location encodings to
store that information. This design may be safe. Since we use `unsigned`
to store source locations but we use uint64_t in serialization. And
generally `unsigned` is 32 bit width in most platforms. So it might not
be a safe problem. Since all the bits we used to store the module file
index is not used before. So the new encodings may be:
```
|-----------------------|-----------------------|
| A | B | C |
* A: 32 bit. The index of the module file in the module manager + 1.
* The +1
here is necessary since we wish 0 stands for the current
module file.
* B: 31 bit. The offset of the source location to the module file
* containing it.
* C: The macro bit. We rotate it to the lowest bit so that we can save
* some
space in case the index of the module file is 0.
```
(The B and C is the existing raw encoding for source locations)
Another reason to reuse the same slot of the source location is to
reduce the impact of the patch. Since there are a lot of places assuming
we can store and get a source location from a slot. And if I tried to
add another slot, a lot of codes breaks. I don't feel it is worhty.
Another impact of this decision is that, the existing small
optimizations for encoding source location may be invalided. The key of
the optimization is that we can turn large values into small values then
we can use VBR6 format to reduce the size. But if we decided to put the
module file index into the higher bits, then maybe it simply doesn't
work. An example may be the `SourceLocationSequence` optimization.
This will only affect the size of on-disk .pcm files. I don't expect
this impact the speed and memory use of compilations. And seeing my
small experiments above, I feel this trade off is worthy.
The mental model for handling source location offsets is not so complex
and I believe we can solve it by adding module file index to each stored
source location.
For the practical side, since the source location is pretty sensitive,
and the patch can pass all the in-tree tests and a small scale projects,
I feel it should be correct.
I'll continue to work on no transitive decl change and no transitive
identifier change (if matters) to achieve the goal to stop the
propagation of unnecessary changes. But all of this depends on this
patch. Since, clearly, the source locations are the most sensitive
thing.
---
The release nots and documentation will be added seperately.
2024-05-06 10:41:42 +08:00
|
|
|
SourceLocationEncoding::RawLocEncoding RawLoc =
|
|
|
|
getRawSourceLocationEncoding(getAdjustedLocation(Loc));
|
|
|
|
|
2024-06-19 10:48:55 +08:00
|
|
|
unsigned Index = ID.getRawValue() - FirstDeclID.getRawValue();
|
2016-03-27 05:52:25 +00:00
|
|
|
if (DeclOffsets.size() == Index)
|
Reland "[Modules] No transitive source location change (#86912)"
This relands 6c31104.
The patch was reverted due to incorrectly introduced alignment. And the
patch was re-commited after fixing the alignment issue.
Following off are the original message:
This is part of "no transitive change" patch series, "no transitive
source location change". I talked this with @Bigcheese in the tokyo's
WG21 meeting.
The idea comes from @jyknight posted on LLVM discourse. That for:
```
// A.cppm
export module A;
...
// B.cppm
export module B;
import A;
...
//--- C.cppm
export module C;
import C;
```
Almost every time A.cppm changes, we need to recompile `B`. Due to we
think the source location is significant to the semantics. But it may be
good if we can avoid recompiling `C` if the change from `A` wouldn't
change the BMI of B.
This patch only cares source locations. So let's focus on source
location's example. We can see the full example from the attached test.
```
//--- A.cppm
export module A;
export template <class T>
struct C {
T func() {
return T(43);
}
};
export int funcA() {
return 43;
}
//--- A.v1.cppm
export module A;
export template <class T>
struct C {
T func() {
return T(43);
}
};
export int funcA() {
return 43;
}
//--- B.cppm
export module B;
import A;
export int funcB() {
return funcA();
}
//--- C.cppm
export module C;
import A;
export void testD() {
C<int> c;
c.func();
}
```
Here the only difference between `A.cppm` and `A.v1.cppm` is that
`A.v1.cppm` has an additional blank line. Then the test shows that two
BMI of `B.cppm`, one specified `-fmodule-file=A=A.pcm` and the other
specified `-fmodule-file=A=A.v1.pcm`, should have the bit-wise same
contents.
However, it is a different story for C, since C instantiates templates
from A, and the instantiation records the source information from module
A, which is different from `A` and `A.v1`, so it is expected that the
BMI `C.pcm` and `C.v1.pcm` can and should differ.
To fully understand the patch, we need to understand how we encodes
source locations and how we serialize and deserialize them.
For source locations, we encoded them as:
```
|
|
| _____ base offset of an imported module
|
|
|
|_____ base offset of another imported module
|
|
|
|
| ___ 0
```
As the diagram shows, we encode the local (unloaded) source location
from 0 to higher bits. And we allocate the space for source locations
from the loaded modules from high bits to 0. Then the source locations
from the loaded modules will be mapped to our source location space
according to the allocated offset.
For example, for,
```
// a.cppm
export module a;
...
// b.cppm
export module b;
import a;
...
```
Assuming the offset of a source location (let's name the location as
`S`) in a.cppm is 45 and we will record the value `45` into the BMI
`a.pcm`. Then in b.cppm, when we import a, the source manager will
allocate a space for module 'a' (according to the recorded number of
source locations) as the base offset of module 'a' in the current source
location spaces. Let's assume the allocated base offset as 90 in this
example. Then when we want to get the location in the current source
location space for `S`, we can get it simply by adding `45` to `90` to
`135`. Finally we can get the source location for `S` in module B as
`135`.
And when we want to write module `b`, we would also write the source
location of `S` as `135` directly in the BMI. And to clarify the
location `S` comes from module `a`, we also need to record the base
offset of module `a`, 90 in the BMI of `b`.
Then the problem comes. Since the base offset of module 'a' is computed
by the number source locations in module 'a'. In module 'b', the
recorded base offset of module 'a' will change every time the number of
source locations in module 'a' increase or decrease. In other words, the
contents of BMI of B will change every time the number of locations in
module 'a' changes. This is pretty sensitive. Almost every change will
change the number of locations. So this is the problem this patch want
to solve.
Let's continue with the existing design to understand what's going on.
Another interesting case is:
```
// c.cppm
export module c;
import whatever;
import a;
import b;
...
```
In `c.cppm`, when we import `a`, we still need to allocate a base
location offset for it, let's say the value becomes to `200` somehow.
Then when we reach the location `S` recorded in module `b`, we need to
translate it into the current source location space. The solution is
quite simple, we can get it by `135 + (200 - 90) = 245`. In another
word, the offset of a source location in current module can be computed
as `Recorded Offset + Base Offset of the its module file - Recorded Base
Offset`.
Then we're almost done about how we handle the offset of source
locations in serializers.
From the abstract level, what we want to do is to remove the hardcoded
base offset of imported modules and remain the ability to calculate the
source location in a new module unit. To achieve this, we need to be
able to find the module file owning a source location from the encoding
of the source location.
So in this patch, for each source location, we will store the local
offset of the location and the module file index. For the above example,
in `b.pcm`, the source location of `S` will be recorded as `135`
directly. And in the new design, the source location of `S` will be
recorded as `<1, 45>`. Here `1` stands for the module file index of `a`
in module `b`. And `45` means the offset of `S` to the base offset of
module `a`.
So the trade-off here is that, to make the BMI more independent, we need
to record more abstract information. And I feel it is worthy. The
recompilation problem of modules is really annoying and there are still
people complaining this. But if we can make this (including stopping
other changes transitively), I think this may be a killer feature for
modules. And from @Bigcheese , this should be helpful for clang explicit
modules too.
And the benchmarking side, I tested this patch against
https://github.com/alibaba/async_simple/tree/CXX20Modules. No
significant change on compilation time. The size of .pcm files becomes
to 204M from 200M. I think the trade-off is pretty fair.
I didn't use another slot to record the module file index. I tried to
use the higher 32 bits of the existing source location encodings to
store that information. This design may be safe. Since we use `unsigned`
to store source locations but we use uint64_t in serialization. And
generally `unsigned` is 32 bit width in most platforms. So it might not
be a safe problem. Since all the bits we used to store the module file
index is not used before. So the new encodings may be:
```
|-----------------------|-----------------------|
| A | B | C |
* A: 32 bit. The index of the module file in the module manager + 1.
* The +1
here is necessary since we wish 0 stands for the current
module file.
* B: 31 bit. The offset of the source location to the module file
* containing it.
* C: The macro bit. We rotate it to the lowest bit so that we can save
* some
space in case the index of the module file is 0.
```
(The B and C is the existing raw encoding for source locations)
Another reason to reuse the same slot of the source location is to
reduce the impact of the patch. Since there are a lot of places assuming
we can store and get a source location from a slot. And if I tried to
add another slot, a lot of codes breaks. I don't feel it is worhty.
Another impact of this decision is that, the existing small
optimizations for encoding source location may be invalided. The key of
the optimization is that we can turn large values into small values then
we can use VBR6 format to reduce the size. But if we decided to put the
module file index into the higher bits, then maybe it simply doesn't
work. An example may be the `SourceLocationSequence` optimization.
This will only affect the size of on-disk .pcm files. I don't expect
this impact the speed and memory use of compilations. And seeing my
small experiments above, I feel this trade off is worthy.
The mental model for handling source location offsets is not so complex
and I believe we can solve it by adding module file index to each stored
source location.
For the practical side, since the source location is pretty sensitive,
and the patch can pass all the in-tree tests and a small scale projects,
I feel it should be correct.
I'll continue to work on no transitive decl change and no transitive
identifier change (if matters) to achieve the goal to stop the
propagation of unnecessary changes. But all of this depends on this
patch. Since, clearly, the source locations are the most sensitive
thing.
---
The release nots and documentation will be added seperately.
2024-05-06 10:41:42 +08:00
|
|
|
DeclOffsets.emplace_back(RawLoc, Offset, DeclTypesBlockStartOffset);
|
2016-03-27 05:52:25 +00:00
|
|
|
else if (DeclOffsets.size() < Index) {
|
2016-04-01 22:52:03 +00:00
|
|
|
// FIXME: Can/should this happen?
|
2016-03-27 05:52:25 +00:00
|
|
|
DeclOffsets.resize(Index+1);
|
Reland "[Modules] No transitive source location change (#86912)"
This relands 6c31104.
The patch was reverted due to incorrectly introduced alignment. And the
patch was re-commited after fixing the alignment issue.
Following off are the original message:
This is part of "no transitive change" patch series, "no transitive
source location change". I talked this with @Bigcheese in the tokyo's
WG21 meeting.
The idea comes from @jyknight posted on LLVM discourse. That for:
```
// A.cppm
export module A;
...
// B.cppm
export module B;
import A;
...
//--- C.cppm
export module C;
import C;
```
Almost every time A.cppm changes, we need to recompile `B`. Due to we
think the source location is significant to the semantics. But it may be
good if we can avoid recompiling `C` if the change from `A` wouldn't
change the BMI of B.
This patch only cares source locations. So let's focus on source
location's example. We can see the full example from the attached test.
```
//--- A.cppm
export module A;
export template <class T>
struct C {
T func() {
return T(43);
}
};
export int funcA() {
return 43;
}
//--- A.v1.cppm
export module A;
export template <class T>
struct C {
T func() {
return T(43);
}
};
export int funcA() {
return 43;
}
//--- B.cppm
export module B;
import A;
export int funcB() {
return funcA();
}
//--- C.cppm
export module C;
import A;
export void testD() {
C<int> c;
c.func();
}
```
Here the only difference between `A.cppm` and `A.v1.cppm` is that
`A.v1.cppm` has an additional blank line. Then the test shows that two
BMI of `B.cppm`, one specified `-fmodule-file=A=A.pcm` and the other
specified `-fmodule-file=A=A.v1.pcm`, should have the bit-wise same
contents.
However, it is a different story for C, since C instantiates templates
from A, and the instantiation records the source information from module
A, which is different from `A` and `A.v1`, so it is expected that the
BMI `C.pcm` and `C.v1.pcm` can and should differ.
To fully understand the patch, we need to understand how we encodes
source locations and how we serialize and deserialize them.
For source locations, we encoded them as:
```
|
|
| _____ base offset of an imported module
|
|
|
|_____ base offset of another imported module
|
|
|
|
| ___ 0
```
As the diagram shows, we encode the local (unloaded) source location
from 0 to higher bits. And we allocate the space for source locations
from the loaded modules from high bits to 0. Then the source locations
from the loaded modules will be mapped to our source location space
according to the allocated offset.
For example, for,
```
// a.cppm
export module a;
...
// b.cppm
export module b;
import a;
...
```
Assuming the offset of a source location (let's name the location as
`S`) in a.cppm is 45 and we will record the value `45` into the BMI
`a.pcm`. Then in b.cppm, when we import a, the source manager will
allocate a space for module 'a' (according to the recorded number of
source locations) as the base offset of module 'a' in the current source
location spaces. Let's assume the allocated base offset as 90 in this
example. Then when we want to get the location in the current source
location space for `S`, we can get it simply by adding `45` to `90` to
`135`. Finally we can get the source location for `S` in module B as
`135`.
And when we want to write module `b`, we would also write the source
location of `S` as `135` directly in the BMI. And to clarify the
location `S` comes from module `a`, we also need to record the base
offset of module `a`, 90 in the BMI of `b`.
Then the problem comes. Since the base offset of module 'a' is computed
by the number source locations in module 'a'. In module 'b', the
recorded base offset of module 'a' will change every time the number of
source locations in module 'a' increase or decrease. In other words, the
contents of BMI of B will change every time the number of locations in
module 'a' changes. This is pretty sensitive. Almost every change will
change the number of locations. So this is the problem this patch want
to solve.
Let's continue with the existing design to understand what's going on.
Another interesting case is:
```
// c.cppm
export module c;
import whatever;
import a;
import b;
...
```
In `c.cppm`, when we import `a`, we still need to allocate a base
location offset for it, let's say the value becomes to `200` somehow.
Then when we reach the location `S` recorded in module `b`, we need to
translate it into the current source location space. The solution is
quite simple, we can get it by `135 + (200 - 90) = 245`. In another
word, the offset of a source location in current module can be computed
as `Recorded Offset + Base Offset of the its module file - Recorded Base
Offset`.
Then we're almost done about how we handle the offset of source
locations in serializers.
From the abstract level, what we want to do is to remove the hardcoded
base offset of imported modules and remain the ability to calculate the
source location in a new module unit. To achieve this, we need to be
able to find the module file owning a source location from the encoding
of the source location.
So in this patch, for each source location, we will store the local
offset of the location and the module file index. For the above example,
in `b.pcm`, the source location of `S` will be recorded as `135`
directly. And in the new design, the source location of `S` will be
recorded as `<1, 45>`. Here `1` stands for the module file index of `a`
in module `b`. And `45` means the offset of `S` to the base offset of
module `a`.
So the trade-off here is that, to make the BMI more independent, we need
to record more abstract information. And I feel it is worthy. The
recompilation problem of modules is really annoying and there are still
people complaining this. But if we can make this (including stopping
other changes transitively), I think this may be a killer feature for
modules. And from @Bigcheese , this should be helpful for clang explicit
modules too.
And the benchmarking side, I tested this patch against
https://github.com/alibaba/async_simple/tree/CXX20Modules. No
significant change on compilation time. The size of .pcm files becomes
to 204M from 200M. I think the trade-off is pretty fair.
I didn't use another slot to record the module file index. I tried to
use the higher 32 bits of the existing source location encodings to
store that information. This design may be safe. Since we use `unsigned`
to store source locations but we use uint64_t in serialization. And
generally `unsigned` is 32 bit width in most platforms. So it might not
be a safe problem. Since all the bits we used to store the module file
index is not used before. So the new encodings may be:
```
|-----------------------|-----------------------|
| A | B | C |
* A: 32 bit. The index of the module file in the module manager + 1.
* The +1
here is necessary since we wish 0 stands for the current
module file.
* B: 31 bit. The offset of the source location to the module file
* containing it.
* C: The macro bit. We rotate it to the lowest bit so that we can save
* some
space in case the index of the module file is 0.
```
(The B and C is the existing raw encoding for source locations)
Another reason to reuse the same slot of the source location is to
reduce the impact of the patch. Since there are a lot of places assuming
we can store and get a source location from a slot. And if I tried to
add another slot, a lot of codes breaks. I don't feel it is worhty.
Another impact of this decision is that, the existing small
optimizations for encoding source location may be invalided. The key of
the optimization is that we can turn large values into small values then
we can use VBR6 format to reduce the size. But if we decided to put the
module file index into the higher bits, then maybe it simply doesn't
work. An example may be the `SourceLocationSequence` optimization.
This will only affect the size of on-disk .pcm files. I don't expect
this impact the speed and memory use of compilations. And seeing my
small experiments above, I feel this trade off is worthy.
The mental model for handling source location offsets is not so complex
and I believe we can solve it by adding module file index to each stored
source location.
For the practical side, since the source location is pretty sensitive,
and the patch can pass all the in-tree tests and a small scale projects,
I feel it should be correct.
I'll continue to work on no transitive decl change and no transitive
identifier change (if matters) to achieve the goal to stop the
propagation of unnecessary changes. But all of this depends on this
patch. Since, clearly, the source locations are the most sensitive
thing.
---
The release nots and documentation will be added seperately.
2024-05-06 10:41:42 +08:00
|
|
|
DeclOffsets[Index].setRawLoc(RawLoc);
|
2020-05-13 17:07:47 +01:00
|
|
|
DeclOffsets[Index].setBitOffset(Offset, DeclTypesBlockStartOffset);
|
2016-04-01 22:52:03 +00:00
|
|
|
} else {
|
|
|
|
llvm_unreachable("declarations should be emitted in ID order");
|
2009-10-17 00:13:19 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2016-03-27 05:52:25 +00:00
|
|
|
SourceManager &SM = Context.getSourceManager();
|
|
|
|
if (Loc.isValid() && SM.isLocalSourceLocation(Loc))
|
|
|
|
associateDeclWithFile(D, ID);
|
|
|
|
|
2014-01-31 01:06:56 +00:00
|
|
|
// Note declarations that should be deserialized eagerly so that we can add
|
|
|
|
// them to a record in the AST file later.
|
2017-04-11 20:46:34 +00:00
|
|
|
if (isRequiredDecl(D, Context, WritingModule))
|
2024-04-25 11:43:13 +08:00
|
|
|
AddDeclRef(D, EagerlyDeserializedDecls);
|
2009-04-27 06:16:06 +00:00
|
|
|
}
|
2014-03-22 23:33:22 +00:00
|
|
|
|
2016-04-06 17:06:00 +00:00
|
|
|
void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
|
|
|
|
// Switch case IDs are per function body.
|
|
|
|
Writer->ClearSwitchCaseIDs();
|
2014-03-22 23:33:22 +00:00
|
|
|
|
2016-04-06 17:06:00 +00:00
|
|
|
assert(FD->doesThisDeclarationHaveABody());
|
2017-07-06 00:30:00 +00:00
|
|
|
bool ModulesCodegen = false;
|
2019-11-03 21:15:03 +01:00
|
|
|
if (!FD->isDependentContext()) {
|
2023-01-14 12:31:01 -08:00
|
|
|
std::optional<GVALinkage> Linkage;
|
2019-11-03 21:15:03 +01:00
|
|
|
if (Writer->WritingModule &&
|
2022-04-01 14:35:35 +08:00
|
|
|
Writer->WritingModule->isInterfaceOrPartition()) {
|
|
|
|
// When building a C++20 module interface unit or a partition unit, a
|
|
|
|
// strong definition in the module interface is provided by the
|
|
|
|
// compilation of that unit, not by its users. (Inline functions are still
|
|
|
|
// emitted in module users.)
|
2024-11-07 14:40:21 -08:00
|
|
|
Linkage = getASTContext().GetGVALinkageForFunction(FD);
|
2023-02-14 10:27:22 +08:00
|
|
|
ModulesCodegen = *Linkage >= GVA_StrongExternal;
|
2017-11-02 21:55:40 +00:00
|
|
|
}
|
2024-11-07 14:40:21 -08:00
|
|
|
if (Writer->getLangOpts().ModulesCodegen ||
|
Merge some of the PCH object support with modular codegen
I was trying to pick this up a bit when reviewing D48426 (& perhaps D69778) - in any case, looks like D48426 added a module level flag that might not be needed.
The D48426 implementation worked by setting a module level flag, then code generating contents from the PCH a special case in ASTContext::DeclMustBeEmitted would be used to delay emitting the definition of these functions if they came from a Module with this flag.
This strategy is similar to the one initially implemented for modular codegen that was removed in D29901 in favor of the modular decls list and a bit on each decl to specify whether it's homed to a module.
One major difference between PCH object support and modular code generation, other than the specific list of decls that are homed, is the compilation model: MSVC PCH modules are built into the object file for some other source file (when compiling that source file /Yc is specified to say "this compilation is where the PCH is homed"), whereas modular code generation invokes a separate compilation for the PCH alone. So the current modular code generation test of to decide if a decl should be emitted "is the module where this decl is serialized the current main file" has to be extended (as Lubos did in D69778) to also test the command line flag -building-pch-with-obj.
Otherwise the whole thing is basically streamlined down to the modular code generation path.
This even offers one extra material improvement compared to the existing divergent implementation: Homed functions are not emitted into object files that use the pch. Instead at -O0 they are not emitted into the IR at all, and at -O1 they are emitted using available_externally (existing functionality implemented for modular code generation). The pch-codegen test has been updated to reflect this new behavior.
[If possible: I'd love it if we could not have the extra MSVC-style way of accessing dllexport-pch-homing, and just do it the modular codegen way, but I understand that it might be a limitation of existing build systems. @hans / @thakis: Do either of you know if it'd be practical to move to something more similar to .pcm handling, where the pch itself is passed to the compilation, rather than homed as a side effect of compiling some other source file?]
Reviewers: llunak, hans
Differential Revision: https://reviews.llvm.org/D83652
2020-07-12 15:36:56 -07:00
|
|
|
(FD->hasAttr<DLLExportAttr>() &&
|
2024-11-07 14:40:21 -08:00
|
|
|
Writer->getLangOpts().BuildingPCHWithObjectFile)) {
|
Merge some of the PCH object support with modular codegen
I was trying to pick this up a bit when reviewing D48426 (& perhaps D69778) - in any case, looks like D48426 added a module level flag that might not be needed.
The D48426 implementation worked by setting a module level flag, then code generating contents from the PCH a special case in ASTContext::DeclMustBeEmitted would be used to delay emitting the definition of these functions if they came from a Module with this flag.
This strategy is similar to the one initially implemented for modular codegen that was removed in D29901 in favor of the modular decls list and a bit on each decl to specify whether it's homed to a module.
One major difference between PCH object support and modular code generation, other than the specific list of decls that are homed, is the compilation model: MSVC PCH modules are built into the object file for some other source file (when compiling that source file /Yc is specified to say "this compilation is where the PCH is homed"), whereas modular code generation invokes a separate compilation for the PCH alone. So the current modular code generation test of to decide if a decl should be emitted "is the module where this decl is serialized the current main file" has to be extended (as Lubos did in D69778) to also test the command line flag -building-pch-with-obj.
Otherwise the whole thing is basically streamlined down to the modular code generation path.
This even offers one extra material improvement compared to the existing divergent implementation: Homed functions are not emitted into object files that use the pch. Instead at -O0 they are not emitted into the IR at all, and at -O1 they are emitted using available_externally (existing functionality implemented for modular code generation). The pch-codegen test has been updated to reflect this new behavior.
[If possible: I'd love it if we could not have the extra MSVC-style way of accessing dllexport-pch-homing, and just do it the modular codegen way, but I understand that it might be a limitation of existing build systems. @hans / @thakis: Do either of you know if it'd be practical to move to something more similar to .pcm handling, where the pch itself is passed to the compilation, rather than homed as a side effect of compiling some other source file?]
Reviewers: llunak, hans
Differential Revision: https://reviews.llvm.org/D83652
2020-07-12 15:36:56 -07:00
|
|
|
|
2017-11-02 21:55:40 +00:00
|
|
|
// Under -fmodules-codegen, codegen is performed for all non-internal,
|
2019-11-03 20:47:40 +01:00
|
|
|
// non-always_inline functions, unless they are available elsewhere.
|
2017-11-02 22:28:50 +00:00
|
|
|
if (!FD->hasAttr<AlwaysInlineAttr>()) {
|
|
|
|
if (!Linkage)
|
2024-11-07 14:40:21 -08:00
|
|
|
Linkage = getASTContext().GetGVALinkageForFunction(FD);
|
2019-11-03 20:47:40 +01:00
|
|
|
ModulesCodegen =
|
|
|
|
*Linkage != GVA_Internal && *Linkage != GVA_AvailableExternally;
|
2017-11-02 22:28:50 +00:00
|
|
|
}
|
2017-11-02 21:55:40 +00:00
|
|
|
}
|
2017-07-06 00:30:00 +00:00
|
|
|
}
|
2017-04-12 20:58:33 +00:00
|
|
|
Record->push_back(ModulesCodegen);
|
|
|
|
if (ModulesCodegen)
|
2024-04-25 11:43:13 +08:00
|
|
|
Writer->AddDeclRef(FD, Writer->ModularCodegenDecls);
|
2016-04-06 17:06:00 +00:00
|
|
|
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
|
|
|
|
Record->push_back(CD->getNumCtorInitializers());
|
|
|
|
if (CD->getNumCtorInitializers())
|
2023-01-06 16:56:23 +01:00
|
|
|
AddCXXCtorInitializers(llvm::ArrayRef(CD->init_begin(), CD->init_end()));
|
2016-04-06 17:06:00 +00:00
|
|
|
}
|
|
|
|
AddStmt(FD->getBody());
|
2014-03-22 23:33:22 +00:00
|
|
|
}
|