Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the C++ related Decl classes.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/DeclCXX.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- generic lambdas within template functions and nested
within other generic lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
(Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)
As an example of what compiles through this commit:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
generate a template-parameter-type when 'auto' is parsed in a generic
lambda parameter context. (i.e we do NOT use AutoType deduced to
a template parameter type - Richard seemed ok with this approach).
We encode that this template type was generated from an auto by simply
adding $auto to the name which can be used for better diagnostics if needed.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- various tests were added - but much more will be needed.
There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.
A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 191453
2013-09-27 03:54:12 +08:00
|
|
|
#include "clang/AST/ASTLambda.h"
|
2010-10-25 01:26:36 +08:00
|
|
|
#include "clang/AST/ASTMutationListener.h"
|
2010-09-29 08:15:42 +08:00
|
|
|
#include "clang/AST/CXXInheritance.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2009-03-14 08:25:26 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2011-11-01 09:16:03 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2009-12-03 06:36:29 +08:00
|
|
|
#include "clang/AST/TypeLoc.h"
|
2008-11-13 07:21:09 +08:00
|
|
|
#include "clang/Basic/IdentifierTable.h"
|
2008-12-24 05:31:30 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2009-09-13 03:52:10 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Decl Allocation/Deallocation Method Implementations
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-12-06 02:15:24 +08:00
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void AccessSpecDecl::anchor() { }
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) AccessSpecDecl(EmptyShell());
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2013-08-30 12:46:40 +08:00
|
|
|
void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const {
|
|
|
|
ExternalASTSource *Source = C.getExternalSource();
|
|
|
|
assert(Impl.Decls.isLazy() && "getFromExternalSource for non-lazy set");
|
|
|
|
assert(Source && "getFromExternalSource with no external source");
|
|
|
|
|
|
|
|
for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I)
|
|
|
|
I.setDecl(cast<NamedDecl>(Source->GetExternalDecl(
|
|
|
|
reinterpret_cast<uintptr_t>(I.getDecl()) >> 2)));
|
|
|
|
Impl.Decls.setLazy(false);
|
|
|
|
}
|
|
|
|
|
2010-02-05 06:26:26 +08:00
|
|
|
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
2012-11-30 13:11:39 +08:00
|
|
|
: UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
|
2009-08-16 06:23:00 +08:00
|
|
|
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
2011-04-30 18:07:30 +08:00
|
|
|
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
|
2013-12-10 16:25:00 +08:00
|
|
|
HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true),
|
2012-12-08 10:01:17 +08:00
|
|
|
HasInClassInitializer(false), HasUninitializedReferenceMember(false),
|
2012-12-08 16:32:28 +08:00
|
|
|
NeedOverloadResolutionForMoveConstructor(false),
|
|
|
|
NeedOverloadResolutionForMoveAssignment(false),
|
|
|
|
NeedOverloadResolutionForDestructor(false),
|
|
|
|
DefaultedMoveConstructorIsDeleted(false),
|
|
|
|
DefaultedMoveAssignmentIsDeleted(false),
|
|
|
|
DefaultedDestructorIsDeleted(false),
|
2012-11-30 13:11:39 +08:00
|
|
|
HasTrivialSpecialMembers(SMF_All),
|
2012-12-08 10:53:02 +08:00
|
|
|
DeclaredNonTrivialSpecialMembers(0),
|
2012-11-30 13:11:39 +08:00
|
|
|
HasIrrelevantDestructor(true),
|
2011-12-22 10:22:31 +08:00
|
|
|
HasConstexprNonCopyMoveConstructor(false),
|
|
|
|
DefaultedDefaultConstructorIsConstexpr(true),
|
2012-11-30 13:11:39 +08:00
|
|
|
HasConstexprDefaultConstructor(false),
|
2011-05-10 02:22:59 +08:00
|
|
|
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
|
2012-11-30 13:11:39 +08:00
|
|
|
UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
|
2012-11-28 14:23:12 +08:00
|
|
|
ImplicitCopyConstructorHasConstParam(true),
|
|
|
|
ImplicitCopyAssignmentHasConstParam(true),
|
|
|
|
HasDeclaredCopyConstructorWithConstParam(false),
|
|
|
|
HasDeclaredCopyAssignmentWithConstParam(false),
|
|
|
|
IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
|
2013-06-26 10:41:25 +08:00
|
|
|
Definition(D), FirstFriend() {
|
2010-02-05 06:26:26 +08:00
|
|
|
}
|
|
|
|
|
2012-07-05 01:03:33 +08:00
|
|
|
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
|
|
|
|
return Bases.get(Definition->getASTContext().getExternalSource());
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getVBasesSlowCase() const {
|
|
|
|
return VBases.get(Definition->getASTContext().getExternalSource());
|
|
|
|
}
|
|
|
|
|
2010-02-05 06:26:26 +08:00
|
|
|
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
|
2011-03-09 22:09:51 +08:00
|
|
|
SourceLocation StartLoc, SourceLocation IdLoc,
|
|
|
|
IdentifierInfo *Id, CXXRecordDecl *PrevDecl)
|
|
|
|
: RecordDecl(K, TK, DC, StartLoc, IdLoc, Id, PrevDecl),
|
2010-02-05 06:26:26 +08:00
|
|
|
DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0),
|
2009-03-26 05:17:03 +08:00
|
|
|
TemplateOrInstantiation() { }
|
2008-11-13 07:21:09 +08:00
|
|
|
|
2011-01-12 17:06:06 +08:00
|
|
|
CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
|
2011-03-09 22:09:51 +08:00
|
|
|
DeclContext *DC, SourceLocation StartLoc,
|
|
|
|
SourceLocation IdLoc, IdentifierInfo *Id,
|
2009-05-16 03:11:46 +08:00
|
|
|
CXXRecordDecl* PrevDecl,
|
|
|
|
bool DelayTypeCreation) {
|
2013-11-22 17:01:48 +08:00
|
|
|
CXXRecordDecl *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, DC, StartLoc,
|
|
|
|
IdLoc, Id, PrevDecl);
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 07:36:44 +08:00
|
|
|
// FIXME: DelayTypeCreation seems like such a hack
|
2009-05-16 03:11:46 +08:00
|
|
|
if (!DelayTypeCreation)
|
2009-09-09 23:08:12 +08:00
|
|
|
C.getTypeDeclType(R, PrevDecl);
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
2012-02-13 23:44:47 +08:00
|
|
|
CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
|
2012-09-19 09:18:11 +08:00
|
|
|
TypeSourceInfo *Info, SourceLocation Loc,
|
2013-10-24 00:10:50 +08:00
|
|
|
bool Dependent, bool IsGeneric,
|
|
|
|
LambdaCaptureDefault CaptureDefault) {
|
2013-11-22 17:01:48 +08:00
|
|
|
CXXRecordDecl *R =
|
|
|
|
new (C, DC) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc, 0, 0);
|
2012-02-13 23:44:47 +08:00
|
|
|
R->IsBeingDefined = true;
|
2013-10-24 00:10:50 +08:00
|
|
|
R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info,
|
|
|
|
Dependent,
|
|
|
|
IsGeneric,
|
|
|
|
CaptureDefault);
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
R->MayHaveOutOfDateDef = false;
|
2013-09-06 01:46:21 +08:00
|
|
|
R->setImplicit(true);
|
2012-02-13 23:44:47 +08:00
|
|
|
C.getTypeDeclType(R, /*PrevDecl=*/0);
|
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
CXXRecordDecl *
|
|
|
|
CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
CXXRecordDecl *R = new (C, ID) CXXRecordDecl(
|
|
|
|
CXXRecord, TTK_Struct, 0, SourceLocation(), SourceLocation(), 0, 0);
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
R->MayHaveOutOfDateDef = false;
|
|
|
|
return R;
|
2010-07-02 19:54:55 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
void
|
2010-02-11 09:30:34 +08:00
|
|
|
CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
2008-10-24 02:13:27 +08:00
|
|
|
unsigned NumBases) {
|
2010-02-11 09:30:34 +08:00
|
|
|
ASTContext &C = getASTContext();
|
2008-11-06 00:20:31 +08:00
|
|
|
|
2010-10-30 06:39:52 +08:00
|
|
|
if (!data().Bases.isOffset() && data().NumBases > 0)
|
|
|
|
C.Deallocate(data().getBases());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-19 04:08:55 +08:00
|
|
|
if (NumBases) {
|
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is [...] a class with [...] no base classes [...].
|
|
|
|
data().Aggregate = false;
|
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class...
|
|
|
|
data().PlainOldData = false;
|
|
|
|
}
|
|
|
|
|
2010-03-29 13:13:12 +08:00
|
|
|
// The set of seen virtual base types.
|
2010-03-30 03:49:09 +08:00
|
|
|
llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes;
|
2010-03-29 13:13:12 +08:00
|
|
|
|
|
|
|
// The virtual bases of this class.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<const CXXBaseSpecifier *, 8> VBases;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-05 06:26:26 +08:00
|
|
|
data().Bases = new(C) CXXBaseSpecifier [NumBases];
|
|
|
|
data().NumBases = NumBases;
|
2009-07-11 04:13:23 +08:00
|
|
|
for (unsigned i = 0; i < NumBases; ++i) {
|
2010-10-30 06:39:52 +08:00
|
|
|
data().getBases()[i] = *Bases[i];
|
2009-07-11 04:13:23 +08:00
|
|
|
// Keep track of inherited vbases for this base class.
|
|
|
|
const CXXBaseSpecifier *Base = Bases[i];
|
|
|
|
QualType BaseType = Base->getType();
|
2010-02-27 08:25:28 +08:00
|
|
|
// Skip dependent types; we can't do any checking on them now.
|
2009-07-11 04:13:23 +08:00
|
|
|
if (BaseType->isDependentType())
|
|
|
|
continue;
|
|
|
|
CXXRecordDecl *BaseClassDecl
|
2009-07-30 05:53:49 +08:00
|
|
|
= cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
|
2010-03-29 13:13:12 +08:00
|
|
|
|
2010-09-29 04:38:10 +08:00
|
|
|
// A class with a non-empty base class is not empty.
|
|
|
|
// FIXME: Standard ref?
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
if (!BaseClassDecl->isEmpty()) {
|
|
|
|
if (!data().Empty) {
|
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that:
|
|
|
|
// [...]
|
|
|
|
// -- either has no non-static data members in the most derived
|
|
|
|
// class and at most one base class with non-static data members,
|
|
|
|
// or has no base classes with non-static data members, and
|
|
|
|
// If this is the second non-empty base, then neither of these two
|
|
|
|
// clauses can be true.
|
2011-04-30 18:07:30 +08:00
|
|
|
data().IsStandardLayout = false;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
}
|
|
|
|
|
2010-09-29 04:38:10 +08:00
|
|
|
data().Empty = false;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
data().HasNoNonEmptyBases = false;
|
|
|
|
}
|
2010-09-29 04:38:10 +08:00
|
|
|
|
2010-09-29 04:50:54 +08:00
|
|
|
// C++ [class.virtual]p1:
|
|
|
|
// A class that declares or inherits a virtual function is called a
|
|
|
|
// polymorphic class.
|
|
|
|
if (BaseClassDecl->isPolymorphic())
|
|
|
|
data().Polymorphic = true;
|
2011-04-24 10:49:34 +08:00
|
|
|
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that: [...]
|
|
|
|
// -- has no non-standard-layout base classes
|
2011-04-30 18:07:30 +08:00
|
|
|
if (!BaseClassDecl->isStandardLayout())
|
|
|
|
data().IsStandardLayout = false;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
|
2011-04-24 10:49:34 +08:00
|
|
|
// Record if this base is the first non-literal field or base.
|
2013-04-22 23:31:51 +08:00
|
|
|
if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C))
|
2011-04-24 10:49:34 +08:00
|
|
|
data().HasNonLiteralTypeFieldsOrBases = true;
|
2010-09-29 04:50:54 +08:00
|
|
|
|
2010-03-29 13:13:12 +08:00
|
|
|
// Now go through all virtual bases of this base and add them.
|
2014-03-14 00:15:17 +08:00
|
|
|
for (const auto &VBase : BaseClassDecl->vbases()) {
|
2010-03-29 13:13:12 +08:00
|
|
|
// Add this base if it's not already in the list.
|
2014-03-14 00:15:17 +08:00
|
|
|
if (SeenVBaseTypes.insert(C.getCanonicalType(VBase.getType()))) {
|
|
|
|
VBases.push_back(&VBase);
|
2012-11-28 14:23:12 +08:00
|
|
|
|
|
|
|
// C++11 [class.copy]p8:
|
|
|
|
// The implicitly-declared copy constructor for a class X will have
|
|
|
|
// the form 'X::X(const X&)' if each [...] virtual base class B of X
|
|
|
|
// has a copy constructor whose first parameter is of type
|
|
|
|
// 'const B&' or 'const volatile B&' [...]
|
2014-03-14 00:15:17 +08:00
|
|
|
if (CXXRecordDecl *VBaseDecl = VBase.getType()->getAsCXXRecordDecl())
|
2012-11-28 14:23:12 +08:00
|
|
|
if (!VBaseDecl->hasCopyConstructorWithConstParam())
|
|
|
|
data().ImplicitCopyConstructorHasConstParam = false;
|
|
|
|
}
|
2009-07-11 04:13:23 +08:00
|
|
|
}
|
2010-03-29 13:13:12 +08:00
|
|
|
|
|
|
|
if (Base->isVirtual()) {
|
|
|
|
// Add this base if it's not already in the list.
|
2010-03-30 03:49:09 +08:00
|
|
|
if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
|
2012-11-28 14:23:12 +08:00
|
|
|
VBases.push_back(Base);
|
|
|
|
|
2010-09-29 04:38:10 +08:00
|
|
|
// C++0x [meta.unary.prop] is_empty:
|
|
|
|
// T is a class type, but not a union type, with ... no virtual base
|
|
|
|
// classes
|
|
|
|
data().Empty = false;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
2012-11-30 13:11:39 +08:00
|
|
|
// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
|
|
|
|
// A [default constructor, copy/move constructor, or copy/move assignment
|
|
|
|
// operator for a class X] is trivial [...] if:
|
|
|
|
// -- class X has [...] no virtual base classes
|
|
|
|
data().HasTrivialSpecialMembers &= SMF_Destructor;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
|
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that: [...]
|
|
|
|
// -- has [...] no virtual base classes
|
2011-04-30 18:07:30 +08:00
|
|
|
data().IsStandardLayout = false;
|
2011-12-22 10:22:31 +08:00
|
|
|
|
|
|
|
// C++11 [dcl.constexpr]p4:
|
|
|
|
// In the definition of a constexpr constructor [...]
|
|
|
|
// -- the class shall not have any virtual base classes
|
|
|
|
data().DefaultedDefaultConstructorIsConstexpr = false;
|
2010-09-29 04:50:54 +08:00
|
|
|
} else {
|
|
|
|
// C++ [class.ctor]p5:
|
2011-05-10 02:22:59 +08:00
|
|
|
// A default constructor is trivial [...] if:
|
|
|
|
// -- all the direct base classes of its class have trivial default
|
|
|
|
// constructors.
|
|
|
|
if (!BaseClassDecl->hasTrivialDefaultConstructor())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
|
|
|
|
|
2011-04-24 07:10:33 +08:00
|
|
|
// C++0x [class.copy]p13:
|
|
|
|
// A copy/move constructor for class X is trivial if [...]
|
|
|
|
// [...]
|
|
|
|
// -- the constructor selected to copy/move each direct base class
|
|
|
|
// subobject is trivial, and
|
2010-09-29 04:50:54 +08:00
|
|
|
if (!BaseClassDecl->hasTrivialCopyConstructor())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
|
2012-12-08 16:32:28 +08:00
|
|
|
// If the base class doesn't have a simple move constructor, we'll eagerly
|
|
|
|
// declare it and perform overload resolution to determine which function
|
|
|
|
// it actually calls. If it does have a simple move constructor, this
|
|
|
|
// check is correct.
|
2012-11-16 08:53:38 +08:00
|
|
|
if (!BaseClassDecl->hasTrivialMoveConstructor())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
|
|
|
// C++0x [class.copy]p27:
|
|
|
|
// A copy/move assignment operator for class X is trivial if [...]
|
|
|
|
// [...]
|
|
|
|
// -- the assignment operator selected to copy/move each direct base
|
|
|
|
// class subobject is trivial, and
|
2010-09-29 04:50:54 +08:00
|
|
|
if (!BaseClassDecl->hasTrivialCopyAssignment())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
|
2012-12-08 16:32:28 +08:00
|
|
|
// If the base class doesn't have a simple move assignment, we'll eagerly
|
|
|
|
// declare it and perform overload resolution to determine which function
|
|
|
|
// it actually calls. If it does have a simple move assignment, this
|
|
|
|
// check is correct.
|
2012-11-16 08:53:38 +08:00
|
|
|
if (!BaseClassDecl->hasTrivialMoveAssignment())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
|
2011-12-22 10:22:31 +08:00
|
|
|
|
|
|
|
// C++11 [class.ctor]p6:
|
2012-01-12 02:26:05 +08:00
|
|
|
// If that user-written default constructor would satisfy the
|
2011-12-22 10:22:31 +08:00
|
|
|
// requirements of a constexpr constructor, the implicitly-defined
|
|
|
|
// default constructor is constexpr.
|
|
|
|
if (!BaseClassDecl->hasConstexprDefaultConstructor())
|
|
|
|
data().DefaultedDefaultConstructorIsConstexpr = false;
|
2009-07-11 04:13:23 +08:00
|
|
|
}
|
2012-12-08 10:53:02 +08:00
|
|
|
|
2010-09-29 04:50:54 +08:00
|
|
|
// C++ [class.ctor]p3:
|
|
|
|
// A destructor is trivial if all the direct base classes of its class
|
|
|
|
// have trivial destructors.
|
|
|
|
if (!BaseClassDecl->hasTrivialDestructor())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_Destructor;
|
2012-02-25 15:33:38 +08:00
|
|
|
|
|
|
|
if (!BaseClassDecl->hasIrrelevantDestructor())
|
|
|
|
data().HasIrrelevantDestructor = false;
|
|
|
|
|
2012-11-28 14:23:12 +08:00
|
|
|
// C++11 [class.copy]p18:
|
|
|
|
// The implicitly-declared copy assignment oeprator for a class X will
|
|
|
|
// have the form 'X& X::operator=(const X&)' if each direct base class B
|
|
|
|
// of X has a copy assignment operator whose parameter is of type 'const
|
|
|
|
// B&', 'const volatile B&', or 'B' [...]
|
|
|
|
if (!BaseClassDecl->hasCopyAssignmentWithConstParam())
|
|
|
|
data().ImplicitCopyAssignmentHasConstParam = false;
|
|
|
|
|
|
|
|
// C++11 [class.copy]p8:
|
|
|
|
// The implicitly-declared copy constructor for a class X will have
|
|
|
|
// the form 'X::X(const X&)' if each direct [...] base class B of X
|
|
|
|
// has a copy constructor whose first parameter is of type
|
|
|
|
// 'const B&' or 'const volatile B&' [...]
|
|
|
|
if (!BaseClassDecl->hasCopyConstructorWithConstParam())
|
|
|
|
data().ImplicitCopyConstructorHasConstParam = false;
|
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
// A class has an Objective-C object member if... or any of its bases
|
|
|
|
// has an Objective-C object member.
|
|
|
|
if (BaseClassDecl->hasObjectMember())
|
|
|
|
setHasObjectMember(true);
|
2013-01-26 07:57:05 +08:00
|
|
|
|
|
|
|
if (BaseClassDecl->hasVolatileMember())
|
|
|
|
setHasVolatileMember(true);
|
2011-06-16 07:02:42 +08:00
|
|
|
|
2011-05-13 09:05:07 +08:00
|
|
|
// Keep track of the presence of mutable fields.
|
|
|
|
if (BaseClassDecl->hasMutableFields())
|
|
|
|
data().HasMutableFields = true;
|
2012-12-08 10:01:17 +08:00
|
|
|
|
|
|
|
if (BaseClassDecl->hasUninitializedReferenceMember())
|
|
|
|
data().HasUninitializedReferenceMember = true;
|
2012-12-08 16:32:28 +08:00
|
|
|
|
|
|
|
addedClassSubobject(BaseClassDecl);
|
2009-07-11 04:13:23 +08:00
|
|
|
}
|
2010-03-29 13:13:12 +08:00
|
|
|
|
|
|
|
if (VBases.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create base specifier for any direct or indirect virtual bases.
|
|
|
|
data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
|
|
|
|
data().NumVBases = VBases.size();
|
2012-12-08 16:32:28 +08:00
|
|
|
for (int I = 0, E = VBases.size(); I != E; ++I) {
|
|
|
|
QualType Type = VBases[I]->getType();
|
|
|
|
if (!Type->isDependentType())
|
|
|
|
addedClassSubobject(Type->getAsCXXRecordDecl());
|
2011-07-13 07:49:11 +08:00
|
|
|
data().getVBases()[I] = *VBases[I];
|
2012-12-08 16:32:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
|
|
|
|
// C++11 [class.copy]p11:
|
|
|
|
// A defaulted copy/move constructor for a class X is defined as
|
|
|
|
// deleted if X has:
|
|
|
|
// -- a direct or virtual base class B that cannot be copied/moved [...]
|
|
|
|
// -- a non-static data member of class type M (or array thereof)
|
|
|
|
// that cannot be copied or moved [...]
|
|
|
|
if (!Subobj->hasSimpleMoveConstructor())
|
|
|
|
data().NeedOverloadResolutionForMoveConstructor = true;
|
|
|
|
|
|
|
|
// C++11 [class.copy]p23:
|
|
|
|
// A defaulted copy/move assignment operator for a class X is defined as
|
|
|
|
// deleted if X has:
|
|
|
|
// -- a direct or virtual base class B that cannot be copied/moved [...]
|
|
|
|
// -- a non-static data member of class type M (or array thereof)
|
|
|
|
// that cannot be copied or moved [...]
|
|
|
|
if (!Subobj->hasSimpleMoveAssignment())
|
|
|
|
data().NeedOverloadResolutionForMoveAssignment = true;
|
|
|
|
|
|
|
|
// C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5:
|
|
|
|
// A defaulted [ctor or dtor] for a class X is defined as
|
|
|
|
// deleted if X has:
|
|
|
|
// -- any direct or virtual base class [...] has a type with a destructor
|
|
|
|
// that is deleted or inaccessible from the defaulted [ctor or dtor].
|
|
|
|
// -- any non-static data member has a type with a destructor
|
|
|
|
// that is deleted or inaccessible from the defaulted [ctor or dtor].
|
|
|
|
if (!Subobj->hasSimpleDestructor()) {
|
|
|
|
data().NeedOverloadResolutionForMoveConstructor = true;
|
|
|
|
data().NeedOverloadResolutionForDestructor = true;
|
|
|
|
}
|
2008-10-24 02:13:27 +08:00
|
|
|
}
|
|
|
|
|
2010-01-15 01:47:39 +08:00
|
|
|
/// Callback function for CXXRecordDecl::forallBases that acknowledges
|
|
|
|
/// that it saw a base class.
|
|
|
|
static bool SawBase(const CXXRecordDecl *, void *) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CXXRecordDecl::hasAnyDependentBases() const {
|
|
|
|
if (!isDependentContext())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return !forallBases(SawBase, 0);
|
|
|
|
}
|
|
|
|
|
2011-04-23 18:47:28 +08:00
|
|
|
bool CXXRecordDecl::isTriviallyCopyable() const {
|
|
|
|
// C++0x [class]p5:
|
|
|
|
// A trivially copyable class is a class that:
|
|
|
|
// -- has no non-trivial copy constructors,
|
2012-11-16 08:53:38 +08:00
|
|
|
if (hasNonTrivialCopyConstructor()) return false;
|
2011-04-23 18:47:28 +08:00
|
|
|
// -- has no non-trivial move constructors,
|
2012-11-16 08:53:38 +08:00
|
|
|
if (hasNonTrivialMoveConstructor()) return false;
|
2011-04-23 18:47:28 +08:00
|
|
|
// -- has no non-trivial copy assignment operators,
|
2012-11-16 08:53:38 +08:00
|
|
|
if (hasNonTrivialCopyAssignment()) return false;
|
2011-04-23 18:47:28 +08:00
|
|
|
// -- has no non-trivial move assignment operators, and
|
2012-11-16 08:53:38 +08:00
|
|
|
if (hasNonTrivialMoveAssignment()) return false;
|
2011-04-23 18:47:28 +08:00
|
|
|
// -- has a trivial destructor.
|
|
|
|
if (!hasTrivialDestructor()) return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-09-29 05:55:22 +08:00
|
|
|
void CXXRecordDecl::markedVirtualFunctionPure() {
|
|
|
|
// C++ [class.abstract]p2:
|
|
|
|
// A class is abstract if it has at least one pure virtual function.
|
|
|
|
data().Abstract = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CXXRecordDecl::addedMember(Decl *D) {
|
2012-09-01 06:18:20 +08:00
|
|
|
if (!D->isImplicit() &&
|
|
|
|
!isa<FieldDecl>(D) &&
|
|
|
|
!isa<IndirectFieldDecl>(D) &&
|
|
|
|
(!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class ||
|
|
|
|
cast<TagDecl>(D)->getTagKind() == TTK_Interface))
|
|
|
|
data().HasOnlyCMembers = false;
|
|
|
|
|
|
|
|
// Ignore friends and invalid declarations.
|
2010-09-28 06:06:20 +08:00
|
|
|
if (D->getFriendObjectKind() || D->isInvalidDecl())
|
2010-09-28 05:17:54 +08:00
|
|
|
return;
|
|
|
|
|
2010-09-28 06:06:20 +08:00
|
|
|
FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
|
|
|
|
if (FunTmpl)
|
|
|
|
D = FunTmpl->getTemplatedDecl();
|
|
|
|
|
2010-09-29 03:45:33 +08:00
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
|
|
|
|
if (Method->isVirtual()) {
|
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is an array or a class with [...] no virtual functions.
|
|
|
|
data().Aggregate = false;
|
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class...
|
|
|
|
data().PlainOldData = false;
|
2010-09-29 04:38:10 +08:00
|
|
|
|
|
|
|
// Virtual functions make the class non-empty.
|
|
|
|
// FIXME: Standard ref?
|
|
|
|
data().Empty = false;
|
2010-09-29 04:50:54 +08:00
|
|
|
|
|
|
|
// C++ [class.virtual]p1:
|
|
|
|
// A class that declares or inherits a virtual function is called a
|
|
|
|
// polymorphic class.
|
|
|
|
data().Polymorphic = true;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
2012-11-30 13:11:39 +08:00
|
|
|
// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
|
|
|
|
// A [default constructor, copy/move constructor, or copy/move
|
|
|
|
// assignment operator for a class X] is trivial [...] if:
|
2011-04-24 07:10:33 +08:00
|
|
|
// -- class X has no virtual functions [...]
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= SMF_Destructor;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that: [...]
|
|
|
|
// -- has no virtual functions
|
2011-04-30 18:07:30 +08:00
|
|
|
data().IsStandardLayout = false;
|
2010-09-29 03:45:33 +08:00
|
|
|
}
|
|
|
|
}
|
2010-09-29 04:38:10 +08:00
|
|
|
|
2012-11-28 14:23:12 +08:00
|
|
|
// Notify the listener if an implicit member was added after the definition
|
|
|
|
// was completed.
|
|
|
|
if (!isBeingDefined() && D->isImplicit())
|
|
|
|
if (ASTMutationListener *L = getASTMutationListener())
|
|
|
|
L->AddedCXXImplicitMember(data().Definition, D);
|
|
|
|
|
2012-11-30 13:11:39 +08:00
|
|
|
// The kind of special member this declaration is, if any.
|
|
|
|
unsigned SMKind = 0;
|
|
|
|
|
2012-11-28 14:23:12 +08:00
|
|
|
// Handle constructors.
|
2010-09-28 06:06:20 +08:00
|
|
|
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
2012-11-28 14:23:12 +08:00
|
|
|
if (!Constructor->isImplicit()) {
|
|
|
|
// Note that we have a user-declared constructor.
|
|
|
|
data().UserDeclaredConstructor = true;
|
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class [...]
|
|
|
|
// Since the POD bit is meant to be C++03 POD-ness, clear it even if the
|
|
|
|
// type is technically an aggregate in C++0x since it wouldn't be in 03.
|
|
|
|
data().PlainOldData = false;
|
|
|
|
}
|
2009-06-18 06:44:31 +08:00
|
|
|
|
2011-09-05 10:13:09 +08:00
|
|
|
// Technically, "user-provided" is only defined for special member
|
|
|
|
// functions, but the intent of the standard is clearly that it should apply
|
|
|
|
// to all functions.
|
|
|
|
bool UserProvided = Constructor->isUserProvided();
|
2010-09-28 06:06:20 +08:00
|
|
|
|
2011-05-10 05:45:35 +08:00
|
|
|
if (Constructor->isDefaultConstructor()) {
|
2012-11-30 13:11:39 +08:00
|
|
|
SMKind |= SMF_DefaultConstructor;
|
|
|
|
|
|
|
|
if (UserProvided)
|
2011-05-12 06:34:38 +08:00
|
|
|
data().UserProvidedDefaultConstructor = true;
|
2012-11-28 14:23:12 +08:00
|
|
|
if (Constructor->isConstexpr())
|
2011-12-22 10:22:31 +08:00
|
|
|
data().HasConstexprDefaultConstructor = true;
|
2011-05-10 05:45:35 +08:00
|
|
|
}
|
2010-09-28 06:06:20 +08:00
|
|
|
|
2011-04-24 07:10:33 +08:00
|
|
|
if (!FunTmpl) {
|
2012-11-28 14:23:12 +08:00
|
|
|
unsigned Quals;
|
|
|
|
if (Constructor->isCopyConstructor(Quals)) {
|
2012-11-30 13:11:39 +08:00
|
|
|
SMKind |= SMF_CopyConstructor;
|
2012-11-28 14:23:12 +08:00
|
|
|
|
|
|
|
if (Quals & Qualifiers::Const)
|
|
|
|
data().HasDeclaredCopyConstructorWithConstParam = true;
|
2012-11-30 13:11:39 +08:00
|
|
|
} else if (Constructor->isMoveConstructor())
|
|
|
|
SMKind |= SMF_MoveConstructor;
|
2010-09-28 06:06:20 +08:00
|
|
|
}
|
2012-11-28 14:23:12 +08:00
|
|
|
|
|
|
|
// Record if we see any constexpr constructors which are neither copy
|
|
|
|
// nor move constructors.
|
|
|
|
if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor())
|
2011-08-11 02:11:37 +08:00
|
|
|
data().HasConstexprNonCopyMoveConstructor = true;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
2011-05-10 05:45:35 +08:00
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is an array or a class with no user-declared
|
|
|
|
// constructors [...].
|
2013-04-21 06:23:05 +08:00
|
|
|
// C++11 [dcl.init.aggr]p1:
|
2011-05-10 05:45:35 +08:00
|
|
|
// An aggregate is an array or a class with no user-provided
|
|
|
|
// constructors [...].
|
2013-01-02 19:42:31 +08:00
|
|
|
if (getASTContext().getLangOpts().CPlusPlus11
|
2012-11-28 14:23:12 +08:00
|
|
|
? UserProvided : !Constructor->isImplicit())
|
2011-05-10 05:45:35 +08:00
|
|
|
data().Aggregate = false;
|
2009-07-23 02:25:24 +08:00
|
|
|
}
|
2008-11-01 04:25:05 +08:00
|
|
|
|
2012-11-28 14:23:12 +08:00
|
|
|
// Handle destructors.
|
2011-05-17 06:41:40 +08:00
|
|
|
if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
|
2012-11-30 13:11:39 +08:00
|
|
|
SMKind |= SMF_Destructor;
|
2012-02-25 15:33:38 +08:00
|
|
|
|
2012-11-30 13:11:39 +08:00
|
|
|
if (!DD->isImplicit())
|
2012-11-28 14:23:12 +08:00
|
|
|
data().HasIrrelevantDestructor = false;
|
|
|
|
|
|
|
|
// C++11 [class.dtor]p5:
|
2012-11-30 13:11:39 +08:00
|
|
|
// A destructor is trivial if [...] the destructor is not virtual.
|
|
|
|
if (DD->isVirtual())
|
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_Destructor;
|
2010-09-28 06:48:58 +08:00
|
|
|
}
|
2012-11-28 14:23:12 +08:00
|
|
|
|
|
|
|
// Handle member functions.
|
2010-09-28 06:06:20 +08:00
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
|
2011-05-26 04:50:04 +08:00
|
|
|
if (Method->isCopyAssignmentOperator()) {
|
2012-11-30 13:11:39 +08:00
|
|
|
SMKind |= SMF_CopyAssignment;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
2012-11-28 14:23:12 +08:00
|
|
|
const ReferenceType *ParamTy =
|
|
|
|
Method->getParamDecl(0)->getType()->getAs<ReferenceType>();
|
|
|
|
if (!ParamTy || ParamTy->getPointeeType().isConstQualified())
|
|
|
|
data().HasDeclaredCopyAssignmentWithConstParam = true;
|
2011-05-26 04:50:04 +08:00
|
|
|
}
|
|
|
|
|
2012-11-30 13:11:39 +08:00
|
|
|
if (Method->isMoveAssignmentOperator())
|
|
|
|
SMKind |= SMF_MoveAssignment;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
2010-09-29 12:25:11 +08:00
|
|
|
// Keep the list of conversion functions up-to-date.
|
|
|
|
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
|
2013-04-09 01:12:58 +08:00
|
|
|
// FIXME: We use the 'unsafe' accessor for the access specifier here,
|
|
|
|
// because Sema may not have set it yet. That's really just a misdesign
|
|
|
|
// in Sema. However, LLDB *will* have set the access specifier correctly,
|
|
|
|
// and adds declarations after the class is technically completed,
|
|
|
|
// so completeDefinition()'s overriding of the access specifiers doesn't
|
|
|
|
// work.
|
|
|
|
AccessSpecifier AS = Conversion->getAccessUnsafe();
|
|
|
|
|
2012-11-30 13:11:39 +08:00
|
|
|
if (Conversion->getPrimaryTemplate()) {
|
|
|
|
// We don't record specializations.
|
2010-09-29 12:25:11 +08:00
|
|
|
} else {
|
2013-08-30 12:46:40 +08:00
|
|
|
ASTContext &Ctx = getASTContext();
|
|
|
|
ASTUnresolvedSet &Conversions = data().Conversions.get(Ctx);
|
|
|
|
NamedDecl *Primary =
|
|
|
|
FunTmpl ? cast<NamedDecl>(FunTmpl) : cast<NamedDecl>(Conversion);
|
|
|
|
if (Primary->getPreviousDecl())
|
|
|
|
Conversions.replace(cast<NamedDecl>(Primary->getPreviousDecl()),
|
|
|
|
Primary, AS);
|
2010-09-29 12:25:11 +08:00
|
|
|
else
|
2013-08-30 12:46:40 +08:00
|
|
|
Conversions.addDecl(Ctx, Primary, AS);
|
2010-09-29 12:25:11 +08:00
|
|
|
}
|
|
|
|
}
|
2012-11-28 14:23:12 +08:00
|
|
|
|
2012-11-30 13:11:39 +08:00
|
|
|
if (SMKind) {
|
2012-12-08 10:53:02 +08:00
|
|
|
// If this is the first declaration of a special member, we no longer have
|
|
|
|
// an implicit trivial special member.
|
|
|
|
data().HasTrivialSpecialMembers &=
|
|
|
|
data().DeclaredSpecialMembers | ~SMKind;
|
|
|
|
|
|
|
|
if (!Method->isImplicit() && !Method->isUserProvided()) {
|
|
|
|
// This method is user-declared but not user-provided. We can't work out
|
|
|
|
// whether it's trivial yet (not until we get to the end of the class).
|
|
|
|
// We'll handle this method in finishedDefaultedOrDeletedMember.
|
|
|
|
} else if (Method->isTrivial())
|
|
|
|
data().HasTrivialSpecialMembers |= SMKind;
|
|
|
|
else
|
|
|
|
data().DeclaredNonTrivialSpecialMembers |= SMKind;
|
|
|
|
|
2012-11-30 13:11:39 +08:00
|
|
|
// Note when we have declared a declared special member, and suppress the
|
|
|
|
// implicit declaration of this special member.
|
|
|
|
data().DeclaredSpecialMembers |= SMKind;
|
|
|
|
|
|
|
|
if (!Method->isImplicit()) {
|
|
|
|
data().UserDeclaredSpecialMembers |= SMKind;
|
|
|
|
|
|
|
|
// C++03 [class]p4:
|
|
|
|
// A POD-struct is an aggregate class that has [...] no user-defined
|
|
|
|
// copy assignment operator and no user-defined destructor.
|
|
|
|
//
|
|
|
|
// Since the POD bit is meant to be C++03 POD-ness, and in C++03,
|
|
|
|
// aggregates could not have any constructors, clear it even for an
|
|
|
|
// explicitly defaulted or deleted constructor.
|
|
|
|
// type is technically an aggregate in C++0x since it wouldn't be in 03.
|
|
|
|
//
|
|
|
|
// Also, a user-declared move assignment operator makes a class non-POD.
|
|
|
|
// This is an extension in C++03.
|
|
|
|
data().PlainOldData = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-06 04:52:13 +08:00
|
|
|
return;
|
2010-09-28 06:06:20 +08:00
|
|
|
}
|
2012-11-30 13:11:39 +08:00
|
|
|
|
2010-09-29 03:45:33 +08:00
|
|
|
// Handle non-static data members.
|
|
|
|
if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
|
2011-10-11 01:22:13 +08:00
|
|
|
// C++ [class.bit]p2:
|
|
|
|
// A declaration for a bit-field that omits the identifier declares an
|
|
|
|
// unnamed bit-field. Unnamed bit-fields are not members and cannot be
|
|
|
|
// initialized.
|
|
|
|
if (Field->isUnnamedBitfield())
|
|
|
|
return;
|
|
|
|
|
2010-09-29 03:45:33 +08:00
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is an array or a class (clause 9) with [...] no
|
|
|
|
// private or protected non-static data members (clause 11).
|
|
|
|
//
|
|
|
|
// A POD must be an aggregate.
|
|
|
|
if (D->getAccess() == AS_private || D->getAccess() == AS_protected) {
|
|
|
|
data().Aggregate = false;
|
|
|
|
data().PlainOldData = false;
|
|
|
|
}
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
|
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that:
|
|
|
|
// [...]
|
|
|
|
// -- has the same access control for all non-static data members,
|
|
|
|
switch (D->getAccess()) {
|
|
|
|
case AS_private: data().HasPrivateFields = true; break;
|
|
|
|
case AS_protected: data().HasProtectedFields = true; break;
|
|
|
|
case AS_public: data().HasPublicFields = true; break;
|
2011-09-23 13:06:16 +08:00
|
|
|
case AS_none: llvm_unreachable("Invalid access specifier");
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
};
|
|
|
|
if ((data().HasPrivateFields + data().HasProtectedFields +
|
|
|
|
data().HasPublicFields) > 1)
|
2011-04-30 18:07:30 +08:00
|
|
|
data().IsStandardLayout = false;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
|
2011-05-13 09:05:07 +08:00
|
|
|
// Keep track of the presence of mutable fields.
|
|
|
|
if (Field->isMutable())
|
|
|
|
data().HasMutableFields = true;
|
2013-12-10 16:25:00 +08:00
|
|
|
|
|
|
|
// C++11 [class.union]p8, DR1460:
|
|
|
|
// If X is a union, a non-static data member of X that is not an anonymous
|
|
|
|
// union is a variant member of X.
|
|
|
|
if (isUnion() && !Field->isAnonymousStructOrUnion())
|
|
|
|
data().HasVariantMembers = true;
|
|
|
|
|
2011-04-24 07:10:33 +08:00
|
|
|
// C++0x [class]p9:
|
2010-09-29 03:45:33 +08:00
|
|
|
// A POD struct is a class that is both a trivial class and a
|
|
|
|
// standard-layout class, and has no non-static data members of type
|
|
|
|
// non-POD struct, non-POD union (or array of such types).
|
2011-06-16 07:02:42 +08:00
|
|
|
//
|
|
|
|
// Automatic Reference Counting: the presence of a member of Objective-C pointer type
|
|
|
|
// that does not explicitly have no lifetime makes the class a non-POD.
|
|
|
|
// However, we delay setting PlainOldData to false in this case so that
|
|
|
|
// Sema has a chance to diagnostic causes where the same class will be
|
2012-07-23 12:23:39 +08:00
|
|
|
// non-POD with Automatic Reference Counting but a POD without ARC.
|
2011-06-16 07:02:42 +08:00
|
|
|
// In this case, the class will become a non-POD class when we complete
|
|
|
|
// the definition.
|
2010-09-29 03:45:33 +08:00
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
QualType T = Context.getBaseElementType(Field->getType());
|
2011-06-16 07:02:42 +08:00
|
|
|
if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!Context.getLangOpts().ObjCAutoRefCount ||
|
2011-06-16 07:02:42 +08:00
|
|
|
T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
|
|
|
|
setHasObjectMember(true);
|
2013-07-20 09:06:31 +08:00
|
|
|
} else if (!T.isCXX98PODType(Context))
|
2010-09-29 03:45:33 +08:00
|
|
|
data().PlainOldData = false;
|
2011-06-16 07:02:42 +08:00
|
|
|
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
if (T->isReferenceType()) {
|
2012-12-08 10:01:17 +08:00
|
|
|
if (!Field->hasInClassInitializer())
|
|
|
|
data().HasUninitializedReferenceMember = true;
|
2011-04-24 10:49:34 +08:00
|
|
|
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that:
|
|
|
|
// -- has no non-static data members of type [...] reference,
|
2011-04-30 18:07:30 +08:00
|
|
|
data().IsStandardLayout = false;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
}
|
|
|
|
|
2012-02-13 11:54:03 +08:00
|
|
|
// Record if this field is the first non-literal or volatile field or base.
|
2013-04-22 23:31:51 +08:00
|
|
|
if (!T->isLiteralType(Context) || T.isVolatileQualified())
|
2011-04-24 10:49:34 +08:00
|
|
|
data().HasNonLiteralTypeFieldsOrBases = true;
|
|
|
|
|
2013-12-10 16:25:00 +08:00
|
|
|
if (Field->hasInClassInitializer() ||
|
|
|
|
(Field->isAnonymousStructOrUnion() &&
|
|
|
|
Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) {
|
2012-05-07 09:07:30 +08:00
|
|
|
data().HasInClassInitializer = true;
|
|
|
|
|
|
|
|
// C++11 [class]p5:
|
2011-06-12 01:19:42 +08:00
|
|
|
// A default constructor is trivial if [...] no non-static data member
|
|
|
|
// of its class has a brace-or-equal-initializer.
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
|
2011-06-12 01:19:42 +08:00
|
|
|
|
2012-05-07 09:07:30 +08:00
|
|
|
// C++11 [dcl.init.aggr]p1:
|
2011-06-12 01:19:42 +08:00
|
|
|
// An aggregate is a [...] class with [...] no
|
|
|
|
// brace-or-equal-initializers for non-static data members.
|
2013-04-21 06:23:05 +08:00
|
|
|
//
|
|
|
|
// This rule was removed in C++1y.
|
|
|
|
if (!getASTContext().getLangOpts().CPlusPlus1y)
|
|
|
|
data().Aggregate = false;
|
2011-06-12 01:19:42 +08:00
|
|
|
|
2012-05-07 09:07:30 +08:00
|
|
|
// C++11 [class]p10:
|
2011-06-12 01:19:42 +08:00
|
|
|
// A POD struct is [...] a trivial class.
|
|
|
|
data().PlainOldData = false;
|
|
|
|
}
|
|
|
|
|
2012-12-08 16:32:28 +08:00
|
|
|
// C++11 [class.copy]p23:
|
|
|
|
// A defaulted copy/move assignment operator for a class X is defined
|
|
|
|
// as deleted if X has:
|
|
|
|
// -- a non-static data member of reference type
|
|
|
|
if (T->isReferenceType())
|
|
|
|
data().DefaultedMoveAssignmentIsDeleted = true;
|
|
|
|
|
2010-09-29 04:50:54 +08:00
|
|
|
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
|
|
|
|
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
|
|
|
|
if (FieldRec->getDefinition()) {
|
2012-12-08 16:32:28 +08:00
|
|
|
addedClassSubobject(FieldRec);
|
|
|
|
|
2013-11-25 15:07:05 +08:00
|
|
|
// We may need to perform overload resolution to determine whether a
|
|
|
|
// field can be moved if it's const or volatile qualified.
|
|
|
|
if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) {
|
|
|
|
data().NeedOverloadResolutionForMoveConstructor = true;
|
|
|
|
data().NeedOverloadResolutionForMoveAssignment = true;
|
|
|
|
}
|
|
|
|
|
2012-12-08 16:32:28 +08:00
|
|
|
// C++11 [class.ctor]p5, C++11 [class.copy]p11:
|
|
|
|
// A defaulted [special member] for a class X is defined as
|
|
|
|
// deleted if:
|
|
|
|
// -- X is a union-like class that has a variant member with a
|
|
|
|
// non-trivial [corresponding special member]
|
|
|
|
if (isUnion()) {
|
|
|
|
if (FieldRec->hasNonTrivialMoveConstructor())
|
|
|
|
data().DefaultedMoveConstructorIsDeleted = true;
|
|
|
|
if (FieldRec->hasNonTrivialMoveAssignment())
|
|
|
|
data().DefaultedMoveAssignmentIsDeleted = true;
|
|
|
|
if (FieldRec->hasNonTrivialDestructor())
|
|
|
|
data().DefaultedDestructorIsDeleted = true;
|
|
|
|
}
|
|
|
|
|
2011-05-10 02:22:59 +08:00
|
|
|
// C++0x [class.ctor]p5:
|
2011-12-22 10:22:31 +08:00
|
|
|
// A default constructor is trivial [...] if:
|
2011-05-10 02:22:59 +08:00
|
|
|
// -- for all the non-static data members of its class that are of
|
|
|
|
// class type (or array thereof), each such class has a trivial
|
|
|
|
// default constructor.
|
|
|
|
if (!FieldRec->hasTrivialDefaultConstructor())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
|
|
|
// C++0x [class.copy]p13:
|
|
|
|
// A copy/move constructor for class X is trivial if [...]
|
|
|
|
// [...]
|
|
|
|
// -- for each non-static data member of X that is of class type (or
|
|
|
|
// an array thereof), the constructor selected to copy/move that
|
|
|
|
// member is trivial;
|
2010-09-29 04:50:54 +08:00
|
|
|
if (!FieldRec->hasTrivialCopyConstructor())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
|
2012-12-08 16:32:28 +08:00
|
|
|
// If the field doesn't have a simple move constructor, we'll eagerly
|
|
|
|
// declare the move constructor for this class and we'll decide whether
|
|
|
|
// it's trivial then.
|
2012-11-16 08:53:38 +08:00
|
|
|
if (!FieldRec->hasTrivialMoveConstructor())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
|
|
|
// C++0x [class.copy]p27:
|
|
|
|
// A copy/move assignment operator for class X is trivial if [...]
|
|
|
|
// [...]
|
|
|
|
// -- for each non-static data member of X that is of class type (or
|
|
|
|
// an array thereof), the assignment operator selected to
|
|
|
|
// copy/move that member is trivial;
|
2010-09-29 04:50:54 +08:00
|
|
|
if (!FieldRec->hasTrivialCopyAssignment())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
|
2012-12-08 16:32:28 +08:00
|
|
|
// If the field doesn't have a simple move assignment, we'll eagerly
|
|
|
|
// declare the move assignment for this class and we'll decide whether
|
|
|
|
// it's trivial then.
|
2012-11-16 08:53:38 +08:00
|
|
|
if (!FieldRec->hasTrivialMoveAssignment())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
|
2011-04-24 07:10:33 +08:00
|
|
|
|
2010-09-29 04:50:54 +08:00
|
|
|
if (!FieldRec->hasTrivialDestructor())
|
2012-11-30 13:11:39 +08:00
|
|
|
data().HasTrivialSpecialMembers &= ~SMF_Destructor;
|
2012-02-25 15:33:38 +08:00
|
|
|
if (!FieldRec->hasIrrelevantDestructor())
|
|
|
|
data().HasIrrelevantDestructor = false;
|
2011-06-16 07:02:42 +08:00
|
|
|
if (FieldRec->hasObjectMember())
|
|
|
|
setHasObjectMember(true);
|
2013-01-26 07:57:05 +08:00
|
|
|
if (FieldRec->hasVolatileMember())
|
|
|
|
setHasVolatileMember(true);
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
|
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that:
|
|
|
|
// -- has no non-static data members of type non-standard-layout
|
|
|
|
// class (or array of such types) [...]
|
2011-04-30 18:07:30 +08:00
|
|
|
if (!FieldRec->isStandardLayout())
|
|
|
|
data().IsStandardLayout = false;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
|
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that:
|
|
|
|
// [...]
|
|
|
|
// -- has no base classes of the same type as the first non-static
|
|
|
|
// data member.
|
|
|
|
// We don't want to expend bits in the state of the record decl
|
|
|
|
// tracking whether this is the first non-static data member so we
|
|
|
|
// cheat a bit and use some of the existing state: the empty bit.
|
|
|
|
// Virtual bases and virtual methods make a class non-empty, but they
|
|
|
|
// also make it non-standard-layout so we needn't check here.
|
|
|
|
// A non-empty base class may leave the class standard-layout, but not
|
2013-12-10 16:25:00 +08:00
|
|
|
// if we have arrived here, and have at least one non-static data
|
2011-04-30 18:07:30 +08:00
|
|
|
// member. If IsStandardLayout remains true, then the first non-static
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
// data member must come through here with Empty still true, and Empty
|
|
|
|
// will subsequently be set to false below.
|
2011-04-30 18:07:30 +08:00
|
|
|
if (data().IsStandardLayout && data().Empty) {
|
2014-03-13 23:41:46 +08:00
|
|
|
for (const auto &BI : bases()) {
|
|
|
|
if (Context.hasSameUnqualifiedType(BI.getType(), T)) {
|
2011-04-30 18:07:30 +08:00
|
|
|
data().IsStandardLayout = false;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-05-13 09:05:07 +08:00
|
|
|
|
|
|
|
// Keep track of the presence of mutable fields.
|
|
|
|
if (FieldRec->hasMutableFields())
|
|
|
|
data().HasMutableFields = true;
|
2011-12-22 10:22:31 +08:00
|
|
|
|
|
|
|
// C++11 [class.copy]p13:
|
|
|
|
// If the implicitly-defined constructor would satisfy the
|
|
|
|
// requirements of a constexpr constructor, the implicitly-defined
|
|
|
|
// constructor is constexpr.
|
|
|
|
// C++11 [dcl.constexpr]p4:
|
|
|
|
// -- every constructor involved in initializing non-static data
|
|
|
|
// members [...] shall be a constexpr constructor
|
|
|
|
if (!Field->hasInClassInitializer() &&
|
2012-05-07 09:07:30 +08:00
|
|
|
!FieldRec->hasConstexprDefaultConstructor() && !isUnion())
|
2011-12-22 10:22:31 +08:00
|
|
|
// The standard requires any in-class initializer to be a constant
|
|
|
|
// expression. We consider this to be a defect.
|
|
|
|
data().DefaultedDefaultConstructorIsConstexpr = false;
|
2012-11-28 14:23:12 +08:00
|
|
|
|
|
|
|
// C++11 [class.copy]p8:
|
|
|
|
// The implicitly-declared copy constructor for a class X will have
|
|
|
|
// the form 'X::X(const X&)' if [...] for all the non-static data
|
|
|
|
// members of X that are of a class type M (or array thereof), each
|
|
|
|
// such class type has a copy constructor whose first parameter is
|
|
|
|
// of type 'const M&' or 'const volatile M&'.
|
|
|
|
if (!FieldRec->hasCopyConstructorWithConstParam())
|
|
|
|
data().ImplicitCopyConstructorHasConstParam = false;
|
|
|
|
|
|
|
|
// C++11 [class.copy]p18:
|
|
|
|
// The implicitly-declared copy assignment oeprator for a class X will
|
|
|
|
// have the form 'X& X::operator=(const X&)' if [...] for all the
|
|
|
|
// non-static data members of X that are of a class type M (or array
|
|
|
|
// thereof), each such class type has a copy assignment operator whose
|
|
|
|
// parameter is of type 'const M&', 'const volatile M&' or 'M'.
|
|
|
|
if (!FieldRec->hasCopyAssignmentWithConstParam())
|
|
|
|
data().ImplicitCopyAssignmentHasConstParam = false;
|
2012-12-08 10:01:17 +08:00
|
|
|
|
|
|
|
if (FieldRec->hasUninitializedReferenceMember() &&
|
|
|
|
!Field->hasInClassInitializer())
|
|
|
|
data().HasUninitializedReferenceMember = true;
|
2013-12-10 16:25:00 +08:00
|
|
|
|
|
|
|
// C++11 [class.union]p8, DR1460:
|
|
|
|
// a non-static data member of an anonymous union that is a member of
|
|
|
|
// X is also a variant member of X.
|
|
|
|
if (FieldRec->hasVariantMembers() &&
|
|
|
|
Field->isAnonymousStructOrUnion())
|
|
|
|
data().HasVariantMembers = true;
|
2010-09-29 04:50:54 +08:00
|
|
|
}
|
2011-12-22 10:22:31 +08:00
|
|
|
} else {
|
|
|
|
// Base element type of field is a non-class type.
|
2013-04-22 23:31:51 +08:00
|
|
|
if (!T->isLiteralType(Context) ||
|
2012-06-10 15:07:24 +08:00
|
|
|
(!Field->hasInClassInitializer() && !isUnion()))
|
2011-12-22 10:22:31 +08:00
|
|
|
data().DefaultedDefaultConstructorIsConstexpr = false;
|
2012-12-08 16:32:28 +08:00
|
|
|
|
|
|
|
// C++11 [class.copy]p23:
|
|
|
|
// A defaulted copy/move assignment operator for a class X is defined
|
|
|
|
// as deleted if X has:
|
|
|
|
// -- a non-static data member of const non-class type (or array
|
|
|
|
// thereof)
|
|
|
|
if (T.isConstQualified())
|
|
|
|
data().DefaultedMoveAssignmentIsDeleted = true;
|
2010-09-29 04:50:54 +08:00
|
|
|
}
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
|
|
|
|
// C++0x [class]p7:
|
|
|
|
// A standard-layout class is a class that:
|
|
|
|
// [...]
|
|
|
|
// -- either has no non-static data members in the most derived
|
|
|
|
// class and at most one base class with non-static data members,
|
|
|
|
// or has no base classes with non-static data members, and
|
|
|
|
// At this point we know that we have a non-static data member, so the last
|
|
|
|
// clause holds.
|
|
|
|
if (!data().HasNoNonEmptyBases)
|
2011-04-30 18:07:30 +08:00
|
|
|
data().IsStandardLayout = false;
|
Completely re-implement the core logic behind the __is_standard_layout
type trait. The previous implementation suffered from several problems:
1) It implemented all of the logic in RecordType by walking over every
base and field in a CXXRecordDecl and validating the constraints of
the standard. This made for very straightforward code, but is
extremely inefficient. It also is conceptually wrong, the logic tied
to the C++ definition of standard-layout classes should be in
CXXRecordDecl, not RecordType.
2) To address the performance problems with #1, a cache bit was added to
CXXRecordDecl, and at the completion of every C++ class, the
RecordType was queried to determine if it was a standard layout
class, and that state was cached. Two things went very very wrong
with this. First, the caching version of the query *was never
called*. Even within the recursive steps of the walk over all fields
and bases the caching variant was not called, making each query
a full *recursive* walk. Second, despite the cache not being used, it
was computed for every class declared, even when the trait was never
used in the program. This probably significantly regressed compile
time performance for edge-case files.
3) An ASTContext was required merely to query the type trait because
querying it performed the actual computations.
4) The caching bit wasn't managed correctly (uninitialized).
The new implementation follows the system for all the other traits on
C++ classes by encoding all the state needed in the definition data and
building up the trait incrementally as each base and member are added to
the definition of the class.
The idiosyncracies of the specification of standard-layout classes
requires more state than I would like; currently 5 bits. I could
eliminate one of the bits easily at the expense of both clarity and
resilience of the code. I might be able to eliminate one of the other
bits by computing its state in terms of other state bits in the
definition. I've already done that in one place where there was a fairly
simple way to achieve it.
It's possible some of the bits could be moved out of the definition data
and into some other structure which isn't serialized if the serialized
bloat is a problem. That would preclude serialization of a partial class
declaration, but that's likely already precluded.
Comments on any of these issues welcome.
llvm-svn: 130601
2011-04-30 17:17:45 +08:00
|
|
|
|
2010-09-29 04:38:10 +08:00
|
|
|
// If this is not a zero-length bit-field, then the class is not empty.
|
|
|
|
if (data().Empty) {
|
2011-10-11 02:28:20 +08:00
|
|
|
if (!Field->isBitField() ||
|
|
|
|
(!Field->getBitWidth()->isTypeDependent() &&
|
|
|
|
!Field->getBitWidth()->isValueDependent() &&
|
|
|
|
Field->getBitWidthValue(Context) != 0))
|
2010-09-29 04:38:10 +08:00
|
|
|
data().Empty = false;
|
|
|
|
}
|
2010-09-29 03:45:33 +08:00
|
|
|
}
|
2010-09-29 12:25:11 +08:00
|
|
|
|
|
|
|
// Handle using declarations of conversion functions.
|
2013-08-30 12:46:40 +08:00
|
|
|
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) {
|
2010-09-29 12:25:11 +08:00
|
|
|
if (Shadow->getDeclName().getNameKind()
|
2013-08-30 12:46:40 +08:00
|
|
|
== DeclarationName::CXXConversionFunctionName) {
|
|
|
|
ASTContext &Ctx = getASTContext();
|
|
|
|
data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess());
|
|
|
|
}
|
|
|
|
}
|
2012-09-01 06:18:20 +08:00
|
|
|
}
|
|
|
|
|
2012-12-08 10:53:02 +08:00
|
|
|
void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
|
|
|
|
assert(!D->isImplicit() && !D->isUserProvided());
|
|
|
|
|
|
|
|
// The kind of special member this declaration is, if any.
|
|
|
|
unsigned SMKind = 0;
|
|
|
|
|
|
|
|
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
|
|
|
if (Constructor->isDefaultConstructor()) {
|
|
|
|
SMKind |= SMF_DefaultConstructor;
|
|
|
|
if (Constructor->isConstexpr())
|
|
|
|
data().HasConstexprDefaultConstructor = true;
|
|
|
|
}
|
|
|
|
if (Constructor->isCopyConstructor())
|
|
|
|
SMKind |= SMF_CopyConstructor;
|
|
|
|
else if (Constructor->isMoveConstructor())
|
|
|
|
SMKind |= SMF_MoveConstructor;
|
|
|
|
else if (Constructor->isConstexpr())
|
|
|
|
// We may now know that the constructor is constexpr.
|
|
|
|
data().HasConstexprNonCopyMoveConstructor = true;
|
|
|
|
} else if (isa<CXXDestructorDecl>(D))
|
|
|
|
SMKind |= SMF_Destructor;
|
|
|
|
else if (D->isCopyAssignmentOperator())
|
|
|
|
SMKind |= SMF_CopyAssignment;
|
|
|
|
else if (D->isMoveAssignmentOperator())
|
|
|
|
SMKind |= SMF_MoveAssignment;
|
|
|
|
|
|
|
|
// Update which trivial / non-trivial special members we have.
|
|
|
|
// addedMember will have skipped this step for this member.
|
|
|
|
if (D->isTrivial())
|
|
|
|
data().HasTrivialSpecialMembers |= SMKind;
|
|
|
|
else
|
|
|
|
data().DeclaredNonTrivialSpecialMembers |= SMKind;
|
|
|
|
}
|
|
|
|
|
2012-09-01 06:18:20 +08:00
|
|
|
bool CXXRecordDecl::isCLike() const {
|
|
|
|
if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface ||
|
|
|
|
!TemplateOrInstantiation.isNull())
|
|
|
|
return false;
|
|
|
|
if (!hasDefinition())
|
|
|
|
return true;
|
2012-01-24 00:58:45 +08:00
|
|
|
|
2012-02-01 14:36:44 +08:00
|
|
|
return isPOD() && data().HasOnlyCMembers;
|
2012-01-24 00:58:45 +08:00
|
|
|
}
|
2013-10-24 00:10:50 +08:00
|
|
|
|
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- generic lambdas within template functions and nested
within other generic lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
(Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)
As an example of what compiles through this commit:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
generate a template-parameter-type when 'auto' is parsed in a generic
lambda parameter context. (i.e we do NOT use AutoType deduced to
a template parameter type - Richard seemed ok with this approach).
We encode that this template type was generated from an auto by simply
adding $auto to the name which can be used for better diagnostics if needed.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- various tests were added - but much more will be needed.
There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.
A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 191453
2013-09-27 03:54:12 +08:00
|
|
|
bool CXXRecordDecl::isGenericLambda() const {
|
2013-10-24 00:10:50 +08:00
|
|
|
if (!isLambda()) return false;
|
|
|
|
return getLambdaData().IsGenericLambda;
|
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- generic lambdas within template functions and nested
within other generic lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
(Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)
As an example of what compiles through this commit:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
generate a template-parameter-type when 'auto' is parsed in a generic
lambda parameter context. (i.e we do NOT use AutoType deduced to
a template parameter type - Richard seemed ok with this approach).
We encode that this template type was generated from an auto by simply
adding $auto to the name which can be used for better diagnostics if needed.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- various tests were added - but much more will be needed.
There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.
A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 191453
2013-09-27 03:54:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
|
|
|
|
if (!isLambda()) return 0;
|
2013-09-30 01:08:32 +08:00
|
|
|
DeclarationName Name =
|
|
|
|
getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
|
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- generic lambdas within template functions and nested
within other generic lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
(Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)
As an example of what compiles through this commit:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
generate a template-parameter-type when 'auto' is parsed in a generic
lambda parameter context. (i.e we do NOT use AutoType deduced to
a template parameter type - Richard seemed ok with this approach).
We encode that this template type was generated from an auto by simply
adding $auto to the name which can be used for better diagnostics if needed.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- various tests were added - but much more will be needed.
There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.
A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 191453
2013-09-27 03:54:12 +08:00
|
|
|
DeclContext::lookup_const_result Calls = lookup(Name);
|
2013-09-30 01:08:32 +08:00
|
|
|
|
|
|
|
assert(!Calls.empty() && "Missing lambda call operator!");
|
|
|
|
assert(Calls.size() == 1 && "More than one lambda call operator!");
|
|
|
|
|
|
|
|
NamedDecl *CallOp = Calls.front();
|
|
|
|
if (FunctionTemplateDecl *CallOpTmpl =
|
|
|
|
dyn_cast<FunctionTemplateDecl>(CallOp))
|
|
|
|
return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
|
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- generic lambdas within template functions and nested
within other generic lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
(Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)
As an example of what compiles through this commit:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
generate a template-parameter-type when 'auto' is parsed in a generic
lambda parameter context. (i.e we do NOT use AutoType deduced to
a template parameter type - Richard seemed ok with this approach).
We encode that this template type was generated from an auto by simply
adding $auto to the name which can be used for better diagnostics if needed.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- various tests were added - but much more will be needed.
There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.
A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 191453
2013-09-27 03:54:12 +08:00
|
|
|
|
|
|
|
return cast<CXXMethodDecl>(CallOp);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
|
|
|
|
if (!isLambda()) return 0;
|
2013-09-30 01:08:32 +08:00
|
|
|
DeclarationName Name =
|
|
|
|
&getASTContext().Idents.get(getLambdaStaticInvokerName());
|
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- generic lambdas within template functions and nested
within other generic lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
(Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)
As an example of what compiles through this commit:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
generate a template-parameter-type when 'auto' is parsed in a generic
lambda parameter context. (i.e we do NOT use AutoType deduced to
a template parameter type - Richard seemed ok with this approach).
We encode that this template type was generated from an auto by simply
adding $auto to the name which can be used for better diagnostics if needed.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- various tests were added - but much more will be needed.
There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.
A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 191453
2013-09-27 03:54:12 +08:00
|
|
|
DeclContext::lookup_const_result Invoker = lookup(Name);
|
2013-09-30 01:08:32 +08:00
|
|
|
if (Invoker.empty()) return 0;
|
|
|
|
assert(Invoker.size() == 1 && "More than one static invoker operator!");
|
|
|
|
NamedDecl *InvokerFun = Invoker.front();
|
|
|
|
if (FunctionTemplateDecl *InvokerTemplate =
|
|
|
|
dyn_cast<FunctionTemplateDecl>(InvokerFun))
|
|
|
|
return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());
|
|
|
|
|
2013-09-29 16:45:24 +08:00
|
|
|
return cast<CXXMethodDecl>(InvokerFun);
|
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- generic lambdas within template functions and nested
within other generic lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
(Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)
As an example of what compiles through this commit:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
generate a template-parameter-type when 'auto' is parsed in a generic
lambda parameter context. (i.e we do NOT use AutoType deduced to
a template parameter type - Richard seemed ok with this approach).
We encode that this template type was generated from an auto by simply
adding $auto to the name which can be used for better diagnostics if needed.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- various tests were added - but much more will be needed.
There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.
A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 191453
2013-09-27 03:54:12 +08:00
|
|
|
}
|
|
|
|
|
2012-02-10 15:45:31 +08:00
|
|
|
void CXXRecordDecl::getCaptureFields(
|
|
|
|
llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
|
2012-02-11 08:18:00 +08:00
|
|
|
FieldDecl *&ThisCapture) const {
|
2012-02-10 15:45:31 +08:00
|
|
|
Captures.clear();
|
|
|
|
ThisCapture = 0;
|
|
|
|
|
2012-02-13 23:44:47 +08:00
|
|
|
LambdaDefinitionData &Lambda = getLambdaData();
|
2012-02-10 15:45:31 +08:00
|
|
|
RecordDecl::field_iterator Field = field_begin();
|
2012-02-14 01:20:40 +08:00
|
|
|
for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
|
2012-02-10 15:45:31 +08:00
|
|
|
C != CEnd; ++C, ++Field) {
|
2013-05-16 14:20:58 +08:00
|
|
|
if (C->capturesThis())
|
2012-06-07 04:45:41 +08:00
|
|
|
ThisCapture = *Field;
|
2013-05-16 14:20:58 +08:00
|
|
|
else if (C->capturesVariable())
|
|
|
|
Captures[C->getCapturedVar()] = *Field;
|
2012-02-10 15:45:31 +08:00
|
|
|
}
|
2013-09-28 12:02:39 +08:00
|
|
|
assert(Field == field_end());
|
2012-02-10 15:45:31 +08:00
|
|
|
}
|
|
|
|
|
Implement a rudimentary form of generic lambdas.
Specifically, the following features are not included in this commit:
- any sort of capturing within generic lambdas
- generic lambdas within template functions and nested
within other generic lambdas
- conversion operator for captureless lambdas
- ensuring all visitors are generic lambda aware
(Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)
As an example of what compiles through this commit:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).
Some implementation notes:
- Add a new Declarator context => LambdaExprParameterContext to
clang::Declarator to allow the use of 'auto' in declaring generic
lambda parameters
- Add various helpers to CXXRecordDecl to facilitate identifying
and querying a closure class
- LambdaScopeInfo (which maintains the current lambda's Sema state)
was augmented to house the current depth of the template being
parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
generate a template-parameter-type when 'auto' is parsed in a generic
lambda parameter context. (i.e we do NOT use AutoType deduced to
a template parameter type - Richard seemed ok with this approach).
We encode that this template type was generated from an auto by simply
adding $auto to the name which can be used for better diagnostics if needed.
- SemaLambda.h was added to hold some common lambda utility
functions (this file is likely to grow ...)
- Teach Sema::ActOnStartOfFunctionDef to check whether it
is being called to instantiate a generic lambda's call
operator, and if so, push an appropriately prepared
LambdaScopeInfo object on the stack.
- various tests were added - but much more will be needed.
There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.
A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!
Thanks!
llvm-svn: 191453
2013-09-27 03:54:12 +08:00
|
|
|
TemplateParameterList *
|
|
|
|
CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
|
|
|
|
if (!isLambda()) return 0;
|
|
|
|
CXXMethodDecl *CallOp = getLambdaCallOperator();
|
|
|
|
if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
|
|
|
|
return Tmpl->getTemplateParameters();
|
|
|
|
return 0;
|
|
|
|
}
|
2012-02-10 15:45:31 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
|
2014-01-22 15:29:52 +08:00
|
|
|
QualType T =
|
|
|
|
cast<CXXConversionDecl>(Conv->getUnderlyingDecl()->getAsFunction())
|
|
|
|
->getConversionType();
|
2010-03-15 17:07:48 +08:00
|
|
|
return Context.getCanonicalType(T);
|
2009-10-08 04:43:36 +08:00
|
|
|
}
|
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
/// Collect the visible conversions of a base class.
|
|
|
|
///
|
2012-06-16 06:28:09 +08:00
|
|
|
/// \param Record a base class of the class we're considering
|
2010-03-15 17:07:48 +08:00
|
|
|
/// \param InVirtual whether this base class is a virtual base (or a base
|
|
|
|
/// of a virtual base)
|
|
|
|
/// \param Access the access along the inheritance path to this base
|
|
|
|
/// \param ParentHiddenTypes the conversions provided by the inheritors
|
|
|
|
/// of this base
|
|
|
|
/// \param Output the set to which to add conversions from non-virtual bases
|
|
|
|
/// \param VOutput the set to which to add conversions from virtual bases
|
|
|
|
/// \param HiddenVBaseCs the set of conversions which were hidden in a
|
|
|
|
/// virtual base along some inheritance path
|
|
|
|
static void CollectVisibleConversions(ASTContext &Context,
|
|
|
|
CXXRecordDecl *Record,
|
|
|
|
bool InVirtual,
|
|
|
|
AccessSpecifier Access,
|
|
|
|
const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
|
2012-11-28 11:56:16 +08:00
|
|
|
ASTUnresolvedSet &Output,
|
2010-03-15 17:07:48 +08:00
|
|
|
UnresolvedSetImpl &VOutput,
|
|
|
|
llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
|
|
|
|
// The set of types which have conversions in this class or its
|
|
|
|
// subclasses. As an optimization, we don't copy the derived set
|
|
|
|
// unless it might change.
|
|
|
|
const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes;
|
|
|
|
llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer;
|
|
|
|
|
|
|
|
// Collect the direct conversions and figure out which conversions
|
|
|
|
// will be hidden in the subclasses.
|
2012-11-28 11:56:09 +08:00
|
|
|
CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin();
|
|
|
|
CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end();
|
|
|
|
if (ConvI != ConvE) {
|
2010-03-15 17:07:48 +08:00
|
|
|
HiddenTypesBuffer = ParentHiddenTypes;
|
|
|
|
HiddenTypes = &HiddenTypesBuffer;
|
|
|
|
|
2012-11-28 11:56:09 +08:00
|
|
|
for (CXXRecordDecl::conversion_iterator I = ConvI; I != ConvE; ++I) {
|
2012-05-06 08:04:32 +08:00
|
|
|
CanQualType ConvType(GetConversionType(Context, I.getDecl()));
|
|
|
|
bool Hidden = ParentHiddenTypes.count(ConvType);
|
|
|
|
if (!Hidden)
|
|
|
|
HiddenTypesBuffer.insert(ConvType);
|
2010-03-15 17:07:48 +08:00
|
|
|
|
|
|
|
// If this conversion is hidden and we're in a virtual base,
|
|
|
|
// remember that it's hidden along some inheritance path.
|
|
|
|
if (Hidden && InVirtual)
|
|
|
|
HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()));
|
|
|
|
|
|
|
|
// If this conversion isn't hidden, add it to the appropriate output.
|
|
|
|
else if (!Hidden) {
|
|
|
|
AccessSpecifier IAccess
|
|
|
|
= CXXRecordDecl::MergeAccess(Access, I.getAccess());
|
|
|
|
|
|
|
|
if (InVirtual)
|
|
|
|
VOutput.addDecl(I.getDecl(), IAccess);
|
2009-09-13 02:26:03 +08:00
|
|
|
else
|
2012-11-28 11:56:16 +08:00
|
|
|
Output.addDecl(Context, I.getDecl(), IAccess);
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
// Collect information recursively from any base classes.
|
2014-03-13 23:41:46 +08:00
|
|
|
for (const auto &I : Record->bases()) {
|
|
|
|
const RecordType *RT = I.getType()->getAs<RecordType>();
|
2010-03-15 17:07:48 +08:00
|
|
|
if (!RT) continue;
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
AccessSpecifier BaseAccess
|
2014-03-13 23:41:46 +08:00
|
|
|
= CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier());
|
|
|
|
bool BaseInVirtual = InVirtual || I.isVirtual();
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess,
|
|
|
|
*HiddenTypes, Output, VOutput, HiddenVBaseCs);
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
2010-03-15 17:07:48 +08:00
|
|
|
}
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
/// Collect the visible conversions of a class.
|
|
|
|
///
|
|
|
|
/// This would be extremely straightforward if it weren't for virtual
|
|
|
|
/// bases. It might be worth special-casing that, really.
|
|
|
|
static void CollectVisibleConversions(ASTContext &Context,
|
|
|
|
CXXRecordDecl *Record,
|
2012-11-28 11:56:16 +08:00
|
|
|
ASTUnresolvedSet &Output) {
|
2010-03-15 17:07:48 +08:00
|
|
|
// The collection of all conversions in virtual bases that we've
|
|
|
|
// found. These will be added to the output as long as they don't
|
|
|
|
// appear in the hidden-conversions set.
|
|
|
|
UnresolvedSet<8> VBaseCs;
|
|
|
|
|
|
|
|
// The set of conversions in virtual bases that we've determined to
|
|
|
|
// be hidden.
|
|
|
|
llvm::SmallPtrSet<NamedDecl*, 8> HiddenVBaseCs;
|
|
|
|
|
|
|
|
// The set of types hidden by classes derived from this one.
|
|
|
|
llvm::SmallPtrSet<CanQualType, 8> HiddenTypes;
|
|
|
|
|
|
|
|
// Go ahead and collect the direct conversions and add them to the
|
|
|
|
// hidden-types set.
|
2012-11-28 11:56:09 +08:00
|
|
|
CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin();
|
|
|
|
CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end();
|
2012-11-28 11:56:16 +08:00
|
|
|
Output.append(Context, ConvI, ConvE);
|
2012-11-28 11:56:09 +08:00
|
|
|
for (; ConvI != ConvE; ++ConvI)
|
|
|
|
HiddenTypes.insert(GetConversionType(Context, ConvI.getDecl()));
|
2010-03-15 17:07:48 +08:00
|
|
|
|
|
|
|
// Recursively collect conversions from base classes.
|
2014-03-13 23:41:46 +08:00
|
|
|
for (const auto &I : Record->bases()) {
|
|
|
|
const RecordType *RT = I.getType()->getAs<RecordType>();
|
2010-03-15 17:07:48 +08:00
|
|
|
if (!RT) continue;
|
|
|
|
|
|
|
|
CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()),
|
2014-03-13 23:41:46 +08:00
|
|
|
I.isVirtual(), I.getAccessSpecifier(),
|
2010-03-15 17:07:48 +08:00
|
|
|
HiddenTypes, Output, VBaseCs, HiddenVBaseCs);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add any unhidden conversions provided by virtual bases.
|
|
|
|
for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())))
|
2012-11-28 11:56:16 +08:00
|
|
|
Output.addDecl(Context, I.getDecl(), I.getAccess());
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
2009-09-13 02:26:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getVisibleConversionFunctions - get all conversion functions visible
|
|
|
|
/// in current class; including conversion function templates.
|
2012-11-28 11:56:09 +08:00
|
|
|
std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator>
|
|
|
|
CXXRecordDecl::getVisibleConversionFunctions() {
|
2013-08-30 12:46:40 +08:00
|
|
|
ASTContext &Ctx = getASTContext();
|
|
|
|
|
|
|
|
ASTUnresolvedSet *Set;
|
|
|
|
if (bases_begin() == bases_end()) {
|
|
|
|
// If root class, all conversions are visible.
|
|
|
|
Set = &data().Conversions.get(Ctx);
|
|
|
|
} else {
|
|
|
|
Set = &data().VisibleConversions.get(Ctx);
|
|
|
|
// If visible conversion list is not evaluated, evaluate it.
|
|
|
|
if (!data().ComputedVisibleConversions) {
|
|
|
|
CollectVisibleConversions(Ctx, this, *Set);
|
|
|
|
data().ComputedVisibleConversions = true;
|
|
|
|
}
|
2012-11-28 11:56:09 +08:00
|
|
|
}
|
2013-08-30 12:46:40 +08:00
|
|
|
return std::make_pair(Set->begin(), Set->end());
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
|
|
|
|
2010-03-31 09:36:47 +08:00
|
|
|
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
|
|
|
|
// This operation is O(N) but extremely rare. Sema only uses it to
|
|
|
|
// remove UsingShadowDecls in a class that were followed by a direct
|
|
|
|
// declaration, e.g.:
|
|
|
|
// class A : B {
|
|
|
|
// using B::operator int;
|
|
|
|
// operator int();
|
|
|
|
// };
|
|
|
|
// This is uncommon by itself and even more uncommon in conjunction
|
|
|
|
// with sufficiently large numbers of directly-declared conversions
|
|
|
|
// that asymptotic behavior matters.
|
|
|
|
|
2013-08-30 12:46:40 +08:00
|
|
|
ASTUnresolvedSet &Convs = data().Conversions.get(getASTContext());
|
2010-03-31 09:36:47 +08:00
|
|
|
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
|
|
|
|
if (Convs[I].getDecl() == ConvDecl) {
|
|
|
|
Convs.erase(I);
|
|
|
|
assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end()
|
|
|
|
&& "conversion was found multiple times in unresolved set");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2008-11-08 04:08:42 +08:00
|
|
|
|
2010-03-31 09:36:47 +08:00
|
|
|
llvm_unreachable("conversion not found in set!");
|
2009-08-22 07:19:43 +08:00
|
|
|
}
|
2009-06-20 03:55:27 +08:00
|
|
|
|
2009-10-08 23:14:33 +08:00
|
|
|
CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
|
2009-10-13 04:18:28 +08:00
|
|
|
if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo())
|
2009-10-08 23:14:33 +08:00
|
|
|
return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
|
|
|
|
TemplateSpecializationKind TSK) {
|
|
|
|
assert(TemplateOrInstantiation.isNull() &&
|
|
|
|
"Previous template or instantiation?");
|
2013-12-14 09:04:22 +08:00
|
|
|
assert(!isa<ClassTemplatePartialSpecializationDecl>(this));
|
2009-10-08 23:14:33 +08:00
|
|
|
TemplateOrInstantiation
|
|
|
|
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
|
|
|
|
}
|
|
|
|
|
2009-12-07 14:33:48 +08:00
|
|
|
TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{
|
|
|
|
if (const ClassTemplateSpecializationDecl *Spec
|
2009-10-08 23:14:33 +08:00
|
|
|
= dyn_cast<ClassTemplateSpecializationDecl>(this))
|
|
|
|
return Spec->getSpecializationKind();
|
|
|
|
|
2009-10-13 04:18:28 +08:00
|
|
|
if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo())
|
2009-10-08 23:14:33 +08:00
|
|
|
return MSInfo->getTemplateSpecializationKind();
|
|
|
|
|
|
|
|
return TSK_Undeclared;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
|
|
|
|
if (ClassTemplateSpecializationDecl *Spec
|
|
|
|
= dyn_cast<ClassTemplateSpecializationDecl>(this)) {
|
|
|
|
Spec->setSpecializationKind(TSK);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-13 04:18:28 +08:00
|
|
|
if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) {
|
2009-10-08 23:14:33 +08:00
|
|
|
MSInfo->setTemplateSpecializationKind(TSK);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Not a class template or member class specialization");
|
2009-10-08 23:14:33 +08:00
|
|
|
}
|
|
|
|
|
2010-07-01 22:13:13 +08:00
|
|
|
CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
|
|
|
|
ASTContext &Context = getASTContext();
|
2009-05-30 05:03:38 +08:00
|
|
|
QualType ClassType = Context.getTypeDeclType(this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
DeclarationName Name
|
2009-08-05 13:36:45 +08:00
|
|
|
= Context.DeclarationNames.getCXXDestructorName(
|
|
|
|
Context.getCanonicalType(ClassType));
|
2009-05-30 05:03:38 +08:00
|
|
|
|
2012-12-19 08:45:41 +08:00
|
|
|
DeclContext::lookup_const_result R = lookup(Name);
|
|
|
|
if (R.empty())
|
2010-09-03 07:19:42 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-12-19 08:45:41 +08:00
|
|
|
CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front());
|
2009-05-30 05:03:38 +08:00
|
|
|
return Dtor;
|
|
|
|
}
|
|
|
|
|
2011-02-20 02:51:44 +08:00
|
|
|
void CXXRecordDecl::completeDefinition() {
|
|
|
|
completeDefinition(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
|
|
|
|
RecordDecl::completeDefinition();
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (hasObjectMember() && getASTContext().getLangOpts().ObjCAutoRefCount) {
|
2011-06-16 07:02:42 +08:00
|
|
|
// Objective-C Automatic Reference Counting:
|
|
|
|
// If a class has a non-static data member of Objective-C pointer
|
|
|
|
// type (or array thereof), it is a non-POD type and its
|
2012-07-23 12:23:39 +08:00
|
|
|
// default constructor (if any), copy constructor, move constructor,
|
|
|
|
// copy assignment operator, move assignment operator, and destructor are
|
|
|
|
// non-trivial.
|
2011-06-16 07:02:42 +08:00
|
|
|
struct DefinitionData &Data = data();
|
|
|
|
Data.PlainOldData = false;
|
2012-11-30 13:11:39 +08:00
|
|
|
Data.HasTrivialSpecialMembers = 0;
|
2012-02-25 15:33:38 +08:00
|
|
|
Data.HasIrrelevantDestructor = false;
|
2011-06-16 07:02:42 +08:00
|
|
|
}
|
|
|
|
|
2010-09-29 08:15:42 +08:00
|
|
|
// If the class may be abstract (but hasn't been marked as such), check for
|
|
|
|
// any pure final overriders.
|
|
|
|
if (mayBeAbstract()) {
|
|
|
|
CXXFinalOverriderMap MyFinalOverriders;
|
|
|
|
if (!FinalOverriders) {
|
|
|
|
getFinalOverriders(MyFinalOverriders);
|
|
|
|
FinalOverriders = &MyFinalOverriders;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Done = false;
|
|
|
|
for (CXXFinalOverriderMap::iterator M = FinalOverriders->begin(),
|
|
|
|
MEnd = FinalOverriders->end();
|
|
|
|
M != MEnd && !Done; ++M) {
|
|
|
|
for (OverridingMethods::iterator SO = M->second.begin(),
|
|
|
|
SOEnd = M->second.end();
|
|
|
|
SO != SOEnd && !Done; ++SO) {
|
|
|
|
assert(SO->second.size() > 0 &&
|
|
|
|
"All virtual functions have overridding virtual functions");
|
|
|
|
|
|
|
|
// C++ [class.abstract]p4:
|
|
|
|
// A class is abstract if it contains or inherits at least one
|
|
|
|
// pure virtual function for which the final overrider is pure
|
|
|
|
// virtual.
|
|
|
|
if (SO->second.front().Method->isPure()) {
|
|
|
|
data().Abstract = true;
|
|
|
|
Done = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-29 12:25:11 +08:00
|
|
|
|
|
|
|
// Set access bits correctly on the directly-declared conversions.
|
2013-08-30 12:46:40 +08:00
|
|
|
for (conversion_iterator I = conversion_begin(), E = conversion_end();
|
2010-09-29 12:25:11 +08:00
|
|
|
I != E; ++I)
|
2012-11-28 11:56:16 +08:00
|
|
|
I.setAccess((*I)->getAccess());
|
2010-09-29 08:15:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CXXRecordDecl::mayBeAbstract() const {
|
|
|
|
if (data().Abstract || isInvalidDecl() || !data().Polymorphic ||
|
|
|
|
isDependentContext())
|
|
|
|
return false;
|
|
|
|
|
2014-03-13 23:41:46 +08:00
|
|
|
for (const auto &B : bases()) {
|
2010-09-29 08:15:42 +08:00
|
|
|
CXXRecordDecl *BaseDecl
|
2014-03-13 23:41:46 +08:00
|
|
|
= cast<CXXRecordDecl>(B.getType()->getAs<RecordType>()->getDecl());
|
2010-09-29 08:15:42 +08:00
|
|
|
if (BaseDecl->isAbstract())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void CXXMethodDecl::anchor() { }
|
|
|
|
|
2013-04-04 03:27:57 +08:00
|
|
|
bool CXXMethodDecl::isStatic() const {
|
2013-04-15 20:38:20 +08:00
|
|
|
const CXXMethodDecl *MD = getCanonicalDecl();
|
2013-04-04 03:27:57 +08:00
|
|
|
|
|
|
|
if (MD->getStorageClass() == SC_Static)
|
|
|
|
return true;
|
|
|
|
|
2013-10-08 08:58:57 +08:00
|
|
|
OverloadedOperatorKind OOK = getDeclName().getCXXOverloadedOperator();
|
|
|
|
return isStaticOverloadedOperator(OOK);
|
2013-04-04 03:27:57 +08:00
|
|
|
}
|
|
|
|
|
2012-06-27 01:45:31 +08:00
|
|
|
static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
|
|
|
|
const CXXMethodDecl *BaseMD) {
|
|
|
|
for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(),
|
|
|
|
E = DerivedMD->end_overridden_methods(); I != E; ++I) {
|
|
|
|
const CXXMethodDecl *MD = *I;
|
|
|
|
if (MD->getCanonicalDecl() == BaseMD->getCanonicalDecl())
|
|
|
|
return true;
|
|
|
|
if (recursivelyOverrides(MD, BaseMD))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl *
|
2012-08-16 04:07:17 +08:00
|
|
|
CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
|
|
|
|
bool MayBeBase) {
|
2012-06-27 01:45:31 +08:00
|
|
|
if (this->getParent()->getCanonicalDecl() == RD->getCanonicalDecl())
|
|
|
|
return this;
|
|
|
|
|
|
|
|
// Lookup doesn't work for destructors, so handle them separately.
|
|
|
|
if (isa<CXXDestructorDecl>(this)) {
|
|
|
|
CXXMethodDecl *MD = RD->getDestructor();
|
2012-08-16 04:07:17 +08:00
|
|
|
if (MD) {
|
|
|
|
if (recursivelyOverrides(MD, this))
|
|
|
|
return MD;
|
|
|
|
if (MayBeBase && recursivelyOverrides(this, MD))
|
|
|
|
return MD;
|
|
|
|
}
|
2012-06-27 01:45:31 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
lookup_const_result Candidates = RD->lookup(getDeclName());
|
2012-12-19 08:45:41 +08:00
|
|
|
for (NamedDecl * const * I = Candidates.begin(); I != Candidates.end(); ++I) {
|
2012-06-27 01:45:31 +08:00
|
|
|
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I);
|
|
|
|
if (!MD)
|
|
|
|
continue;
|
|
|
|
if (recursivelyOverrides(MD, this))
|
|
|
|
return MD;
|
2012-08-16 04:07:17 +08:00
|
|
|
if (MayBeBase && recursivelyOverrides(this, MD))
|
|
|
|
return MD;
|
2012-06-27 01:45:31 +08:00
|
|
|
}
|
|
|
|
|
2014-03-13 23:41:46 +08:00
|
|
|
for (const auto &I : RD->bases()) {
|
|
|
|
const RecordType *RT = I.getType()->getAs<RecordType>();
|
2012-06-27 01:45:31 +08:00
|
|
|
if (!RT)
|
|
|
|
continue;
|
|
|
|
const CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
CXXMethodDecl *T = this->getCorrespondingMethodInClass(Base);
|
|
|
|
if (T)
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
CXXMethodDecl *
|
|
|
|
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2011-03-08 16:55:46 +08:00
|
|
|
SourceLocation StartLoc,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2013-04-04 03:27:57 +08:00
|
|
|
StorageClass SC, bool isInline,
|
2011-08-16 05:04:07 +08:00
|
|
|
bool isConstexpr, SourceLocation EndLocation) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, RD) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo,
|
|
|
|
SC, isInline, isConstexpr, EndLocation);
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) CXXMethodDecl(CXXMethod, 0, SourceLocation(),
|
|
|
|
DeclarationNameInfo(), QualType(), 0,
|
|
|
|
SC_None, false, false, SourceLocation());
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2009-09-30 02:16:17 +08:00
|
|
|
bool CXXMethodDecl::isUsualDeallocationFunction() const {
|
|
|
|
if (getOverloadedOperator() != OO_Delete &&
|
|
|
|
getOverloadedOperator() != OO_Array_Delete)
|
|
|
|
return false;
|
2010-02-26 13:06:18 +08:00
|
|
|
|
|
|
|
// C++ [basic.stc.dynamic.deallocation]p2:
|
|
|
|
// A template instance is never a usual deallocation function,
|
|
|
|
// regardless of its signature.
|
|
|
|
if (getPrimaryTemplate())
|
|
|
|
return false;
|
|
|
|
|
2009-09-30 02:16:17 +08:00
|
|
|
// C++ [basic.stc.dynamic.deallocation]p2:
|
|
|
|
// If a class T has a member deallocation function named operator delete
|
|
|
|
// with exactly one parameter, then that function is a usual (non-placement)
|
|
|
|
// deallocation function. [...]
|
|
|
|
if (getNumParams() == 1)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// C++ [basic.stc.dynamic.deallocation]p2:
|
|
|
|
// [...] If class T does not declare such an operator delete but does
|
|
|
|
// declare a member deallocation function named operator delete with
|
|
|
|
// exactly two parameters, the second of which has type std::size_t (18.1),
|
|
|
|
// then this function is a usual deallocation function.
|
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
if (getNumParams() != 2 ||
|
2010-02-09 02:54:05 +08:00
|
|
|
!Context.hasSameUnqualifiedType(getParamDecl(1)->getType(),
|
|
|
|
Context.getSizeType()))
|
2009-09-30 02:16:17 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// This function is a usual deallocation function if there are no
|
|
|
|
// single-parameter deallocation functions of the same kind.
|
2012-12-19 08:45:41 +08:00
|
|
|
DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
|
|
|
|
for (DeclContext::lookup_const_result::iterator I = R.begin(), E = R.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I))
|
2009-09-30 02:16:17 +08:00
|
|
|
if (FD->getNumParams() == 1)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Complete reimplementation of the synthesis for implicitly-defined copy
assignment operators.
Previously, Sema provided type-checking and template instantiation for
copy assignment operators, then CodeGen would synthesize the actual
body of the copy constructor. Unfortunately, the two were not in sync,
and CodeGen might pick a copy-assignment operator that is different
from what Sema chose, leading to strange failures, e.g., link-time
failures when CodeGen called a copy-assignment operator that was not
instantiation, run-time failures when copy-assignment operators were
overloaded for const/non-const references and the wrong one was
picked, and run-time failures when by-value copy-assignment operators
did not have their arguments properly copy-initialized.
This implementation synthesizes the implicitly-defined copy assignment
operator bodies in Sema, so that the resulting ASTs encode exactly
what CodeGen needs to do; there is no longer any special code in
CodeGen to synthesize copy-assignment operators. The synthesis of the
body is relatively simple, and we generate one of three different
kinds of copy statements for each base or member:
- For a class subobject, call the appropriate copy-assignment
operator, after overload resolution has determined what that is.
- For an array of scalar types or an array of class types that have
trivial copy assignment operators, construct a call to
__builtin_memcpy.
- For an array of class types with non-trivial copy assignment
operators, synthesize a (possibly nested!) for loop whose inner
statement calls the copy constructor.
- For a scalar type, use built-in assignment.
This patch fixes at least a few tests cases in Boost.Spirit that were
failing because CodeGen picked the wrong copy-assignment operator
(leading to link-time failures), and I suspect a number of undiagnosed
problems will also go away with this change.
Some of the diagnostics we had previously have gotten worse with this
change, since we're going through generic code for our
type-checking. I will improve this in a subsequent patch.
llvm-svn: 102853
2010-05-02 04:49:11 +08:00
|
|
|
bool CXXMethodDecl::isCopyAssignmentOperator() const {
|
2011-05-26 04:50:04 +08:00
|
|
|
// C++0x [class.copy]p17:
|
Complete reimplementation of the synthesis for implicitly-defined copy
assignment operators.
Previously, Sema provided type-checking and template instantiation for
copy assignment operators, then CodeGen would synthesize the actual
body of the copy constructor. Unfortunately, the two were not in sync,
and CodeGen might pick a copy-assignment operator that is different
from what Sema chose, leading to strange failures, e.g., link-time
failures when CodeGen called a copy-assignment operator that was not
instantiation, run-time failures when copy-assignment operators were
overloaded for const/non-const references and the wrong one was
picked, and run-time failures when by-value copy-assignment operators
did not have their arguments properly copy-initialized.
This implementation synthesizes the implicitly-defined copy assignment
operator bodies in Sema, so that the resulting ASTs encode exactly
what CodeGen needs to do; there is no longer any special code in
CodeGen to synthesize copy-assignment operators. The synthesis of the
body is relatively simple, and we generate one of three different
kinds of copy statements for each base or member:
- For a class subobject, call the appropriate copy-assignment
operator, after overload resolution has determined what that is.
- For an array of scalar types or an array of class types that have
trivial copy assignment operators, construct a call to
__builtin_memcpy.
- For an array of class types with non-trivial copy assignment
operators, synthesize a (possibly nested!) for loop whose inner
statement calls the copy constructor.
- For a scalar type, use built-in assignment.
This patch fixes at least a few tests cases in Boost.Spirit that were
failing because CodeGen picked the wrong copy-assignment operator
(leading to link-time failures), and I suspect a number of undiagnosed
problems will also go away with this change.
Some of the diagnostics we had previously have gotten worse with this
change, since we're going through generic code for our
type-checking. I will improve this in a subsequent patch.
llvm-svn: 102853
2010-05-02 04:49:11 +08:00
|
|
|
// A user-declared copy assignment operator X::operator= is a non-static
|
|
|
|
// non-template member function of class X with exactly one parameter of
|
|
|
|
// type X, X&, const X&, volatile X& or const volatile X&.
|
|
|
|
if (/*operator=*/getOverloadedOperator() != OO_Equal ||
|
|
|
|
/*non-static*/ isStatic() ||
|
2013-07-12 07:55:07 +08:00
|
|
|
/*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
|
|
|
|
getNumParams() != 1)
|
Complete reimplementation of the synthesis for implicitly-defined copy
assignment operators.
Previously, Sema provided type-checking and template instantiation for
copy assignment operators, then CodeGen would synthesize the actual
body of the copy constructor. Unfortunately, the two were not in sync,
and CodeGen might pick a copy-assignment operator that is different
from what Sema chose, leading to strange failures, e.g., link-time
failures when CodeGen called a copy-assignment operator that was not
instantiation, run-time failures when copy-assignment operators were
overloaded for const/non-const references and the wrong one was
picked, and run-time failures when by-value copy-assignment operators
did not have their arguments properly copy-initialized.
This implementation synthesizes the implicitly-defined copy assignment
operator bodies in Sema, so that the resulting ASTs encode exactly
what CodeGen needs to do; there is no longer any special code in
CodeGen to synthesize copy-assignment operators. The synthesis of the
body is relatively simple, and we generate one of three different
kinds of copy statements for each base or member:
- For a class subobject, call the appropriate copy-assignment
operator, after overload resolution has determined what that is.
- For an array of scalar types or an array of class types that have
trivial copy assignment operators, construct a call to
__builtin_memcpy.
- For an array of class types with non-trivial copy assignment
operators, synthesize a (possibly nested!) for loop whose inner
statement calls the copy constructor.
- For a scalar type, use built-in assignment.
This patch fixes at least a few tests cases in Boost.Spirit that were
failing because CodeGen picked the wrong copy-assignment operator
(leading to link-time failures), and I suspect a number of undiagnosed
problems will also go away with this change.
Some of the diagnostics we had previously have gotten worse with this
change, since we're going through generic code for our
type-checking. I will improve this in a subsequent patch.
llvm-svn: 102853
2010-05-02 04:49:11 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
QualType ParamType = getParamDecl(0)->getType();
|
|
|
|
if (const LValueReferenceType *Ref = ParamType->getAs<LValueReferenceType>())
|
|
|
|
ParamType = Ref->getPointeeType();
|
|
|
|
|
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
QualType ClassType
|
|
|
|
= Context.getCanonicalType(Context.getTypeDeclType(getParent()));
|
|
|
|
return Context.hasSameUnqualifiedType(ClassType, ParamType);
|
|
|
|
}
|
|
|
|
|
2011-05-26 04:50:04 +08:00
|
|
|
bool CXXMethodDecl::isMoveAssignmentOperator() const {
|
|
|
|
// C++0x [class.copy]p19:
|
|
|
|
// A user-declared move assignment operator X::operator= is a non-static
|
|
|
|
// non-template member function of class X with exactly one parameter of type
|
|
|
|
// X&&, const X&&, volatile X&&, or const volatile X&&.
|
|
|
|
if (getOverloadedOperator() != OO_Equal || isStatic() ||
|
2013-07-12 07:55:07 +08:00
|
|
|
getPrimaryTemplate() || getDescribedFunctionTemplate() ||
|
|
|
|
getNumParams() != 1)
|
2011-05-26 04:50:04 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
QualType ParamType = getParamDecl(0)->getType();
|
|
|
|
if (!isa<RValueReferenceType>(ParamType))
|
|
|
|
return false;
|
|
|
|
ParamType = ParamType->getPointeeType();
|
|
|
|
|
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
QualType ClassType
|
|
|
|
= Context.getCanonicalType(Context.getTypeDeclType(getParent()));
|
|
|
|
return Context.hasSameUnqualifiedType(ClassType, ParamType);
|
|
|
|
}
|
|
|
|
|
2009-05-17 07:58:37 +08:00
|
|
|
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
|
2009-12-04 13:51:56 +08:00
|
|
|
assert(MD->isCanonicalDecl() && "Method is not canonical!");
|
2010-01-31 01:42:34 +08:00
|
|
|
assert(!MD->getParent()->isDependentContext() &&
|
|
|
|
"Can't add an overridden method to a class template!");
|
2012-03-10 09:39:01 +08:00
|
|
|
assert(MD->isVirtual() && "Method is not virtual!");
|
2010-01-31 01:42:34 +08:00
|
|
|
|
2010-03-03 07:58:15 +08:00
|
|
|
getASTContext().addOverriddenMethod(this, MD);
|
2009-05-17 07:58:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const {
|
2012-03-10 09:39:01 +08:00
|
|
|
if (isa<CXXConstructorDecl>(this)) return 0;
|
2010-03-03 07:58:15 +08:00
|
|
|
return getASTContext().overridden_methods_begin(this);
|
2009-05-17 07:58:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const {
|
2012-03-10 09:39:01 +08:00
|
|
|
if (isa<CXXConstructorDecl>(this)) return 0;
|
2010-03-03 07:58:15 +08:00
|
|
|
return getASTContext().overridden_methods_end(this);
|
2009-05-17 07:58:37 +08:00
|
|
|
}
|
|
|
|
|
2010-07-05 05:44:35 +08:00
|
|
|
unsigned CXXMethodDecl::size_overridden_methods() const {
|
2012-03-10 09:39:01 +08:00
|
|
|
if (isa<CXXConstructorDecl>(this)) return 0;
|
2010-07-05 05:44:35 +08:00
|
|
|
return getASTContext().overridden_methods_size(this);
|
|
|
|
}
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
QualType CXXMethodDecl::getThisType(ASTContext &C) const {
|
2008-10-25 06:28:18 +08:00
|
|
|
// C++ 9.3.2p1: The type of this in a member function of a class X is X*.
|
|
|
|
// If the member function is declared const, the type of this is const X*,
|
|
|
|
// if the member function is declared volatile, the type of this is
|
|
|
|
// volatile X*, and if the member function is declared const volatile,
|
|
|
|
// the type of this is const volatile X*.
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
assert(isInstance() && "No 'this' for static methods!");
|
2009-06-13 10:59:33 +08:00
|
|
|
|
2010-03-10 11:28:59 +08:00
|
|
|
QualType ClassTy = C.getTypeDeclType(getParent());
|
2009-09-25 03:53:00 +08:00
|
|
|
ClassTy = C.getQualifiedType(ClassTy,
|
|
|
|
Qualifiers::fromCVRMask(getTypeQualifiers()));
|
2009-07-11 05:35:09 +08:00
|
|
|
return C.getPointerType(ClassTy);
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
}
|
|
|
|
|
2009-12-07 04:50:05 +08:00
|
|
|
bool CXXMethodDecl::hasInlineBody() const {
|
2010-01-06 03:06:31 +08:00
|
|
|
// If this function is a template instantiation, look at the template from
|
|
|
|
// which it was instantiated.
|
|
|
|
const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
|
|
|
|
if (!CheckFn)
|
|
|
|
CheckFn = this;
|
|
|
|
|
2009-12-07 04:50:05 +08:00
|
|
|
const FunctionDecl *fn;
|
2010-07-07 19:31:19 +08:00
|
|
|
return CheckFn->hasBody(fn) && !fn->isOutOfLine();
|
2009-12-07 04:50:05 +08:00
|
|
|
}
|
|
|
|
|
2012-02-17 11:02:34 +08:00
|
|
|
bool CXXMethodDecl::isLambdaStaticInvoker() const {
|
2013-09-29 16:45:24 +08:00
|
|
|
const CXXRecordDecl *P = getParent();
|
|
|
|
if (P->isLambda()) {
|
|
|
|
if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) {
|
|
|
|
if (StaticInvoker == this) return true;
|
|
|
|
if (P->isGenericLambda() && this->isFunctionTemplateSpecialization())
|
|
|
|
return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2012-02-17 11:02:34 +08:00
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
|
|
|
|
TypeSourceInfo *TInfo, bool IsVirtual,
|
|
|
|
SourceLocation L, Expr *Init,
|
|
|
|
SourceLocation R,
|
|
|
|
SourceLocation EllipsisLoc)
|
2011-01-09 07:01:16 +08:00
|
|
|
: Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init),
|
2011-11-01 09:16:03 +08:00
|
|
|
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual),
|
|
|
|
IsWritten(false), SourceOrderOrNumArrayIndices(0)
|
2009-12-03 06:36:29 +08:00
|
|
|
{
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
|
|
|
|
FieldDecl *Member,
|
|
|
|
SourceLocation MemberLoc,
|
|
|
|
SourceLocation L, Expr *Init,
|
|
|
|
SourceLocation R)
|
2011-01-09 07:01:16 +08:00
|
|
|
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
|
2011-11-01 09:16:03 +08:00
|
|
|
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
|
2010-12-04 17:14:42 +08:00
|
|
|
IsWritten(false), SourceOrderOrNumArrayIndices(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
|
|
|
|
IndirectFieldDecl *Member,
|
|
|
|
SourceLocation MemberLoc,
|
|
|
|
SourceLocation L, Expr *Init,
|
|
|
|
SourceLocation R)
|
2011-01-09 07:01:16 +08:00
|
|
|
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
|
2011-11-01 09:16:03 +08:00
|
|
|
LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
|
2010-05-27 02:09:23 +08:00
|
|
|
IsWritten(false), SourceOrderOrNumArrayIndices(0)
|
2009-12-03 06:36:29 +08:00
|
|
|
{
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
2011-02-27 03:13:13 +08:00
|
|
|
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
|
2011-11-01 09:16:03 +08:00
|
|
|
TypeSourceInfo *TInfo,
|
|
|
|
SourceLocation L, Expr *Init,
|
2011-02-27 03:13:13 +08:00
|
|
|
SourceLocation R)
|
2011-11-01 09:16:03 +08:00
|
|
|
: Initializee(TInfo), MemberOrEllipsisLocation(), Init(Init),
|
|
|
|
LParenLoc(L), RParenLoc(R), IsDelegating(true), IsVirtual(false),
|
2011-02-27 03:13:13 +08:00
|
|
|
IsWritten(false), SourceOrderOrNumArrayIndices(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
|
|
|
|
FieldDecl *Member,
|
|
|
|
SourceLocation MemberLoc,
|
|
|
|
SourceLocation L, Expr *Init,
|
|
|
|
SourceLocation R,
|
|
|
|
VarDecl **Indices,
|
|
|
|
unsigned NumIndices)
|
2011-01-09 07:01:16 +08:00
|
|
|
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
|
2010-12-04 17:14:42 +08:00
|
|
|
LParenLoc(L), RParenLoc(R), IsVirtual(false),
|
2010-05-27 02:09:23 +08:00
|
|
|
IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices)
|
Reimplement code generation for copying fields in the
implicitly-generated copy constructor. Previously, Sema would perform
some checking and instantiation to determine which copy constructors,
etc., would be called, then CodeGen would attempt to figure out which
copy constructor to call... but would get it wrong, or poke at an
uninstantiated default argument, or fail in other ways.
The new scheme is similar to what we now do for the implicit
copy-assignment operator, where Sema performs all of the semantic
analysis and builds specific ASTs that look similar to the ASTs we'd
get from explicitly writing the copy constructor, so that CodeGen need
only do a direct translation.
However, it's not quite that simple because one cannot explicit write
elementwise copy-construction of an array. So, I've extended
CXXBaseOrMemberInitializer to contain a list of indexing variables
used to copy-construct the elements. For example, if we have:
struct A { A(const A&); };
struct B {
A array[2][3];
};
then we generate an implicit copy assignment operator for B that looks
something like this:
B::B(const B &other) : array[i0][i1](other.array[i0][i1]) { }
CodeGen will loop over the invented variables i0 and i1 to visit all
elements in the array, so that each element in the destination array
will be copy-constructed from the corresponding element in the source
array. Of course, if we're dealing with arrays of scalars or class
types with trivial copy-assignment operators, we just generate a
memcpy rather than a loop.
Fixes PR6928, PR5989, and PR6887. Boost.Regex now compiles and passes
all of its regression tests.
Conspicuously missing from this patch is handling for the exceptional
case, where we need to destruct those objects that we have
constructed. I'll address that case separately.
llvm-svn: 103079
2010-05-05 13:51:00 +08:00
|
|
|
{
|
|
|
|
VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1);
|
|
|
|
memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *));
|
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
CXXCtorInitializer *CXXCtorInitializer::Create(ASTContext &Context,
|
|
|
|
FieldDecl *Member,
|
|
|
|
SourceLocation MemberLoc,
|
|
|
|
SourceLocation L, Expr *Init,
|
|
|
|
SourceLocation R,
|
|
|
|
VarDecl **Indices,
|
|
|
|
unsigned NumIndices) {
|
|
|
|
void *Mem = Context.Allocate(sizeof(CXXCtorInitializer) +
|
Reimplement code generation for copying fields in the
implicitly-generated copy constructor. Previously, Sema would perform
some checking and instantiation to determine which copy constructors,
etc., would be called, then CodeGen would attempt to figure out which
copy constructor to call... but would get it wrong, or poke at an
uninstantiated default argument, or fail in other ways.
The new scheme is similar to what we now do for the implicit
copy-assignment operator, where Sema performs all of the semantic
analysis and builds specific ASTs that look similar to the ASTs we'd
get from explicitly writing the copy constructor, so that CodeGen need
only do a direct translation.
However, it's not quite that simple because one cannot explicit write
elementwise copy-construction of an array. So, I've extended
CXXBaseOrMemberInitializer to contain a list of indexing variables
used to copy-construct the elements. For example, if we have:
struct A { A(const A&); };
struct B {
A array[2][3];
};
then we generate an implicit copy assignment operator for B that looks
something like this:
B::B(const B &other) : array[i0][i1](other.array[i0][i1]) { }
CodeGen will loop over the invented variables i0 and i1 to visit all
elements in the array, so that each element in the destination array
will be copy-constructed from the corresponding element in the source
array. Of course, if we're dealing with arrays of scalars or class
types with trivial copy-assignment operators, we just generate a
memcpy rather than a loop.
Fixes PR6928, PR5989, and PR6887. Boost.Regex now compiles and passes
all of its regression tests.
Conspicuously missing from this patch is handling for the exceptional
case, where we need to destruct those objects that we have
constructed. I'll address that case separately.
llvm-svn: 103079
2010-05-05 13:51:00 +08:00
|
|
|
sizeof(VarDecl *) * NumIndices,
|
2011-01-09 04:30:50 +08:00
|
|
|
llvm::alignOf<CXXCtorInitializer>());
|
2011-01-09 07:01:16 +08:00
|
|
|
return new (Mem) CXXCtorInitializer(Context, Member, MemberLoc, L, Init, R,
|
|
|
|
Indices, NumIndices);
|
Reimplement code generation for copying fields in the
implicitly-generated copy constructor. Previously, Sema would perform
some checking and instantiation to determine which copy constructors,
etc., would be called, then CodeGen would attempt to figure out which
copy constructor to call... but would get it wrong, or poke at an
uninstantiated default argument, or fail in other ways.
The new scheme is similar to what we now do for the implicit
copy-assignment operator, where Sema performs all of the semantic
analysis and builds specific ASTs that look similar to the ASTs we'd
get from explicitly writing the copy constructor, so that CodeGen need
only do a direct translation.
However, it's not quite that simple because one cannot explicit write
elementwise copy-construction of an array. So, I've extended
CXXBaseOrMemberInitializer to contain a list of indexing variables
used to copy-construct the elements. For example, if we have:
struct A { A(const A&); };
struct B {
A array[2][3];
};
then we generate an implicit copy assignment operator for B that looks
something like this:
B::B(const B &other) : array[i0][i1](other.array[i0][i1]) { }
CodeGen will loop over the invented variables i0 and i1 to visit all
elements in the array, so that each element in the destination array
will be copy-constructed from the corresponding element in the source
array. Of course, if we're dealing with arrays of scalars or class
types with trivial copy-assignment operators, we just generate a
memcpy rather than a loop.
Fixes PR6928, PR5989, and PR6887. Boost.Regex now compiles and passes
all of its regression tests.
Conspicuously missing from this patch is handling for the exceptional
case, where we need to destruct those objects that we have
constructed. I'll address that case separately.
llvm-svn: 103079
2010-05-05 13:51:00 +08:00
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
TypeLoc CXXCtorInitializer::getBaseClassLoc() const {
|
2009-12-03 06:36:29 +08:00
|
|
|
if (isBaseInitializer())
|
2011-01-09 07:01:16 +08:00
|
|
|
return Initializee.get<TypeSourceInfo*>()->getTypeLoc();
|
2009-12-03 06:36:29 +08:00
|
|
|
else
|
|
|
|
return TypeLoc();
|
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
const Type *CXXCtorInitializer::getBaseClass() const {
|
2009-12-03 06:36:29 +08:00
|
|
|
if (isBaseInitializer())
|
2011-01-09 07:01:16 +08:00
|
|
|
return Initializee.get<TypeSourceInfo*>()->getType().getTypePtr();
|
2009-12-03 06:36:29 +08:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
SourceLocation CXXCtorInitializer::getSourceLocation() const {
|
2011-11-01 09:16:03 +08:00
|
|
|
if (isAnyMemberInitializer())
|
2009-12-03 06:36:29 +08:00
|
|
|
return getMemberLocation();
|
2011-06-12 01:19:42 +08:00
|
|
|
|
|
|
|
if (isInClassMemberInitializer())
|
|
|
|
return getAnyMember()->getLocation();
|
2009-12-03 06:36:29 +08:00
|
|
|
|
2011-11-01 09:16:03 +08:00
|
|
|
if (TypeSourceInfo *TSInfo = Initializee.get<TypeSourceInfo*>())
|
|
|
|
return TSInfo->getTypeLoc().getLocalSourceRange().getBegin();
|
|
|
|
|
|
|
|
return SourceLocation();
|
2009-12-03 06:36:29 +08:00
|
|
|
}
|
|
|
|
|
2011-01-09 04:30:50 +08:00
|
|
|
SourceRange CXXCtorInitializer::getSourceRange() const {
|
2011-06-12 01:19:42 +08:00
|
|
|
if (isInClassMemberInitializer()) {
|
|
|
|
FieldDecl *D = getAnyMember();
|
|
|
|
if (Expr *I = D->getInClassInitializer())
|
|
|
|
return I->getSourceRange();
|
|
|
|
return SourceRange();
|
|
|
|
}
|
|
|
|
|
2009-12-03 06:36:29 +08:00
|
|
|
return SourceRange(getSourceLocation(), getRParenLoc());
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void CXXConstructorDecl::anchor() { }
|
|
|
|
|
2010-05-08 05:43:38 +08:00
|
|
|
CXXConstructorDecl *
|
2012-01-06 05:55:30 +08:00
|
|
|
CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) CXXConstructorDecl(0, SourceLocation(),
|
|
|
|
DeclarationNameInfo(), QualType(),
|
|
|
|
0, false, false, false, false);
|
2010-05-08 05:43:38 +08:00
|
|
|
}
|
|
|
|
|
2008-10-31 17:07:45 +08:00
|
|
|
CXXConstructorDecl *
|
|
|
|
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2011-03-08 16:55:46 +08:00
|
|
|
SourceLocation StartLoc,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2011-08-16 05:04:07 +08:00
|
|
|
bool isExplicit, bool isInline,
|
|
|
|
bool isImplicitlyDeclared, bool isConstexpr) {
|
2010-08-12 06:01:17 +08:00
|
|
|
assert(NameInfo.getName().getNameKind()
|
|
|
|
== DeclarationName::CXXConstructorName &&
|
2008-11-17 22:58:09 +08:00
|
|
|
"Name must refer to a constructor");
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, RD) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo,
|
|
|
|
isExplicit, isInline,
|
|
|
|
isImplicitlyDeclared, isConstexpr);
|
2008-10-31 17:07:45 +08:00
|
|
|
}
|
|
|
|
|
2011-11-01 09:16:03 +08:00
|
|
|
CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const {
|
|
|
|
assert(isDelegatingConstructor() && "Not a delegating constructor!");
|
|
|
|
Expr *E = (*init_begin())->getInit()->IgnoreImplicit();
|
|
|
|
if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(E))
|
|
|
|
return Construct->getConstructor();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-01 04:25:05 +08:00
|
|
|
bool CXXConstructorDecl::isDefaultConstructor() const {
|
|
|
|
// C++ [class.ctor]p5:
|
2008-11-06 00:20:31 +08:00
|
|
|
// A default constructor for a class X is a constructor of class
|
|
|
|
// X that can be called without an argument.
|
2008-11-01 04:25:05 +08:00
|
|
|
return (getNumParams() == 0) ||
|
2009-08-25 13:12:04 +08:00
|
|
|
(getNumParams() > 0 && getParamDecl(0)->hasDefaultArg());
|
2008-11-01 04:25:05 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
bool
|
2009-12-22 08:34:07 +08:00
|
|
|
CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const {
|
2011-01-22 03:38:21 +08:00
|
|
|
return isCopyOrMoveConstructor(TypeQuals) &&
|
|
|
|
getParamDecl(0)->getType()->isLValueReferenceType();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CXXConstructorDecl::isMoveConstructor(unsigned &TypeQuals) const {
|
|
|
|
return isCopyOrMoveConstructor(TypeQuals) &&
|
|
|
|
getParamDecl(0)->getType()->isRValueReferenceType();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Determine whether this is a copy or move constructor.
|
|
|
|
bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const {
|
2008-11-01 04:25:05 +08:00
|
|
|
// C++ [class.copy]p2:
|
2008-11-06 00:20:31 +08:00
|
|
|
// A non-template constructor for class X is a copy constructor
|
|
|
|
// if its first parameter is of type X&, const X&, volatile X& or
|
|
|
|
// const volatile X&, and either there are no other parameters
|
|
|
|
// or else all other parameters have default arguments (8.3.6).
|
2011-01-22 03:38:21 +08:00
|
|
|
// C++0x [class.copy]p3:
|
|
|
|
// A non-template constructor for class X is a move constructor if its
|
|
|
|
// first parameter is of type X&&, const X&&, volatile X&&, or
|
|
|
|
// const volatile X&&, and either there are no other parameters or else
|
|
|
|
// all other parameters have default arguments.
|
2008-11-01 04:25:05 +08:00
|
|
|
if ((getNumParams() < 1) ||
|
2009-10-14 07:45:19 +08:00
|
|
|
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
|
2009-11-14 07:59:09 +08:00
|
|
|
(getPrimaryTemplate() != 0) ||
|
2009-10-14 07:45:19 +08:00
|
|
|
(getDescribedFunctionTemplate() != 0))
|
2008-11-01 04:25:05 +08:00
|
|
|
return false;
|
2011-01-22 03:38:21 +08:00
|
|
|
|
2008-11-01 04:25:05 +08:00
|
|
|
const ParmVarDecl *Param = getParamDecl(0);
|
2011-01-22 03:38:21 +08:00
|
|
|
|
|
|
|
// Do we have a reference type?
|
|
|
|
const ReferenceType *ParamRefType = Param->getType()->getAs<ReferenceType>();
|
2009-11-14 07:59:09 +08:00
|
|
|
if (!ParamRefType)
|
|
|
|
return false;
|
2011-01-22 03:38:21 +08:00
|
|
|
|
2009-11-14 07:59:09 +08:00
|
|
|
// Is it a reference to our class type?
|
2009-12-22 08:34:07 +08:00
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
|
2009-11-14 07:59:09 +08:00
|
|
|
CanQualType PointeeType
|
|
|
|
= Context.getCanonicalType(ParamRefType->getPointeeType());
|
2009-09-16 04:50:23 +08:00
|
|
|
CanQualType ClassTy
|
|
|
|
= Context.getCanonicalType(Context.getTagDeclType(getParent()));
|
2008-11-01 04:25:05 +08:00
|
|
|
if (PointeeType.getUnqualifiedType() != ClassTy)
|
|
|
|
return false;
|
2011-01-22 03:38:21 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// FIXME: other qualifiers?
|
2011-01-22 03:38:21 +08:00
|
|
|
|
|
|
|
// We have a copy or move constructor.
|
2008-11-01 04:25:05 +08:00
|
|
|
TypeQuals = PointeeType.getCVRQualifiers();
|
2011-01-22 03:38:21 +08:00
|
|
|
return true;
|
2008-11-01 04:25:05 +08:00
|
|
|
}
|
|
|
|
|
2009-08-29 00:57:08 +08:00
|
|
|
bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
|
2008-11-01 00:23:19 +08:00
|
|
|
// C++ [class.conv.ctor]p1:
|
|
|
|
// A constructor declared without the function-specifier explicit
|
|
|
|
// that can be called with a single parameter specifies a
|
|
|
|
// conversion from the type of its first parameter to the type of
|
|
|
|
// its class. Such a constructor is called a converting
|
|
|
|
// constructor.
|
2009-08-29 00:57:08 +08:00
|
|
|
if (isExplicit() && !AllowExplicit)
|
2008-11-01 00:23:19 +08:00
|
|
|
return false;
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
return (getNumParams() == 0 &&
|
2009-09-22 07:43:11 +08:00
|
|
|
getType()->getAs<FunctionProtoType>()->isVariadic()) ||
|
2008-11-01 00:23:19 +08:00
|
|
|
(getNumParams() == 1) ||
|
2012-06-06 07:44:51 +08:00
|
|
|
(getNumParams() > 1 &&
|
|
|
|
(getParamDecl(1)->hasDefaultArg() ||
|
|
|
|
getParamDecl(1)->isParameterPack()));
|
2008-11-01 00:23:19 +08:00
|
|
|
}
|
2008-10-31 17:07:45 +08:00
|
|
|
|
2010-11-09 01:16:59 +08:00
|
|
|
bool CXXConstructorDecl::isSpecializationCopyingObject() const {
|
2009-11-14 09:20:54 +08:00
|
|
|
if ((getNumParams() < 1) ||
|
|
|
|
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
|
|
|
|
(getPrimaryTemplate() == 0) ||
|
|
|
|
(getDescribedFunctionTemplate() != 0))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const ParmVarDecl *Param = getParamDecl(0);
|
|
|
|
|
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
CanQualType ParamType = Context.getCanonicalType(Param->getType());
|
|
|
|
|
|
|
|
// Is it the same as our our class type?
|
|
|
|
CanQualType ClassTy
|
|
|
|
= Context.getCanonicalType(Context.getTagDeclType(getParent()));
|
|
|
|
if (ParamType.getUnqualifiedType() != ClassTy)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-06 03:23:19 +08:00
|
|
|
const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const {
|
|
|
|
// Hack: we store the inherited constructor in the overridden method table
|
2012-03-10 09:39:01 +08:00
|
|
|
method_iterator It = getASTContext().overridden_methods_begin(this);
|
|
|
|
if (It == getASTContext().overridden_methods_end(this))
|
2011-02-06 03:23:19 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return cast<CXXConstructorDecl>(*It);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){
|
|
|
|
// Hack: we store the inherited constructor in the overridden method table
|
2012-03-10 09:39:01 +08:00
|
|
|
assert(getASTContext().overridden_methods_size(this) == 0 &&
|
|
|
|
"Base ctor already set.");
|
|
|
|
getASTContext().addOverriddenMethod(this, BaseCtor);
|
2011-02-06 03:23:19 +08:00
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void CXXDestructorDecl::anchor() { }
|
|
|
|
|
2010-05-08 05:43:38 +08:00
|
|
|
CXXDestructorDecl *
|
2012-01-06 05:55:30 +08:00
|
|
|
CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) CXXDestructorDecl(
|
|
|
|
0, SourceLocation(), DeclarationNameInfo(), QualType(), 0, false, false);
|
2010-05-08 05:43:38 +08:00
|
|
|
}
|
|
|
|
|
2008-11-06 04:51:48 +08:00
|
|
|
CXXDestructorDecl *
|
|
|
|
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2011-03-08 16:55:46 +08:00
|
|
|
SourceLocation StartLoc,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2010-10-21 08:44:50 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2011-08-16 05:04:07 +08:00
|
|
|
bool isInline, bool isImplicitlyDeclared) {
|
2010-08-12 06:01:17 +08:00
|
|
|
assert(NameInfo.getName().getNameKind()
|
|
|
|
== DeclarationName::CXXDestructorName &&
|
2008-11-17 22:58:09 +08:00
|
|
|
"Name must refer to a destructor");
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, RD) CXXDestructorDecl(RD, StartLoc, NameInfo, T, TInfo,
|
|
|
|
isInline, isImplicitlyDeclared);
|
2008-11-06 04:51:48 +08:00
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void CXXConversionDecl::anchor() { }
|
|
|
|
|
2010-05-08 05:43:38 +08:00
|
|
|
CXXConversionDecl *
|
2012-01-06 05:55:30 +08:00
|
|
|
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) CXXConversionDecl(0, SourceLocation(),
|
|
|
|
DeclarationNameInfo(), QualType(),
|
|
|
|
0, false, false, false,
|
|
|
|
SourceLocation());
|
2010-05-08 05:43:38 +08:00
|
|
|
}
|
|
|
|
|
2008-11-08 04:08:42 +08:00
|
|
|
CXXConversionDecl *
|
|
|
|
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2011-03-08 16:55:46 +08:00
|
|
|
SourceLocation StartLoc,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2011-03-09 01:10:18 +08:00
|
|
|
bool isInline, bool isExplicit,
|
2011-08-16 05:04:07 +08:00
|
|
|
bool isConstexpr, SourceLocation EndLocation) {
|
2010-08-12 06:01:17 +08:00
|
|
|
assert(NameInfo.getName().getNameKind()
|
|
|
|
== DeclarationName::CXXConversionFunctionName &&
|
2008-11-17 22:58:09 +08:00
|
|
|
"Name must refer to a conversion function");
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, RD) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo,
|
|
|
|
isInline, isExplicit, isConstexpr,
|
|
|
|
EndLocation);
|
2008-11-08 04:08:42 +08:00
|
|
|
}
|
|
|
|
|
2012-02-16 09:06:16 +08:00
|
|
|
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
|
|
|
|
return isImplicit() && getParent()->isLambda() &&
|
|
|
|
getConversionType()->isBlockPointerType();
|
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void LinkageSpecDecl::anchor() { }
|
|
|
|
|
2008-11-05 00:51:42 +08:00
|
|
|
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclContext *DC,
|
2011-03-09 00:41:52 +08:00
|
|
|
SourceLocation ExternLoc,
|
|
|
|
SourceLocation LangLoc,
|
2011-03-03 22:52:38 +08:00
|
|
|
LanguageIDs Lang,
|
2013-04-26 09:30:23 +08:00
|
|
|
bool HasBraces) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, HasBraces);
|
2008-12-17 06:23:02 +08:00
|
|
|
}
|
2009-02-04 03:21:40 +08:00
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C,
|
|
|
|
unsigned ID) {
|
|
|
|
return new (C, ID) LinkageSpecDecl(0, SourceLocation(), SourceLocation(),
|
|
|
|
lang_c, false);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void UsingDirectiveDecl::anchor() { }
|
|
|
|
|
2009-02-04 03:21:40 +08:00
|
|
|
UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L,
|
|
|
|
SourceLocation NamespaceLoc,
|
2011-02-26 00:33:46 +08:00
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
2009-02-04 03:21:40 +08:00
|
|
|
SourceLocation IdentLoc,
|
2009-11-23 23:34:23 +08:00
|
|
|
NamedDecl *Used,
|
2009-02-04 03:21:40 +08:00
|
|
|
DeclContext *CommonAncestor) {
|
2009-11-23 23:34:23 +08:00
|
|
|
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Used))
|
|
|
|
Used = NS->getOriginalNamespace();
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc,
|
|
|
|
IdentLoc, Used, CommonAncestor);
|
2009-02-04 03:21:40 +08:00
|
|
|
}
|
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
UsingDirectiveDecl *UsingDirectiveDecl::CreateDeserialized(ASTContext &C,
|
|
|
|
unsigned ID) {
|
|
|
|
return new (C, ID) UsingDirectiveDecl(0, SourceLocation(), SourceLocation(),
|
|
|
|
NestedNameSpecifierLoc(),
|
|
|
|
SourceLocation(), 0, 0);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2009-11-23 23:34:23 +08:00
|
|
|
NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
|
|
|
|
if (NamespaceAliasDecl *NA =
|
|
|
|
dyn_cast_or_null<NamespaceAliasDecl>(NominatedNamespace))
|
|
|
|
return NA->getNamespace();
|
|
|
|
return cast_or_null<NamespaceDecl>(NominatedNamespace);
|
|
|
|
}
|
|
|
|
|
2012-01-07 17:11:48 +08:00
|
|
|
NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline,
|
|
|
|
SourceLocation StartLoc,
|
|
|
|
SourceLocation IdLoc, IdentifierInfo *Id,
|
|
|
|
NamespaceDecl *PrevDecl)
|
|
|
|
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
|
|
|
|
LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline)
|
|
|
|
{
|
2013-10-17 23:37:26 +08:00
|
|
|
setPreviousDecl(PrevDecl);
|
2012-01-07 17:11:48 +08:00
|
|
|
|
|
|
|
if (PrevDecl)
|
|
|
|
AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
|
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
|
2012-01-07 17:11:48 +08:00
|
|
|
bool Inline, SourceLocation StartLoc,
|
|
|
|
SourceLocation IdLoc, IdentifierInfo *Id,
|
|
|
|
NamespaceDecl *PrevDecl) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) NamespaceDecl(DC, Inline, StartLoc, IdLoc, Id, PrevDecl);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) NamespaceDecl(0, false, SourceLocation(), SourceLocation(),
|
|
|
|
0, 0);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2013-11-26 23:12:20 +08:00
|
|
|
NamespaceDecl *NamespaceDecl::getNextRedeclaration() {
|
|
|
|
return RedeclLink.getNext();
|
|
|
|
}
|
|
|
|
NamespaceDecl *NamespaceDecl::getPreviousDeclImpl() {
|
|
|
|
return getPreviousDecl();
|
|
|
|
}
|
|
|
|
NamespaceDecl *NamespaceDecl::getMostRecentDeclImpl() {
|
|
|
|
return getMostRecentDecl();
|
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void NamespaceAliasDecl::anchor() { }
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
|
2010-09-01 11:07:18 +08:00
|
|
|
SourceLocation UsingLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
SourceLocation AliasLoc,
|
|
|
|
IdentifierInfo *Alias,
|
2011-02-26 01:08:07 +08:00
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
SourceLocation IdentLoc,
|
2009-03-29 06:58:02 +08:00
|
|
|
NamedDecl *Namespace) {
|
2009-11-23 23:34:23 +08:00
|
|
|
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
|
|
|
|
Namespace = NS->getOriginalNamespace();
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias,
|
|
|
|
QualifierLoc, IdentLoc, Namespace);
|
2009-03-29 06:58:02 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
NamespaceAliasDecl *
|
|
|
|
NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) NamespaceAliasDecl(0, SourceLocation(), SourceLocation(),
|
|
|
|
0, NestedNameSpecifierLoc(),
|
|
|
|
SourceLocation(), 0);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void UsingShadowDecl::anchor() { }
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
UsingShadowDecl *
|
|
|
|
UsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) UsingShadowDecl(0, SourceLocation(), 0, 0);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2010-11-10 13:40:41 +08:00
|
|
|
UsingDecl *UsingShadowDecl::getUsingDecl() const {
|
|
|
|
const UsingShadowDecl *Shadow = this;
|
|
|
|
while (const UsingShadowDecl *NextShadow =
|
|
|
|
dyn_cast<UsingShadowDecl>(Shadow->UsingOrNextShadow))
|
|
|
|
Shadow = NextShadow;
|
|
|
|
return cast<UsingDecl>(Shadow->UsingOrNextShadow);
|
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void UsingDecl::anchor() { }
|
|
|
|
|
2010-11-10 13:40:41 +08:00
|
|
|
void UsingDecl::addShadowDecl(UsingShadowDecl *S) {
|
|
|
|
assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() &&
|
|
|
|
"declaration already in set");
|
|
|
|
assert(S->getUsingDecl() == this);
|
|
|
|
|
2012-01-08 03:09:05 +08:00
|
|
|
if (FirstUsingShadow.getPointer())
|
|
|
|
S->UsingOrNextShadow = FirstUsingShadow.getPointer();
|
|
|
|
FirstUsingShadow.setPointer(S);
|
2010-11-10 13:40:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void UsingDecl::removeShadowDecl(UsingShadowDecl *S) {
|
|
|
|
assert(std::find(shadow_begin(), shadow_end(), S) != shadow_end() &&
|
|
|
|
"declaration not in set");
|
|
|
|
assert(S->getUsingDecl() == this);
|
|
|
|
|
|
|
|
// Remove S from the shadow decl chain. This is O(n) but hopefully rare.
|
|
|
|
|
2012-01-08 03:09:05 +08:00
|
|
|
if (FirstUsingShadow.getPointer() == S) {
|
|
|
|
FirstUsingShadow.setPointer(
|
|
|
|
dyn_cast<UsingShadowDecl>(S->UsingOrNextShadow));
|
2010-11-10 13:40:41 +08:00
|
|
|
S->UsingOrNextShadow = this;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-08 03:09:05 +08:00
|
|
|
UsingShadowDecl *Prev = FirstUsingShadow.getPointer();
|
2010-11-10 13:40:41 +08:00
|
|
|
while (Prev->UsingOrNextShadow != S)
|
|
|
|
Prev = cast<UsingShadowDecl>(Prev->UsingOrNextShadow);
|
|
|
|
Prev->UsingOrNextShadow = S->UsingOrNextShadow;
|
|
|
|
S->UsingOrNextShadow = this;
|
|
|
|
}
|
|
|
|
|
2011-02-25 08:36:19 +08:00
|
|
|
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL,
|
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
2010-08-12 19:46:03 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2013-07-22 18:54:09 +08:00
|
|
|
bool HasTypename) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename);
|
2009-06-20 08:51:54 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) UsingDecl(0, SourceLocation(), NestedNameSpecifierLoc(),
|
|
|
|
DeclarationNameInfo(), false);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2013-07-18 01:28:56 +08:00
|
|
|
SourceRange UsingDecl::getSourceRange() const {
|
|
|
|
SourceLocation Begin = isAccessDeclaration()
|
|
|
|
? getQualifierLoc().getBeginLoc() : UsingLocation;
|
|
|
|
return SourceRange(Begin, getNameInfo().getEndLoc());
|
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void UnresolvedUsingValueDecl::anchor() { }
|
|
|
|
|
2009-11-18 10:36:19 +08:00
|
|
|
UnresolvedUsingValueDecl *
|
|
|
|
UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation UsingLoc,
|
2011-02-25 08:36:19 +08:00
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
2010-08-12 19:46:03 +08:00
|
|
|
const DeclarationNameInfo &NameInfo) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
|
|
|
|
QualifierLoc, NameInfo);
|
2009-11-18 10:36:19 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
UnresolvedUsingValueDecl *
|
|
|
|
UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) UnresolvedUsingValueDecl(0, QualType(), SourceLocation(),
|
|
|
|
NestedNameSpecifierLoc(),
|
2012-01-06 05:55:30 +08:00
|
|
|
DeclarationNameInfo());
|
|
|
|
}
|
|
|
|
|
2013-07-18 01:28:56 +08:00
|
|
|
SourceRange UnresolvedUsingValueDecl::getSourceRange() const {
|
|
|
|
SourceLocation Begin = isAccessDeclaration()
|
|
|
|
? getQualifierLoc().getBeginLoc() : UsingLocation;
|
|
|
|
return SourceRange(Begin, getNameInfo().getEndLoc());
|
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void UnresolvedUsingTypenameDecl::anchor() { }
|
|
|
|
|
2009-11-18 10:36:19 +08:00
|
|
|
UnresolvedUsingTypenameDecl *
|
|
|
|
UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation UsingLoc,
|
|
|
|
SourceLocation TypenameLoc,
|
2011-02-25 08:36:19 +08:00
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
2009-11-18 10:36:19 +08:00
|
|
|
SourceLocation TargetNameLoc,
|
|
|
|
DeclarationName TargetName) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) UnresolvedUsingTypenameDecl(
|
|
|
|
DC, UsingLoc, TypenameLoc, QualifierLoc, TargetNameLoc,
|
|
|
|
TargetName.getAsIdentifierInfo());
|
2009-08-28 13:30:28 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
UnresolvedUsingTypenameDecl *
|
|
|
|
UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) UnresolvedUsingTypenameDecl(
|
|
|
|
0, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(),
|
|
|
|
SourceLocation(), 0);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2011-12-20 10:48:34 +08:00
|
|
|
void StaticAssertDecl::anchor() { }
|
|
|
|
|
2009-03-14 08:25:26 +08:00
|
|
|
StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
|
2011-03-09 00:41:52 +08:00
|
|
|
SourceLocation StaticAssertLoc,
|
|
|
|
Expr *AssertExpr,
|
|
|
|
StringLiteral *Message,
|
2012-07-12 06:37:56 +08:00
|
|
|
SourceLocation RParenLoc,
|
|
|
|
bool Failed) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message,
|
|
|
|
RParenLoc, Failed);
|
2009-03-14 08:25:26 +08:00
|
|
|
}
|
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C,
|
2012-01-06 05:55:30 +08:00
|
|
|
unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) StaticAssertDecl(0, SourceLocation(), 0, 0,
|
|
|
|
SourceLocation(), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
MSPropertyDecl *MSPropertyDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L, DeclarationName N,
|
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
|
|
|
SourceLocation StartL,
|
|
|
|
IdentifierInfo *Getter,
|
|
|
|
IdentifierInfo *Setter) {
|
|
|
|
return new (C, DC) MSPropertyDecl(DC, L, N, T, TInfo, StartL, Getter, Setter);
|
|
|
|
}
|
|
|
|
|
|
|
|
MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C,
|
|
|
|
unsigned ID) {
|
|
|
|
return new (C, ID) MSPropertyDecl(0, SourceLocation(), DeclarationName(),
|
|
|
|
QualType(), 0, SourceLocation(), 0, 0);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2009-03-27 07:46:50 +08:00
|
|
|
static const char *getAccessName(AccessSpecifier AS) {
|
|
|
|
switch (AS) {
|
|
|
|
case AS_none:
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Invalid access specifier!");
|
2009-03-27 07:46:50 +08:00
|
|
|
case AS_public:
|
|
|
|
return "public";
|
|
|
|
case AS_private:
|
|
|
|
return "private";
|
|
|
|
case AS_protected:
|
|
|
|
return "protected";
|
|
|
|
}
|
2012-01-17 10:30:50 +08:00
|
|
|
llvm_unreachable("Invalid access specifier!");
|
2009-03-27 07:46:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
|
|
|
|
AccessSpecifier AS) {
|
|
|
|
return DB << getAccessName(AS);
|
|
|
|
}
|
2012-02-02 09:16:57 +08:00
|
|
|
|
|
|
|
const PartialDiagnostic &clang::operator<<(const PartialDiagnostic &DB,
|
|
|
|
AccessSpecifier AS) {
|
|
|
|
return DB << getAccessName(AS);
|
|
|
|
}
|