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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04: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"
|
2009-03-26 00:17:03 +03:00
|
|
|
#include "clang/AST/DeclTemplate.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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-03-14 03:25:26 +03:00
|
|
|
#include "clang/AST/Expr.h"
|
2008-11-13 02:21:09 +03:00
|
|
|
#include "clang/Basic/IdentifierTable.h"
|
2008-12-24 00:31:30 +03:00
|
|
|
#include "llvm/ADT/STLExtras.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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Decl Allocation/Deallocation Method Implementations
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-12-05 21:15:24 +03:00
|
|
|
|
Added ClassTemplateSpecializationDecl, which is a subclass of
CXXRecordDecl that is used to represent class template
specializations. These are canonical declarations that can refer to
either an actual class template specialization in the code, e.g.,
template<> class vector<bool> { };
or to a template instantiation. However, neither of these features is
actually implemented yet, so really we're just using (and uniqing) the
declarations to make sure that, e.g., A<int> is a different type from
A<float>. Note that we carefully distinguish between what the user
wrote in the source code (e.g., "A<FLOAT>") and the semantic entity it
represents (e.g., "A<float, int>"); the former is in the sugared Type,
the latter is an actual Decl.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64716 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-17 04:05:43 +03:00
|
|
|
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
|
2009-07-21 18:46:17 +04:00
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
2009-07-30 03:36:44 +04:00
|
|
|
CXXRecordDecl *PrevDecl,
|
2009-07-21 18:46:17 +04:00
|
|
|
SourceLocation TKL)
|
2009-07-30 03:36:44 +04:00
|
|
|
: RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL),
|
2008-11-13 02:21:09 +03:00
|
|
|
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
|
2009-01-05 23:52:13 +03:00
|
|
|
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
2009-08-16 02:23:00 +04:00
|
|
|
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
|
|
|
Abstract(false), HasTrivialConstructor(true),
|
|
|
|
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
|
|
|
|
HasTrivialDestructor(true), Bases(0), NumBases(0), VBases(0), NumVBases(0),
|
2009-07-11 00:13:23 +04:00
|
|
|
Conversions(DC, DeclarationName()),
|
2009-03-26 00:17:03 +03:00
|
|
|
TemplateOrInstantiation() { }
|
2008-11-13 02:21:09 +03:00
|
|
|
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
2009-07-21 18:46:17 +04:00
|
|
|
SourceLocation TKL,
|
2009-05-15 23:11:46 +04:00
|
|
|
CXXRecordDecl* PrevDecl,
|
|
|
|
bool DelayTypeCreation) {
|
2009-07-30 03:36:44 +04:00
|
|
|
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id,
|
|
|
|
PrevDecl, TKL);
|
|
|
|
|
|
|
|
// FIXME: DelayTypeCreation seems like such a hack
|
2009-05-15 23:11:46 +04:00
|
|
|
if (!DelayTypeCreation)
|
|
|
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
2008-10-22 21:49:05 +04:00
|
|
|
CXXRecordDecl::~CXXRecordDecl() {
|
2009-07-02 22:26:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CXXRecordDecl::Destroy(ASTContext &C) {
|
|
|
|
C.Deallocate(Bases);
|
2009-07-22 21:41:53 +04:00
|
|
|
C.Deallocate(VBases);
|
2009-07-02 22:26:15 +04:00
|
|
|
this->RecordDecl::Destroy(C);
|
2008-10-22 21:49:05 +04:00
|
|
|
}
|
|
|
|
|
2008-10-23 22:13:27 +04:00
|
|
|
void
|
2009-07-02 22:26:15 +04:00
|
|
|
CXXRecordDecl::setBases(ASTContext &C,
|
|
|
|
CXXBaseSpecifier const * const *Bases,
|
2008-10-23 22:13:27 +04:00
|
|
|
unsigned NumBases) {
|
2008-11-05 19:20:31 +03:00
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is an array or a class (clause 9) with [...]
|
|
|
|
// no base classes [...].
|
|
|
|
Aggregate = false;
|
|
|
|
|
2008-10-23 22:13:27 +04:00
|
|
|
if (this->Bases)
|
2009-07-02 22:26:15 +04:00
|
|
|
C.Deallocate(this->Bases);
|
2009-07-11 00:13:23 +04:00
|
|
|
|
|
|
|
int vbaseCount = 0;
|
|
|
|
llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
|
|
|
|
bool hasDirectVirtualBase = false;
|
|
|
|
|
2009-07-02 22:26:15 +04:00
|
|
|
this->Bases = new(C) CXXBaseSpecifier [NumBases];
|
2008-10-23 22:13:27 +04:00
|
|
|
this->NumBases = NumBases;
|
2009-07-11 00:13:23 +04:00
|
|
|
for (unsigned i = 0; i < NumBases; ++i) {
|
2008-10-23 22:13:27 +04:00
|
|
|
this->Bases[i] = *Bases[i];
|
2009-07-11 00:13:23 +04:00
|
|
|
// Keep track of inherited vbases for this base class.
|
|
|
|
const CXXBaseSpecifier *Base = Bases[i];
|
|
|
|
QualType BaseType = Base->getType();
|
|
|
|
// Skip template types.
|
|
|
|
// FIXME. This means that this list must be rebuilt during template
|
|
|
|
// instantiation.
|
|
|
|
if (BaseType->isDependentType())
|
|
|
|
continue;
|
|
|
|
CXXRecordDecl *BaseClassDecl
|
2009-07-30 01:53:49 +04:00
|
|
|
= cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
|
2009-07-11 00:13:23 +04:00
|
|
|
if (Base->isVirtual())
|
|
|
|
hasDirectVirtualBase = true;
|
|
|
|
for (CXXRecordDecl::base_class_iterator VBase =
|
|
|
|
BaseClassDecl->vbases_begin(),
|
|
|
|
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
|
|
|
|
// Add this vbase to the array of vbases for current class if it is
|
|
|
|
// not already in the list.
|
|
|
|
// FIXME. Note that we do a linear search as number of such classes are
|
|
|
|
// very few.
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < vbaseCount; ++i)
|
|
|
|
if (UniqueVbases[i]->getType() == VBase->getType())
|
|
|
|
break;
|
|
|
|
if (i == vbaseCount) {
|
|
|
|
UniqueVbases.push_back(VBase);
|
|
|
|
++vbaseCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hasDirectVirtualBase) {
|
|
|
|
// Iterate one more time through the direct bases and add the virtual
|
|
|
|
// base to the list of vritual bases for current class.
|
|
|
|
for (unsigned i = 0; i < NumBases; ++i) {
|
|
|
|
const CXXBaseSpecifier *VBase = Bases[i];
|
|
|
|
if (!VBase->isVirtual())
|
|
|
|
continue;
|
2009-07-11 18:32:10 +04:00
|
|
|
int j;
|
|
|
|
for (j = 0; j < vbaseCount; ++j)
|
|
|
|
if (UniqueVbases[j]->getType() == VBase->getType())
|
2009-07-11 00:13:23 +04:00
|
|
|
break;
|
2009-07-11 18:32:10 +04:00
|
|
|
if (j == vbaseCount) {
|
2009-07-11 00:13:23 +04:00
|
|
|
UniqueVbases.push_back(VBase);
|
|
|
|
++vbaseCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vbaseCount > 0) {
|
|
|
|
// build AST for inhireted, direct or indirect, virtual bases.
|
2009-07-22 22:25:24 +04:00
|
|
|
this->VBases = new (C) CXXBaseSpecifier [vbaseCount];
|
2009-07-11 00:13:23 +04:00
|
|
|
this->NumVBases = vbaseCount;
|
|
|
|
for (int i = 0; i < vbaseCount; i++) {
|
|
|
|
QualType QT = UniqueVbases[i]->getType();
|
|
|
|
CXXRecordDecl *VBaseClassDecl
|
2009-07-30 01:53:49 +04:00
|
|
|
= cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
|
2009-07-11 00:13:23 +04:00
|
|
|
this->VBases[i] =
|
2009-07-23 00:55:49 +04:00
|
|
|
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
|
|
|
|
VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
|
|
|
|
UniqueVbases[i]->getAccessSpecifier(), QT);
|
2009-07-11 00:13:23 +04:00
|
|
|
}
|
|
|
|
}
|
2008-10-23 22:13:27 +04:00
|
|
|
}
|
|
|
|
|
2008-11-03 20:51:48 +03:00
|
|
|
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
|
2009-06-23 03:34:40 +04:00
|
|
|
return getCopyConstructor(Context, QualType::Const) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
|
|
|
|
unsigned TypeQuals) const{
|
2009-01-05 23:52:13 +03:00
|
|
|
QualType ClassType
|
|
|
|
= Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
|
2008-12-16 00:24:18 +03:00
|
|
|
DeclarationName ConstructorName
|
|
|
|
= Context.DeclarationNames.getCXXConstructorName(
|
2009-06-23 03:34:40 +04:00
|
|
|
Context.getCanonicalType(ClassType));
|
|
|
|
unsigned FoundTQs;
|
2008-12-24 00:31:30 +03:00
|
|
|
DeclContext::lookup_const_iterator Con, ConEnd;
|
2009-06-30 06:36:12 +04:00
|
|
|
for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName);
|
2008-12-24 00:31:30 +03:00
|
|
|
Con != ConEnd; ++Con) {
|
2009-06-23 03:34:40 +04:00
|
|
|
if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context,
|
|
|
|
FoundTQs)) {
|
|
|
|
if (((TypeQuals & QualType::Const) == (FoundTQs & QualType::Const)) ||
|
|
|
|
(!(TypeQuals & QualType::Const) && (FoundTQs & QualType::Const)))
|
|
|
|
return cast<CXXConstructorDecl>(*Con);
|
|
|
|
|
|
|
|
}
|
2008-11-03 20:51:48 +03:00
|
|
|
}
|
2009-06-23 03:34:40 +04:00
|
|
|
return 0;
|
2008-11-03 20:51:48 +03:00
|
|
|
}
|
|
|
|
|
2009-08-13 03:34:46 +04:00
|
|
|
bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context,
|
|
|
|
const CXXMethodDecl *& MD) const {
|
2009-01-05 23:52:13 +03:00
|
|
|
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
|
|
|
|
const_cast<CXXRecordDecl*>(this)));
|
|
|
|
DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal);
|
|
|
|
|
|
|
|
DeclContext::lookup_const_iterator Op, OpEnd;
|
2009-06-30 06:36:12 +04:00
|
|
|
for (llvm::tie(Op, OpEnd) = this->lookup(OpName);
|
2009-01-05 23:52:13 +03:00
|
|
|
Op != OpEnd; ++Op) {
|
|
|
|
// C++ [class.copy]p9:
|
|
|
|
// A user-declared copy assignment 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&.
|
|
|
|
const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op);
|
|
|
|
if (Method->isStatic())
|
|
|
|
continue;
|
|
|
|
// TODO: Skip templates? Or is this implicitly done due to parameter types?
|
2009-02-27 02:50:07 +03:00
|
|
|
const FunctionProtoType *FnType =
|
|
|
|
Method->getType()->getAsFunctionProtoType();
|
2009-01-05 23:52:13 +03:00
|
|
|
assert(FnType && "Overloaded operator has no prototype.");
|
|
|
|
// Don't assert on this; an invalid decl might have been left in the AST.
|
|
|
|
if (FnType->getNumArgs() != 1 || FnType->isVariadic())
|
|
|
|
continue;
|
|
|
|
bool AcceptsConst = true;
|
|
|
|
QualType ArgType = FnType->getArgType(0);
|
2009-07-30 01:53:49 +04:00
|
|
|
if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) {
|
2009-01-05 23:52:13 +03:00
|
|
|
ArgType = Ref->getPointeeType();
|
2009-03-20 23:21:37 +03:00
|
|
|
// Is it a non-const lvalue reference?
|
2009-01-05 23:52:13 +03:00
|
|
|
if (!ArgType.isConstQualified())
|
|
|
|
AcceptsConst = false;
|
|
|
|
}
|
|
|
|
if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType)
|
|
|
|
continue;
|
2009-08-13 03:34:46 +04:00
|
|
|
MD = Method;
|
2009-01-05 23:52:13 +03:00
|
|
|
// We have a single argument of type cv X or cv X&, i.e. we've found the
|
|
|
|
// copy assignment operator. Return whether it accepts const arguments.
|
|
|
|
return AcceptsConst;
|
|
|
|
}
|
|
|
|
assert(isInvalidDecl() &&
|
|
|
|
"No copy assignment operator declared in valid code.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-12-16 00:24:18 +03:00
|
|
|
CXXRecordDecl::addedConstructor(ASTContext &Context,
|
|
|
|
CXXConstructorDecl *ConDecl) {
|
2009-06-18 02:44:31 +04:00
|
|
|
assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl");
|
|
|
|
// Note that we have a user-declared constructor.
|
|
|
|
UserDeclaredConstructor = true;
|
|
|
|
|
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is an array or a class (clause 9) with no
|
|
|
|
// user-declared constructors (12.1) [...].
|
|
|
|
Aggregate = false;
|
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class [...]
|
|
|
|
PlainOldData = false;
|
|
|
|
|
|
|
|
// C++ [class.ctor]p5:
|
|
|
|
// A constructor is trivial if it is an implicitly-declared default
|
|
|
|
// constructor.
|
2009-07-22 22:25:24 +04:00
|
|
|
// FIXME: C++0x: don't do this for "= default" default constructors.
|
2009-06-18 02:44:31 +04:00
|
|
|
HasTrivialConstructor = false;
|
2009-04-16 04:08:20 +04:00
|
|
|
|
2009-06-18 02:44:31 +04:00
|
|
|
// Note when we have a user-declared copy constructor, which will
|
|
|
|
// suppress the implicit declaration of a copy constructor.
|
2009-07-22 22:25:24 +04:00
|
|
|
if (ConDecl->isCopyConstructor(Context)) {
|
2009-06-18 02:44:31 +04:00
|
|
|
UserDeclaredCopyConstructor = true;
|
2009-07-22 22:25:24 +04:00
|
|
|
|
|
|
|
// C++ [class.copy]p6:
|
|
|
|
// A copy constructor is trivial if it is implicitly declared.
|
|
|
|
// FIXME: C++0x: don't do this for "= default" copy constructors.
|
|
|
|
HasTrivialCopyConstructor = false;
|
|
|
|
}
|
2008-10-31 23:25:05 +03:00
|
|
|
}
|
|
|
|
|
2009-01-05 23:52:13 +03:00
|
|
|
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
|
|
|
|
CXXMethodDecl *OpDecl) {
|
|
|
|
// We're interested specifically in copy assignment operators.
|
2009-02-27 02:50:07 +03:00
|
|
|
const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType();
|
2009-01-05 23:52:13 +03:00
|
|
|
assert(FnType && "Overloaded operator has no proto function type.");
|
|
|
|
assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
|
|
|
|
QualType ArgType = FnType->getArgType(0);
|
2009-07-30 01:53:49 +04:00
|
|
|
if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>())
|
2009-01-05 23:52:13 +03:00
|
|
|
ArgType = Ref->getPointeeType();
|
|
|
|
|
|
|
|
ArgType = ArgType.getUnqualifiedType();
|
|
|
|
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
|
|
|
|
const_cast<CXXRecordDecl*>(this)));
|
|
|
|
|
|
|
|
if (ClassType != Context.getCanonicalType(ArgType))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// This is a copy assignment operator.
|
|
|
|
// Suppress the implicit declaration of a copy constructor.
|
|
|
|
UserDeclaredCopyAssignment = true;
|
|
|
|
|
2009-07-22 22:25:24 +04:00
|
|
|
// C++ [class.copy]p11:
|
|
|
|
// A copy assignment operator is trivial if it is implicitly declared.
|
|
|
|
// FIXME: C++0x: don't do this for "= default" copy operators.
|
|
|
|
HasTrivialCopyAssignment = false;
|
|
|
|
|
2009-01-05 23:52:13 +03:00
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class that [...] has no user-defined copy
|
|
|
|
// assignment operator [...].
|
|
|
|
PlainOldData = false;
|
|
|
|
}
|
|
|
|
|
2008-11-07 23:08:42 +03:00
|
|
|
void CXXRecordDecl::addConversionFunction(ASTContext &Context,
|
|
|
|
CXXConversionDecl *ConvDecl) {
|
|
|
|
Conversions.addOverload(ConvDecl);
|
|
|
|
}
|
|
|
|
|
2009-06-19 23:55:27 +04:00
|
|
|
|
|
|
|
CXXConstructorDecl *
|
|
|
|
CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
|
|
|
|
QualType ClassType = Context.getTypeDeclType(this);
|
|
|
|
DeclarationName ConstructorName
|
|
|
|
= Context.DeclarationNames.getCXXConstructorName(
|
|
|
|
Context.getCanonicalType(ClassType.getUnqualifiedType()));
|
|
|
|
|
|
|
|
DeclContext::lookup_const_iterator Con, ConEnd;
|
2009-06-30 06:36:12 +04:00
|
|
|
for (llvm::tie(Con, ConEnd) = lookup(ConstructorName);
|
2009-06-19 23:55:27 +04:00
|
|
|
Con != ConEnd; ++Con) {
|
|
|
|
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
|
|
|
|
if (Constructor->isDefaultConstructor())
|
|
|
|
return Constructor;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-30 01:03:38 +04:00
|
|
|
const CXXDestructorDecl *
|
|
|
|
CXXRecordDecl::getDestructor(ASTContext &Context) {
|
|
|
|
QualType ClassType = Context.getTypeDeclType(this);
|
2009-06-19 23:55:27 +04:00
|
|
|
|
2009-05-30 01:03:38 +04:00
|
|
|
DeclarationName Name
|
2009-08-05 09:36:45 +04:00
|
|
|
= Context.DeclarationNames.getCXXDestructorName(
|
|
|
|
Context.getCanonicalType(ClassType));
|
2009-05-30 01:03:38 +04:00
|
|
|
|
|
|
|
DeclContext::lookup_iterator I, E;
|
2009-06-30 06:36:12 +04:00
|
|
|
llvm::tie(I, E) = lookup(Name);
|
2009-05-30 01:03:38 +04:00
|
|
|
assert(I != E && "Did not find a destructor!");
|
|
|
|
|
|
|
|
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
|
|
|
|
assert(++I == E && "Found more than one destructor!");
|
|
|
|
|
|
|
|
return Dtor;
|
|
|
|
}
|
|
|
|
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
CXXMethodDecl *
|
|
|
|
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2008-11-18 01:58:34 +03:00
|
|
|
SourceLocation L, DeclarationName N,
|
2009-01-20 04:17:11 +03:00
|
|
|
QualType T, bool isStatic, bool isInline) {
|
2009-01-28 00:25:57 +03:00
|
|
|
return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, isStatic, isInline);
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
}
|
|
|
|
|
2009-05-17 03:58:37 +04:00
|
|
|
|
|
|
|
typedef llvm::DenseMap<const CXXMethodDecl*,
|
|
|
|
std::vector<const CXXMethodDecl *> *>
|
|
|
|
OverriddenMethodsMapTy;
|
|
|
|
|
|
|
|
static OverriddenMethodsMapTy *OverriddenMethods = 0;
|
|
|
|
|
|
|
|
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
|
|
|
|
// FIXME: The CXXMethodDecl dtor needs to remove and free the entry.
|
|
|
|
|
|
|
|
if (!OverriddenMethods)
|
|
|
|
OverriddenMethods = new OverriddenMethodsMapTy();
|
|
|
|
|
|
|
|
std::vector<const CXXMethodDecl *> *&Methods = (*OverriddenMethods)[this];
|
|
|
|
if (!Methods)
|
|
|
|
Methods = new std::vector<const CXXMethodDecl *>;
|
|
|
|
|
|
|
|
Methods->push_back(MD);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const {
|
|
|
|
if (!OverriddenMethods)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this);
|
2009-08-02 03:40:20 +04:00
|
|
|
if (it == OverriddenMethods->end() || it->second->empty())
|
2009-05-17 03:58:37 +04:00
|
|
|
return 0;
|
2009-08-02 03:40:20 +04:00
|
|
|
|
2009-05-17 03:58:37 +04:00
|
|
|
return &(*it->second)[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const {
|
|
|
|
if (!OverriddenMethods)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this);
|
2009-08-02 03:40:20 +04:00
|
|
|
if (it == OverriddenMethods->end() || it->second->empty())
|
2009-05-17 03:58:37 +04:00
|
|
|
return 0;
|
|
|
|
|
2009-08-02 05:48:29 +04:00
|
|
|
return &(*it->second)[0] + it->second->size();
|
2009-05-17 03:58:37 +04:00
|
|
|
}
|
|
|
|
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
QualType CXXMethodDecl::getThisType(ASTContext &C) const {
|
2008-10-25 02:28:18 +04: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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
assert(isInstance() && "No 'this' for static methods!");
|
2009-06-13 06:59:33 +04:00
|
|
|
|
|
|
|
QualType ClassTy;
|
|
|
|
if (ClassTemplateDecl *TD = getParent()->getDescribedClassTemplate())
|
|
|
|
ClassTy = TD->getInjectedClassNameType(C);
|
|
|
|
else
|
2009-08-07 22:05:12 +04:00
|
|
|
ClassTy = C.getTagDeclType(getParent());
|
2008-10-25 01:46:40 +04:00
|
|
|
ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers());
|
2009-07-11 01:35:09 +04: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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
}
|
|
|
|
|
2008-11-05 07:29:56 +03:00
|
|
|
CXXBaseOrMemberInitializer::
|
2009-06-30 04:02:17 +04:00
|
|
|
CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs,
|
2009-07-23 04:42:24 +04:00
|
|
|
CXXConstructorDecl *C,
|
2009-06-30 04:02:17 +04:00
|
|
|
SourceLocation L)
|
|
|
|
: Args(0), NumArgs(0), IdLoc(L) {
|
2008-11-05 07:29:56 +03:00
|
|
|
BaseOrMember = reinterpret_cast<uintptr_t>(BaseType.getTypePtr());
|
|
|
|
assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer");
|
|
|
|
BaseOrMember |= 0x01;
|
|
|
|
|
|
|
|
if (NumArgs > 0) {
|
|
|
|
this->NumArgs = NumArgs;
|
2009-07-24 21:57:02 +04:00
|
|
|
// FIXME. Allocation via Context
|
|
|
|
this->Args = new Stmt*[NumArgs];
|
2008-11-05 07:29:56 +03:00
|
|
|
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
|
|
|
|
this->Args[Idx] = Args[Idx];
|
|
|
|
}
|
2009-07-23 04:42:24 +04:00
|
|
|
CtorToCall = C;
|
2008-11-05 07:29:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXBaseOrMemberInitializer::
|
2009-06-30 04:02:17 +04:00
|
|
|
CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs,
|
2009-07-23 04:42:24 +04:00
|
|
|
CXXConstructorDecl *C,
|
2009-06-30 04:02:17 +04:00
|
|
|
SourceLocation L)
|
|
|
|
: Args(0), NumArgs(0), IdLoc(L) {
|
2008-11-05 07:29:56 +03:00
|
|
|
BaseOrMember = reinterpret_cast<uintptr_t>(Member);
|
|
|
|
assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer");
|
|
|
|
|
|
|
|
if (NumArgs > 0) {
|
|
|
|
this->NumArgs = NumArgs;
|
2009-07-24 21:57:02 +04:00
|
|
|
this->Args = new Stmt*[NumArgs];
|
2008-11-05 07:29:56 +03:00
|
|
|
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
|
|
|
|
this->Args[Idx] = Args[Idx];
|
|
|
|
}
|
2009-07-23 04:42:24 +04:00
|
|
|
CtorToCall = C;
|
2008-11-05 07:29:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() {
|
|
|
|
delete [] Args;
|
|
|
|
}
|
|
|
|
|
2008-10-31 12:07:45 +03:00
|
|
|
CXXConstructorDecl *
|
|
|
|
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2008-11-17 17:58:09 +03:00
|
|
|
SourceLocation L, DeclarationName N,
|
2008-10-31 12:07:45 +03:00
|
|
|
QualType T, bool isExplicit,
|
|
|
|
bool isInline, bool isImplicitlyDeclared) {
|
2008-11-17 17:58:09 +03:00
|
|
|
assert(N.getNameKind() == DeclarationName::CXXConstructorName &&
|
|
|
|
"Name must refer to a constructor");
|
2009-01-28 00:25:57 +03:00
|
|
|
return new (C) CXXConstructorDecl(RD, L, N, T, isExplicit, isInline,
|
2008-10-31 12:07:45 +03:00
|
|
|
isImplicitlyDeclared);
|
|
|
|
}
|
|
|
|
|
2008-10-31 23:25:05 +03:00
|
|
|
bool CXXConstructorDecl::isDefaultConstructor() const {
|
|
|
|
// C++ [class.ctor]p5:
|
2008-11-05 19:20:31 +03:00
|
|
|
// A default constructor for a class X is a constructor of class
|
|
|
|
// X that can be called without an argument.
|
2008-10-31 23:25:05 +03:00
|
|
|
return (getNumParams() == 0) ||
|
2008-11-05 18:29:30 +03:00
|
|
|
(getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0);
|
2008-10-31 23:25:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
|
|
|
|
unsigned &TypeQuals) const {
|
|
|
|
// C++ [class.copy]p2:
|
2008-11-05 19:20:31 +03: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).
|
2008-10-31 23:25:05 +03:00
|
|
|
if ((getNumParams() < 1) ||
|
2009-06-06 08:14:07 +04:00
|
|
|
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()))
|
2008-10-31 23:25:05 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
const ParmVarDecl *Param = getParamDecl(0);
|
|
|
|
|
2009-03-17 02:22:08 +03:00
|
|
|
// Do we have a reference type? Rvalue references don't count.
|
|
|
|
const LValueReferenceType *ParamRefType =
|
2009-07-30 01:53:49 +04:00
|
|
|
Param->getType()->getAs<LValueReferenceType>();
|
2008-10-31 23:25:05 +03:00
|
|
|
if (!ParamRefType)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Is it a reference to our class type?
|
2009-08-07 22:05:12 +04:00
|
|
|
QualType PointeeType
|
2008-10-31 23:25:05 +03:00
|
|
|
= Context.getCanonicalType(ParamRefType->getPointeeType());
|
2009-08-07 22:05:12 +04:00
|
|
|
QualType ClassTy = Context.getTagDeclType(getParent());
|
2008-10-31 23:25:05 +03:00
|
|
|
if (PointeeType.getUnqualifiedType() != ClassTy)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// We have a copy constructor.
|
|
|
|
TypeQuals = PointeeType.getCVRQualifiers();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-10-31 19:23:19 +03:00
|
|
|
bool CXXConstructorDecl::isConvertingConstructor() const {
|
|
|
|
// 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.
|
|
|
|
if (isExplicit())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return (getNumParams() == 0 &&
|
2009-02-27 02:50:07 +03:00
|
|
|
getType()->getAsFunctionProtoType()->isVariadic()) ||
|
2008-10-31 19:23:19 +03:00
|
|
|
(getNumParams() == 1) ||
|
2009-06-06 08:14:07 +04:00
|
|
|
(getNumParams() > 1 && getParamDecl(1)->hasDefaultArg());
|
2008-10-31 19:23:19 +03:00
|
|
|
}
|
2008-10-31 12:07:45 +03:00
|
|
|
|
2008-11-05 23:51:48 +03:00
|
|
|
CXXDestructorDecl *
|
|
|
|
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2008-11-17 17:58:09 +03:00
|
|
|
SourceLocation L, DeclarationName N,
|
2008-11-05 23:51:48 +03:00
|
|
|
QualType T, bool isInline,
|
|
|
|
bool isImplicitlyDeclared) {
|
2008-11-17 17:58:09 +03:00
|
|
|
assert(N.getNameKind() == DeclarationName::CXXDestructorName &&
|
|
|
|
"Name must refer to a destructor");
|
2009-01-28 00:25:57 +03:00
|
|
|
return new (C) CXXDestructorDecl(RD, L, N, T, isInline,
|
|
|
|
isImplicitlyDeclared);
|
2008-11-05 23:51:48 +03:00
|
|
|
}
|
|
|
|
|
2009-07-16 02:34:08 +04:00
|
|
|
void
|
2009-07-22 02:36:06 +04:00
|
|
|
CXXDestructorDecl::Destroy(ASTContext& C) {
|
|
|
|
C.Deallocate(BaseOrMemberDestructions);
|
|
|
|
CXXMethodDecl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CXXDestructorDecl::computeBaseOrMembersToDestroy(ASTContext &C) {
|
2009-07-16 02:34:08 +04:00
|
|
|
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(getDeclContext());
|
2009-07-22 02:36:06 +04:00
|
|
|
llvm::SmallVector<uintptr_t, 32> AllToDestruct;
|
|
|
|
|
2009-07-16 02:34:08 +04:00
|
|
|
for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
|
|
|
|
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
|
2009-07-22 02:36:06 +04:00
|
|
|
// Skip over virtual bases which have trivial destructors.
|
|
|
|
CXXRecordDecl *BaseClassDecl
|
2009-07-30 01:53:49 +04:00
|
|
|
= cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
|
2009-07-22 02:36:06 +04:00
|
|
|
if (BaseClassDecl->hasTrivialDestructor())
|
|
|
|
continue;
|
|
|
|
uintptr_t Member =
|
2009-07-22 04:42:46 +04:00
|
|
|
reinterpret_cast<uintptr_t>(VBase->getType().getTypePtr()) | VBASE;
|
2009-07-16 02:34:08 +04:00
|
|
|
AllToDestruct.push_back(Member);
|
|
|
|
}
|
|
|
|
for (CXXRecordDecl::base_class_iterator Base =
|
|
|
|
ClassDecl->bases_begin(),
|
|
|
|
E = ClassDecl->bases_end(); Base != E; ++Base) {
|
|
|
|
if (Base->isVirtual())
|
|
|
|
continue;
|
2009-07-22 02:36:06 +04:00
|
|
|
// Skip over virtual bases which have trivial destructors.
|
|
|
|
CXXRecordDecl *BaseClassDecl
|
2009-07-30 01:53:49 +04:00
|
|
|
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
2009-07-22 02:36:06 +04:00
|
|
|
if (BaseClassDecl->hasTrivialDestructor())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
uintptr_t Member =
|
2009-07-22 04:42:46 +04:00
|
|
|
reinterpret_cast<uintptr_t>(Base->getType().getTypePtr()) | DRCTNONVBASE;
|
2009-07-16 02:34:08 +04:00
|
|
|
AllToDestruct.push_back(Member);
|
|
|
|
}
|
2009-07-22 02:36:06 +04:00
|
|
|
|
2009-07-16 02:34:08 +04:00
|
|
|
// non-static data members.
|
|
|
|
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
|
|
|
E = ClassDecl->field_end(); Field != E; ++Field) {
|
2009-07-24 03:49:00 +04:00
|
|
|
QualType FieldType = C.getBaseElementType((*Field)->getType());
|
2009-07-16 02:34:08 +04:00
|
|
|
|
2009-07-30 01:53:49 +04:00
|
|
|
if (const RecordType* RT = FieldType->getAs<RecordType>()) {
|
2009-07-22 02:36:06 +04:00
|
|
|
// Skip over virtual bases which have trivial destructors.
|
2009-07-24 03:49:00 +04:00
|
|
|
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
|
2009-07-22 02:36:06 +04:00
|
|
|
if (BaseClassDecl->hasTrivialDestructor())
|
|
|
|
continue;
|
|
|
|
uintptr_t Member = reinterpret_cast<uintptr_t>(*Field);
|
2009-07-16 02:34:08 +04:00
|
|
|
AllToDestruct.push_back(Member);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned NumDestructions = AllToDestruct.size();
|
|
|
|
if (NumDestructions > 0) {
|
|
|
|
NumBaseOrMemberDestructions = NumDestructions;
|
2009-07-22 02:36:06 +04:00
|
|
|
BaseOrMemberDestructions = new (C) uintptr_t [NumDestructions];
|
2009-07-16 02:34:08 +04:00
|
|
|
// Insert in reverse order.
|
|
|
|
for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx)
|
|
|
|
BaseOrMemberDestructions[i++] = AllToDestruct[Idx];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 01:05:43 +04:00
|
|
|
void
|
|
|
|
CXXConstructorDecl::setBaseOrMemberInitializers(
|
2009-07-24 03:32:59 +04:00
|
|
|
ASTContext &C,
|
|
|
|
CXXBaseOrMemberInitializer **Initializers,
|
|
|
|
unsigned NumInitializers,
|
|
|
|
llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,
|
|
|
|
llvm::SmallVectorImpl<FieldDecl *>&Fields) {
|
2009-07-14 22:24:21 +04:00
|
|
|
// We need to build the initializer AST according to order of construction
|
|
|
|
// and not what user specified in the Initializers list.
|
|
|
|
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(getDeclContext());
|
|
|
|
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
|
2009-07-23 00:25:00 +04:00
|
|
|
llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumInitializers; i++) {
|
|
|
|
CXXBaseOrMemberInitializer *Member = Initializers[i];
|
2009-07-25 05:08:28 +04:00
|
|
|
if (Member->isBaseInitializer())
|
2009-07-30 01:53:49 +04:00
|
|
|
AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
|
2009-07-25 05:08:28 +04:00
|
|
|
else
|
2009-08-11 03:56:17 +04:00
|
|
|
AllBaseFields[Member->getMember()] = Member;
|
2009-07-23 00:25:00 +04:00
|
|
|
}
|
|
|
|
|
2009-07-14 22:24:21 +04:00
|
|
|
// Push virtual bases before others.
|
|
|
|
for (CXXRecordDecl::base_class_iterator VBase =
|
|
|
|
ClassDecl->vbases_begin(),
|
|
|
|
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
|
2009-07-25 05:08:28 +04:00
|
|
|
if (CXXBaseOrMemberInitializer *Value =
|
2009-07-30 01:53:49 +04:00
|
|
|
AllBaseFields.lookup(VBase->getType()->getAs<RecordType>()))
|
2009-07-25 05:08:28 +04:00
|
|
|
AllToInit.push_back(Value);
|
2009-07-23 00:25:00 +04:00
|
|
|
else {
|
2009-07-23 04:42:24 +04:00
|
|
|
CXXRecordDecl *VBaseDecl =
|
2009-07-30 01:53:49 +04:00
|
|
|
cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
|
2009-07-23 04:42:24 +04:00
|
|
|
assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null");
|
2009-07-24 03:32:59 +04:00
|
|
|
if (!VBaseDecl->getDefaultConstructor(C) &&
|
|
|
|
!VBase->getType()->isDependentType())
|
|
|
|
Bases.push_back(VBase);
|
2009-07-14 22:24:21 +04:00
|
|
|
CXXBaseOrMemberInitializer *Member =
|
2009-07-23 04:42:24 +04:00
|
|
|
new (C) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0,
|
|
|
|
VBaseDecl->getDefaultConstructor(C),
|
|
|
|
SourceLocation());
|
2009-07-14 22:24:21 +04:00
|
|
|
AllToInit.push_back(Member);
|
|
|
|
}
|
|
|
|
}
|
2009-07-23 00:25:00 +04:00
|
|
|
|
2009-07-14 22:24:21 +04:00
|
|
|
for (CXXRecordDecl::base_class_iterator Base =
|
|
|
|
ClassDecl->bases_begin(),
|
|
|
|
E = ClassDecl->bases_end(); Base != E; ++Base) {
|
|
|
|
// Virtuals are in the virtual base list and already constructed.
|
|
|
|
if (Base->isVirtual())
|
|
|
|
continue;
|
2009-07-25 05:08:28 +04:00
|
|
|
if (CXXBaseOrMemberInitializer *Value =
|
2009-07-30 01:53:49 +04:00
|
|
|
AllBaseFields.lookup(Base->getType()->getAs<RecordType>()))
|
2009-07-25 05:08:28 +04:00
|
|
|
AllToInit.push_back(Value);
|
2009-07-23 00:25:00 +04:00
|
|
|
else {
|
2009-07-23 04:42:24 +04:00
|
|
|
CXXRecordDecl *BaseDecl =
|
2009-07-30 01:53:49 +04:00
|
|
|
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
2009-07-23 04:42:24 +04:00
|
|
|
assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
|
2009-07-24 03:32:59 +04:00
|
|
|
if (!BaseDecl->getDefaultConstructor(C) &&
|
|
|
|
!Base->getType()->isDependentType())
|
|
|
|
Bases.push_back(Base);
|
2009-07-14 22:24:21 +04:00
|
|
|
CXXBaseOrMemberInitializer *Member =
|
2009-07-23 00:25:00 +04:00
|
|
|
new (C) CXXBaseOrMemberInitializer(Base->getType(), 0, 0,
|
2009-07-23 04:42:24 +04:00
|
|
|
BaseDecl->getDefaultConstructor(C),
|
2009-07-23 00:25:00 +04:00
|
|
|
SourceLocation());
|
2009-07-14 22:24:21 +04:00
|
|
|
AllToInit.push_back(Member);
|
|
|
|
}
|
|
|
|
}
|
2009-07-23 00:25:00 +04:00
|
|
|
|
2009-07-14 22:24:21 +04:00
|
|
|
// non-static data members.
|
|
|
|
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
|
|
|
|
E = ClassDecl->field_end(); Field != E; ++Field) {
|
2009-08-11 03:56:17 +04:00
|
|
|
if ((*Field)->isAnonymousStructOrUnion()) {
|
|
|
|
if (const RecordType *FieldClassType =
|
|
|
|
Field->getType()->getAs<RecordType>()) {
|
|
|
|
CXXRecordDecl *FieldClassDecl
|
|
|
|
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
|
|
|
for(RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
|
|
|
|
EA = FieldClassDecl->field_end(); FA != EA; FA++) {
|
|
|
|
if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) {
|
2009-08-11 22:49:54 +04:00
|
|
|
// 'Member' is the anonymous union field and 'AnonUnionMember' is
|
|
|
|
// set to the anonymous union data member used in the initializer
|
|
|
|
// list.
|
|
|
|
Value->setMember(*Field);
|
|
|
|
Value->setAnonUnionMember(*FA);
|
2009-08-11 03:56:17 +04:00
|
|
|
AllToInit.push_back(Value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2009-08-11 03:59:59 +04:00
|
|
|
if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
|
2009-07-25 05:08:28 +04:00
|
|
|
AllToInit.push_back(Value);
|
2009-07-23 00:25:00 +04:00
|
|
|
continue;
|
2009-07-14 22:24:21 +04:00
|
|
|
}
|
2009-07-24 03:49:00 +04:00
|
|
|
|
|
|
|
QualType FT = C.getBaseElementType((*Field)->getType());
|
2009-07-30 01:53:49 +04:00
|
|
|
if (const RecordType* RT = FT->getAs<RecordType>()) {
|
2009-07-24 03:49:00 +04:00
|
|
|
CXXConstructorDecl *Ctor =
|
|
|
|
cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(C);
|
|
|
|
if (!Ctor && !FT->isDependentType())
|
2009-07-24 03:32:59 +04:00
|
|
|
Fields.push_back(*Field);
|
2009-07-23 00:25:00 +04:00
|
|
|
CXXBaseOrMemberInitializer *Member =
|
2009-07-23 04:42:24 +04:00
|
|
|
new (C) CXXBaseOrMemberInitializer((*Field), 0, 0,
|
|
|
|
Ctor,
|
|
|
|
SourceLocation());
|
2009-07-23 00:25:00 +04:00
|
|
|
AllToInit.push_back(Member);
|
|
|
|
}
|
2009-07-14 22:24:21 +04:00
|
|
|
}
|
2009-07-31 22:25:34 +04:00
|
|
|
|
2009-07-14 22:24:21 +04:00
|
|
|
NumInitializers = AllToInit.size();
|
2009-07-02 01:05:43 +04:00
|
|
|
if (NumInitializers > 0) {
|
|
|
|
NumBaseOrMemberInitializers = NumInitializers;
|
|
|
|
BaseOrMemberInitializers =
|
2009-07-07 20:24:08 +04:00
|
|
|
new (C) CXXBaseOrMemberInitializer*[NumInitializers];
|
2009-07-02 01:05:43 +04:00
|
|
|
for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
|
2009-07-14 22:24:21 +04:00
|
|
|
BaseOrMemberInitializers[Idx] = AllToInit[Idx];
|
2009-07-02 01:05:43 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 03:35:25 +04:00
|
|
|
void
|
|
|
|
CXXConstructorDecl::Destroy(ASTContext& C) {
|
|
|
|
C.Deallocate(BaseOrMemberInitializers);
|
2009-07-07 20:24:08 +04:00
|
|
|
CXXMethodDecl::Destroy(C);
|
2009-07-02 03:35:25 +04:00
|
|
|
}
|
|
|
|
|
2008-11-07 23:08:42 +03:00
|
|
|
CXXConversionDecl *
|
|
|
|
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2008-11-17 17:58:09 +03:00
|
|
|
SourceLocation L, DeclarationName N,
|
2008-11-07 23:08:42 +03:00
|
|
|
QualType T, bool isInline, bool isExplicit) {
|
2008-11-17 17:58:09 +03:00
|
|
|
assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName &&
|
|
|
|
"Name must refer to a conversion function");
|
2009-01-28 00:25:57 +03:00
|
|
|
return new (C) CXXConversionDecl(RD, L, N, T, isInline, isExplicit);
|
2008-11-07 23:08:42 +03:00
|
|
|
}
|
|
|
|
|
2008-10-21 20:13:35 +04:00
|
|
|
OverloadedFunctionDecl *
|
|
|
|
OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
|
2008-11-17 17:58:09 +03:00
|
|
|
DeclarationName N) {
|
2009-01-28 00:25:57 +03:00
|
|
|
return new (C) OverloadedFunctionDecl(DC, N);
|
2008-10-21 20:13:35 +04:00
|
|
|
}
|
2008-11-04 19:51:42 +03:00
|
|
|
|
2009-06-28 01:05:07 +04:00
|
|
|
void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) {
|
|
|
|
Functions.push_back(F);
|
|
|
|
this->setLocation(F.get()->getLocation());
|
2009-06-26 02:08:12 +04:00
|
|
|
}
|
|
|
|
|
2009-07-08 14:57:20 +04:00
|
|
|
OverloadIterator::reference OverloadIterator::operator*() const {
|
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
|
|
|
|
return FD;
|
|
|
|
|
|
|
|
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
|
|
|
|
return FTD;
|
|
|
|
|
|
|
|
assert(isa<OverloadedFunctionDecl>(D));
|
|
|
|
return *Iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
OverloadIterator &OverloadIterator::operator++() {
|
|
|
|
if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
|
|
|
|
D = 0;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (++Iter == cast<OverloadedFunctionDecl>(D)->function_end())
|
|
|
|
D = 0;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OverloadIterator::Equals(const OverloadIterator &Other) const {
|
|
|
|
if (!D || !Other.D)
|
|
|
|
return D == Other.D;
|
|
|
|
|
|
|
|
if (D != Other.D)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
|
|
|
|
}
|
|
|
|
|
2009-08-12 01:13:21 +04:00
|
|
|
FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,
|
|
|
|
DeclContext *DC,
|
2009-08-11 10:59:38 +04:00
|
|
|
SourceLocation L,
|
|
|
|
DeclarationName N, QualType T,
|
|
|
|
bool isInline,
|
|
|
|
SourceLocation FriendL) {
|
|
|
|
return new (C) FriendFunctionDecl(DC, L, N, T, isInline, FriendL);
|
|
|
|
}
|
2009-08-12 01:13:21 +04:00
|
|
|
|
|
|
|
FriendClassDecl *FriendClassDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L, QualType T,
|
|
|
|
SourceLocation FriendL) {
|
|
|
|
return new (C) FriendClassDecl(DC, L, T, FriendL);
|
|
|
|
}
|
2009-08-11 10:59:38 +04:00
|
|
|
|
2008-11-04 19:51:42 +03:00
|
|
|
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
|
2009-01-05 22:45:36 +03:00
|
|
|
DeclContext *DC,
|
2008-11-04 19:51:42 +03:00
|
|
|
SourceLocation L,
|
2009-01-05 22:45:36 +03:00
|
|
|
LanguageIDs Lang, bool Braces) {
|
2009-01-28 00:25:57 +03:00
|
|
|
return new (C) LinkageSpecDecl(DC, L, Lang, Braces);
|
2008-12-17 01:23:02 +03:00
|
|
|
}
|
2009-02-03 22:21:40 +03:00
|
|
|
|
|
|
|
UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L,
|
|
|
|
SourceLocation NamespaceLoc,
|
2009-05-30 10:31:56 +04:00
|
|
|
SourceRange QualifierRange,
|
|
|
|
NestedNameSpecifier *Qualifier,
|
2009-02-03 22:21:40 +03:00
|
|
|
SourceLocation IdentLoc,
|
|
|
|
NamespaceDecl *Used,
|
|
|
|
DeclContext *CommonAncestor) {
|
2009-05-30 10:31:56 +04:00
|
|
|
return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange,
|
|
|
|
Qualifier, IdentLoc, Used, CommonAncestor);
|
2009-02-03 22:21:40 +03:00
|
|
|
}
|
|
|
|
|
2009-03-29 01:58:02 +03:00
|
|
|
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L,
|
|
|
|
SourceLocation AliasLoc,
|
|
|
|
IdentifierInfo *Alias,
|
2009-05-30 10:48:27 +04:00
|
|
|
SourceRange QualifierRange,
|
|
|
|
NestedNameSpecifier *Qualifier,
|
2009-03-29 01:58:02 +03:00
|
|
|
SourceLocation IdentLoc,
|
|
|
|
NamedDecl *Namespace) {
|
2009-05-30 10:48:27 +04:00
|
|
|
return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange,
|
|
|
|
Qualifier, IdentLoc, Namespace);
|
2009-03-29 01:58:02 +03:00
|
|
|
}
|
|
|
|
|
2009-06-20 04:51:54 +04:00
|
|
|
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L, SourceRange NNR, SourceLocation TargetNL,
|
|
|
|
SourceLocation UL, NamedDecl* Target,
|
|
|
|
NestedNameSpecifier* TargetNNS, bool IsTypeNameArg) {
|
|
|
|
return new (C) UsingDecl(DC, L, NNR, TargetNL, UL, Target,
|
|
|
|
TargetNNS, IsTypeNameArg);
|
|
|
|
}
|
|
|
|
|
2009-03-14 03:25:26 +03:00
|
|
|
StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L, Expr *AssertExpr,
|
|
|
|
StringLiteral *Message) {
|
|
|
|
return new (C) StaticAssertDecl(DC, L, AssertExpr, Message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void StaticAssertDecl::Destroy(ASTContext& C) {
|
|
|
|
AssertExpr->Destroy(C);
|
|
|
|
Message->Destroy(C);
|
|
|
|
this->~StaticAssertDecl();
|
|
|
|
C.Deallocate((void *)this);
|
|
|
|
}
|
|
|
|
|
|
|
|
StaticAssertDecl::~StaticAssertDecl() {
|
|
|
|
}
|
|
|
|
|
2009-03-27 02:46:50 +03:00
|
|
|
static const char *getAccessName(AccessSpecifier AS) {
|
|
|
|
switch (AS) {
|
|
|
|
default:
|
|
|
|
case AS_none:
|
|
|
|
assert("Invalid access specifier!");
|
|
|
|
return 0;
|
|
|
|
case AS_public:
|
|
|
|
return "public";
|
|
|
|
case AS_private:
|
|
|
|
return "private";
|
|
|
|
case AS_protected:
|
|
|
|
return "protected";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
|
|
|
|
AccessSpecifier AS) {
|
|
|
|
return DB << getAccessName(AS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|