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"
|
2009-03-26 05:17:03 +08: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).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-03-14 08:25:26 +08:00
|
|
|
#include "clang/AST/Expr.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
|
|
|
|
2010-02-05 06:26:26 +08:00
|
|
|
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
|
|
|
: UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
|
2009-01-06 04:52:13 +08:00
|
|
|
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
2009-08-16 06:23:00 +08:00
|
|
|
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
|
|
|
Abstract(false), HasTrivialConstructor(true),
|
|
|
|
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
|
2009-09-13 02:26:03 +08:00
|
|
|
HasTrivialDestructor(true), ComputedVisibleConversions(false),
|
|
|
|
Bases(0), NumBases(0), VBases(0), NumVBases(0),
|
2010-02-05 06:26:26 +08:00
|
|
|
Definition(D) {
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
|
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
|
|
|
CXXRecordDecl *PrevDecl,
|
|
|
|
SourceLocation TKL)
|
|
|
|
: RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL),
|
|
|
|
DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0),
|
2009-03-26 05:17:03 +08:00
|
|
|
TemplateOrInstantiation() { }
|
2008-11-13 07:21:09 +08: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).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
2009-07-21 22:46:17 +08:00
|
|
|
SourceLocation TKL,
|
2009-05-16 03:11:46 +08:00
|
|
|
CXXRecordDecl* PrevDecl,
|
|
|
|
bool DelayTypeCreation) {
|
2009-09-09 23:08:12 +08:00
|
|
|
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id,
|
2009-07-30 07:36:44 +08:00
|
|
|
PrevDecl, TKL);
|
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;
|
|
|
|
}
|
|
|
|
|
2008-10-23 01:49:05 +08:00
|
|
|
CXXRecordDecl::~CXXRecordDecl() {
|
2009-07-03 02:26:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CXXRecordDecl::Destroy(ASTContext &C) {
|
2010-02-05 06:26:26 +08:00
|
|
|
if (data().Definition == this) {
|
|
|
|
C.Deallocate(data().Bases);
|
|
|
|
C.Deallocate(data().VBases);
|
|
|
|
C.Deallocate(&data());
|
|
|
|
}
|
2009-07-03 02:26:15 +08:00
|
|
|
this->RecordDecl::Destroy(C);
|
2008-10-23 01:49:05 +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();
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// C++ [dcl.init.aggr]p1:
|
2008-11-06 00:20:31 +08:00
|
|
|
// An aggregate is an array or a class (clause 9) with [...]
|
|
|
|
// no base classes [...].
|
2010-02-05 06:26:26 +08:00
|
|
|
data().Aggregate = false;
|
2008-11-06 00:20:31 +08:00
|
|
|
|
2010-02-05 06:26:26 +08:00
|
|
|
if (data().Bases)
|
|
|
|
C.Deallocate(data().Bases);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-11 04:13:23 +08:00
|
|
|
int vbaseCount = 0;
|
|
|
|
llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
|
|
|
|
bool hasDirectVirtualBase = false;
|
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-02-05 06:26:26 +08:00
|
|
|
data().Bases[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());
|
2009-07-11 04:13:23 +08:00
|
|
|
if (Base->isVirtual())
|
|
|
|
hasDirectVirtualBase = true;
|
2009-09-09 23:08:12 +08:00
|
|
|
for (CXXRecordDecl::base_class_iterator VBase =
|
2009-07-11 04:13:23 +08:00
|
|
|
BaseClassDecl->vbases_begin(),
|
|
|
|
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
|
2009-09-09 23:08:12 +08:00
|
|
|
// Add this vbase to the array of vbases for current class if it is
|
2009-07-11 04:13:23 +08:00
|
|
|
// 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 22:32:10 +08:00
|
|
|
int j;
|
|
|
|
for (j = 0; j < vbaseCount; ++j)
|
|
|
|
if (UniqueVbases[j]->getType() == VBase->getType())
|
2009-07-11 04:13:23 +08:00
|
|
|
break;
|
2009-07-11 22:32:10 +08:00
|
|
|
if (j == vbaseCount) {
|
2009-07-11 04:13:23 +08:00
|
|
|
UniqueVbases.push_back(VBase);
|
|
|
|
++vbaseCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vbaseCount > 0) {
|
|
|
|
// build AST for inhireted, direct or indirect, virtual bases.
|
2010-02-05 06:26:26 +08:00
|
|
|
data().VBases = new (C) CXXBaseSpecifier [vbaseCount];
|
|
|
|
data().NumVBases = vbaseCount;
|
2009-07-11 04:13:23 +08:00
|
|
|
for (int i = 0; i < vbaseCount; i++) {
|
|
|
|
QualType QT = UniqueVbases[i]->getType();
|
2010-02-27 08:25:28 +08:00
|
|
|
// Skip dependent types; we can't do any checking on them now.
|
|
|
|
if (QT->isDependentType())
|
|
|
|
continue;
|
2009-07-11 04:13:23 +08:00
|
|
|
CXXRecordDecl *VBaseClassDecl
|
2009-07-30 05:53:49 +08:00
|
|
|
= cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
|
2010-02-05 06:26:26 +08:00
|
|
|
data().VBases[i] =
|
2009-07-23 04:55:49 +08:00
|
|
|
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
|
|
|
|
VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
|
|
|
|
UniqueVbases[i]->getAccessSpecifier(), QT);
|
2009-07-11 04:13:23 +08:00
|
|
|
}
|
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
|
2008-11-04 01:51:48 +08:00
|
|
|
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
|
2009-09-25 03:53:00 +08:00
|
|
|
return getCopyConstructor(Context, Qualifiers::Const) != 0;
|
2009-06-23 07:34:40 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
|
2009-06-23 07:34:40 +08:00
|
|
|
unsigned TypeQuals) const{
|
2009-01-06 04:52:13 +08:00
|
|
|
QualType ClassType
|
|
|
|
= Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclarationName ConstructorName
|
2008-12-16 05:24:18 +08:00
|
|
|
= Context.DeclarationNames.getCXXConstructorName(
|
2009-06-23 07:34:40 +08:00
|
|
|
Context.getCanonicalType(ClassType));
|
|
|
|
unsigned FoundTQs;
|
2008-12-24 05:31:30 +08:00
|
|
|
DeclContext::lookup_const_iterator Con, ConEnd;
|
2009-06-30 10:36:12 +08:00
|
|
|
for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName);
|
2008-12-24 05:31:30 +08:00
|
|
|
Con != ConEnd; ++Con) {
|
2009-09-04 22:46:39 +08:00
|
|
|
// C++ [class.copy]p2:
|
|
|
|
// A non-template constructor for class X is a copy constructor if [...]
|
|
|
|
if (isa<FunctionTemplateDecl>(*Con))
|
|
|
|
continue;
|
|
|
|
|
2009-12-22 08:34:07 +08:00
|
|
|
if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(FoundTQs)) {
|
2009-09-25 03:53:00 +08:00
|
|
|
if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) ||
|
|
|
|
(!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const)))
|
2009-06-23 07:34:40 +08:00
|
|
|
return cast<CXXConstructorDecl>(*Con);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-23 07:34:40 +08:00
|
|
|
}
|
2008-11-04 01:51:48 +08:00
|
|
|
}
|
2009-06-23 07:34:40 +08:00
|
|
|
return 0;
|
2008-11-04 01:51:48 +08:00
|
|
|
}
|
|
|
|
|
2009-08-13 07:34:46 +08:00
|
|
|
bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context,
|
|
|
|
const CXXMethodDecl *& MD) const {
|
2009-01-06 04:52:13 +08: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 10:36:12 +08:00
|
|
|
for (llvm::tie(Op, OpEnd) = this->lookup(OpName);
|
2009-01-06 04:52:13 +08: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&.
|
2009-10-31 06:48:49 +08:00
|
|
|
const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op);
|
|
|
|
if (!Method)
|
|
|
|
continue;
|
|
|
|
|
2009-01-06 04:52:13 +08:00
|
|
|
if (Method->isStatic())
|
|
|
|
continue;
|
2009-10-14 07:45:19 +08:00
|
|
|
if (Method->getPrimaryTemplate())
|
|
|
|
continue;
|
2009-02-27 07:50:07 +08:00
|
|
|
const FunctionProtoType *FnType =
|
2009-09-22 07:43:11 +08:00
|
|
|
Method->getType()->getAs<FunctionProtoType>();
|
2009-01-06 04:52:13 +08: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 05:53:49 +08:00
|
|
|
if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) {
|
2009-01-06 04:52:13 +08:00
|
|
|
ArgType = Ref->getPointeeType();
|
2009-03-21 04:21:37 +08:00
|
|
|
// Is it a non-const lvalue reference?
|
2009-01-06 04:52:13 +08:00
|
|
|
if (!ArgType.isConstQualified())
|
|
|
|
AcceptsConst = false;
|
|
|
|
}
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (!Context.hasSameUnqualifiedType(ArgType, ClassType))
|
2009-01-06 04:52:13 +08:00
|
|
|
continue;
|
2009-08-13 07:34:46 +08:00
|
|
|
MD = Method;
|
2009-01-06 04:52:13 +08: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
|
2009-09-09 23:08:12 +08:00
|
|
|
CXXRecordDecl::addedConstructor(ASTContext &Context,
|
2008-12-16 05:24:18 +08:00
|
|
|
CXXConstructorDecl *ConDecl) {
|
2009-06-18 06:44:31 +08:00
|
|
|
assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl");
|
|
|
|
// Note that we have a user-declared constructor.
|
2010-02-05 06:26:26 +08:00
|
|
|
data().UserDeclaredConstructor = true;
|
2009-06-18 06:44:31 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// C++ [dcl.init.aggr]p1:
|
2009-06-18 06:44:31 +08:00
|
|
|
// An aggregate is an array or a class (clause 9) with no
|
|
|
|
// user-declared constructors (12.1) [...].
|
2010-02-05 06:26:26 +08:00
|
|
|
data().Aggregate = false;
|
2009-06-18 06:44:31 +08:00
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class [...]
|
2010-02-05 06:26:26 +08:00
|
|
|
data().PlainOldData = false;
|
2009-06-18 06:44:31 +08:00
|
|
|
|
|
|
|
// C++ [class.ctor]p5:
|
|
|
|
// A constructor is trivial if it is an implicitly-declared default
|
|
|
|
// constructor.
|
2009-07-23 02:25:24 +08:00
|
|
|
// FIXME: C++0x: don't do this for "= default" default constructors.
|
2010-02-05 06:26:26 +08:00
|
|
|
data().HasTrivialConstructor = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-18 06:44:31 +08:00
|
|
|
// Note when we have a user-declared copy constructor, which will
|
|
|
|
// suppress the implicit declaration of a copy constructor.
|
2009-12-22 08:34:07 +08:00
|
|
|
if (ConDecl->isCopyConstructor()) {
|
2010-02-05 06:26:26 +08:00
|
|
|
data().UserDeclaredCopyConstructor = true;
|
2009-07-23 02:25:24 +08: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.
|
2010-02-05 06:26:26 +08:00
|
|
|
data().HasTrivialCopyConstructor = false;
|
2009-07-23 02:25:24 +08:00
|
|
|
}
|
2008-11-01 04:25:05 +08:00
|
|
|
}
|
|
|
|
|
2009-01-06 04:52:13 +08:00
|
|
|
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
|
|
|
|
CXXMethodDecl *OpDecl) {
|
|
|
|
// We're interested specifically in copy assignment operators.
|
2009-09-22 07:43:11 +08:00
|
|
|
const FunctionProtoType *FnType = OpDecl->getType()->getAs<FunctionProtoType>();
|
2009-01-06 04:52:13 +08:00
|
|
|
assert(FnType && "Overloaded operator has no proto function type.");
|
|
|
|
assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
|
2009-10-14 07:45:19 +08:00
|
|
|
|
|
|
|
// Copy assignment operators must be non-templates.
|
|
|
|
if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate())
|
|
|
|
return;
|
|
|
|
|
2009-01-06 04:52:13 +08:00
|
|
|
QualType ArgType = FnType->getArgType(0);
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>())
|
2009-01-06 04:52:13 +08:00
|
|
|
ArgType = Ref->getPointeeType();
|
|
|
|
|
|
|
|
ArgType = ArgType.getUnqualifiedType();
|
|
|
|
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
|
|
|
|
const_cast<CXXRecordDecl*>(this)));
|
|
|
|
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
|
2009-01-06 04:52:13 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// This is a copy assignment operator.
|
2009-11-07 08:02:45 +08:00
|
|
|
// Note on the decl that it is a copy assignment operator.
|
|
|
|
OpDecl->setCopyAssignment(true);
|
|
|
|
|
2009-01-06 04:52:13 +08:00
|
|
|
// Suppress the implicit declaration of a copy constructor.
|
2010-02-05 06:26:26 +08:00
|
|
|
data().UserDeclaredCopyAssignment = true;
|
2009-01-06 04:52:13 +08:00
|
|
|
|
2009-07-23 02:25:24 +08: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.
|
2010-02-05 06:26:26 +08:00
|
|
|
data().HasTrivialCopyAssignment = false;
|
2009-07-23 02:25:24 +08:00
|
|
|
|
2009-01-06 04:52:13 +08:00
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class that [...] has no user-defined copy
|
|
|
|
// assignment operator [...].
|
2010-02-05 06:26:26 +08:00
|
|
|
data().PlainOldData = false;
|
2009-01-06 04:52:13 +08:00
|
|
|
}
|
|
|
|
|
2009-10-08 04:43:36 +08:00
|
|
|
void
|
|
|
|
CXXRecordDecl::collectConversionFunctions(
|
2009-11-21 16:51:07 +08:00
|
|
|
llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const
|
2009-10-13 02:36:50 +08:00
|
|
|
{
|
2010-01-20 08:46:10 +08:00
|
|
|
const UnresolvedSetImpl *Cs = getConversionFunctions();
|
|
|
|
for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
|
|
|
|
I != E; ++I) {
|
2009-11-21 16:51:07 +08:00
|
|
|
NamedDecl *TopConv = *I;
|
2009-10-13 02:36:50 +08:00
|
|
|
CanQualType TConvType;
|
2009-10-08 04:43:36 +08:00
|
|
|
if (FunctionTemplateDecl *TConversionTemplate =
|
|
|
|
dyn_cast<FunctionTemplateDecl>(TopConv))
|
|
|
|
TConvType =
|
|
|
|
getASTContext().getCanonicalType(
|
|
|
|
TConversionTemplate->getTemplatedDecl()->getResultType());
|
|
|
|
else
|
|
|
|
TConvType =
|
|
|
|
getASTContext().getCanonicalType(
|
|
|
|
cast<CXXConversionDecl>(TopConv)->getConversionType());
|
|
|
|
ConversionsTypeSet.insert(TConvType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-13 02:26:03 +08:00
|
|
|
/// getNestedVisibleConversionFunctions - imports unique conversion
|
|
|
|
/// functions from base classes into the visible conversion function
|
|
|
|
/// list of the class 'RD'. This is a private helper method.
|
2009-10-08 04:43:36 +08:00
|
|
|
/// TopConversionsTypeSet is the set of conversion functions of the class
|
|
|
|
/// we are interested in. HiddenConversionTypes is set of conversion functions
|
|
|
|
/// of the immediate derived class which hides the conversion functions found
|
|
|
|
/// in current class.
|
2009-09-13 02:26:03 +08:00
|
|
|
void
|
2009-10-08 04:43:36 +08:00
|
|
|
CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
|
2009-10-13 02:36:50 +08:00
|
|
|
const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet,
|
|
|
|
const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes)
|
|
|
|
{
|
2009-10-08 04:43:36 +08:00
|
|
|
bool inTopClass = (RD == this);
|
2009-09-13 02:26:03 +08:00
|
|
|
QualType ClassType = getASTContext().getTypeDeclType(this);
|
2009-09-12 05:44:33 +08:00
|
|
|
if (const RecordType *Record = ClassType->getAs<RecordType>()) {
|
2010-01-20 08:46:10 +08:00
|
|
|
const UnresolvedSetImpl *Cs
|
2009-09-12 05:44:33 +08:00
|
|
|
= cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
|
2009-09-13 03:52:10 +08:00
|
|
|
|
2010-01-20 08:46:10 +08:00
|
|
|
for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
|
|
|
|
I != E; ++I) {
|
2009-11-21 16:51:07 +08:00
|
|
|
NamedDecl *Conv = *I;
|
2009-09-12 05:44:33 +08:00
|
|
|
// Only those conversions not exact match of conversions in current
|
|
|
|
// class are candidateconversion routines.
|
2009-10-13 02:36:50 +08:00
|
|
|
CanQualType ConvType;
|
2009-09-13 03:52:10 +08:00
|
|
|
if (FunctionTemplateDecl *ConversionTemplate =
|
|
|
|
dyn_cast<FunctionTemplateDecl>(Conv))
|
|
|
|
ConvType =
|
|
|
|
getASTContext().getCanonicalType(
|
2009-09-16 07:02:16 +08:00
|
|
|
ConversionTemplate->getTemplatedDecl()->getResultType());
|
2009-09-13 03:52:10 +08:00
|
|
|
else
|
|
|
|
ConvType =
|
2009-09-16 06:15:23 +08:00
|
|
|
getASTContext().getCanonicalType(
|
|
|
|
cast<CXXConversionDecl>(Conv)->getConversionType());
|
2009-10-08 04:43:36 +08:00
|
|
|
// We only add conversion functions found in the base class if they
|
|
|
|
// are not hidden by those found in HiddenConversionTypes which are
|
|
|
|
// the conversion functions in its derived class.
|
|
|
|
if (inTopClass ||
|
|
|
|
(!TopConversionsTypeSet.count(ConvType) &&
|
|
|
|
!HiddenConversionTypes.count(ConvType)) ) {
|
2009-09-13 02:26:03 +08:00
|
|
|
if (FunctionTemplateDecl *ConversionTemplate =
|
|
|
|
dyn_cast<FunctionTemplateDecl>(Conv))
|
|
|
|
RD->addVisibleConversionFunction(ConversionTemplate);
|
|
|
|
else
|
|
|
|
RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv));
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2009-10-09 00:33:37 +08:00
|
|
|
if (getNumBases() == 0 && getNumVBases() == 0)
|
|
|
|
return;
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2009-10-13 02:36:50 +08:00
|
|
|
llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions;
|
2009-10-09 00:33:37 +08:00
|
|
|
if (!inTopClass)
|
|
|
|
collectConversionFunctions(ConversionFunctions);
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2009-09-12 05:44:33 +08:00
|
|
|
for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(),
|
|
|
|
E = vbases_end(); VBase != E; ++VBase) {
|
2009-10-26 01:03:50 +08:00
|
|
|
if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) {
|
|
|
|
CXXRecordDecl *VBaseClassDecl
|
|
|
|
= cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
|
|
|
|
TopConversionsTypeSet,
|
|
|
|
(inTopClass ? TopConversionsTypeSet : ConversionFunctions));
|
|
|
|
}
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
|
|
|
for (CXXRecordDecl::base_class_iterator Base = bases_begin(),
|
|
|
|
E = bases_end(); Base != E; ++Base) {
|
|
|
|
if (Base->isVirtual())
|
|
|
|
continue;
|
2009-10-26 01:03:50 +08:00
|
|
|
if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
|
|
|
|
CXXRecordDecl *BaseClassDecl
|
|
|
|
= cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
|
|
|
|
BaseClassDecl->getNestedVisibleConversionFunctions(RD,
|
|
|
|
TopConversionsTypeSet,
|
|
|
|
(inTopClass ? TopConversionsTypeSet : ConversionFunctions));
|
|
|
|
}
|
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.
|
2010-01-20 08:46:10 +08:00
|
|
|
const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
|
2009-09-13 02:26:03 +08:00
|
|
|
// If root class, all conversions are visible.
|
|
|
|
if (bases_begin() == bases_end())
|
2010-02-05 06:26:26 +08:00
|
|
|
return &data().Conversions;
|
2009-09-13 02:26:03 +08:00
|
|
|
// If visible conversion list is already evaluated, return it.
|
2010-02-05 06:26:26 +08:00
|
|
|
if (data().ComputedVisibleConversions)
|
|
|
|
return &data().VisibleConversions;
|
2009-10-13 02:36:50 +08:00
|
|
|
llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet;
|
2009-10-08 04:43:36 +08:00
|
|
|
collectConversionFunctions(TopConversionsTypeSet);
|
|
|
|
getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
|
|
|
|
TopConversionsTypeSet);
|
2010-02-05 06:26:26 +08:00
|
|
|
data().ComputedVisibleConversions = true;
|
|
|
|
return &data().VisibleConversions;
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
|
|
|
|
2009-09-13 02:26:03 +08:00
|
|
|
void CXXRecordDecl::addVisibleConversionFunction(
|
2009-09-12 05:44:33 +08:00
|
|
|
CXXConversionDecl *ConvDecl) {
|
|
|
|
assert(!ConvDecl->getDescribedFunctionTemplate() &&
|
|
|
|
"Conversion function templates should cast to FunctionTemplateDecl.");
|
2010-02-05 06:26:26 +08:00
|
|
|
data().VisibleConversions.addDecl(ConvDecl);
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
|
|
|
|
2009-09-13 02:26:03 +08:00
|
|
|
void CXXRecordDecl::addVisibleConversionFunction(
|
2009-09-12 05:44:33 +08:00
|
|
|
FunctionTemplateDecl *ConvDecl) {
|
|
|
|
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
|
|
|
|
"Function template is not a conversion function template");
|
2010-02-05 06:26:26 +08:00
|
|
|
data().VisibleConversions.addDecl(ConvDecl);
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
|
|
|
|
2009-09-13 03:02:34 +08:00
|
|
|
void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
|
2009-08-22 07:19:43 +08:00
|
|
|
assert(!ConvDecl->getDescribedFunctionTemplate() &&
|
|
|
|
"Conversion function templates should cast to FunctionTemplateDecl.");
|
2010-02-05 06:26:26 +08:00
|
|
|
data().Conversions.addDecl(ConvDecl);
|
2008-11-08 04:08:42 +08:00
|
|
|
}
|
|
|
|
|
2009-09-13 03:02:34 +08:00
|
|
|
void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
|
2009-08-22 07:19:43 +08:00
|
|
|
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
|
|
|
|
"Function template is not a conversion function template");
|
2010-02-05 06:26:26 +08:00
|
|
|
data().Conversions.addDecl(ConvDecl);
|
2009-08-22 07:19:43 +08:00
|
|
|
}
|
2009-06-20 03:55:27 +08:00
|
|
|
|
2009-12-04 02:44:40 +08:00
|
|
|
|
|
|
|
void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) {
|
|
|
|
Method->setVirtualAsWritten(true);
|
|
|
|
setAggregate(false);
|
|
|
|
setPOD(false);
|
|
|
|
setEmpty(false);
|
|
|
|
setPolymorphic(true);
|
|
|
|
setHasTrivialConstructor(false);
|
|
|
|
setHasTrivialCopyConstructor(false);
|
|
|
|
setHasTrivialCopyAssignment(false);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-10-13 04:18:28 +08:00
|
|
|
MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
|
|
|
|
return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
|
|
|
|
}
|
|
|
|
|
2009-10-08 23:14:33 +08:00
|
|
|
void
|
|
|
|
CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
|
|
|
|
TemplateSpecializationKind TSK) {
|
|
|
|
assert(TemplateOrInstantiation.isNull() &&
|
|
|
|
"Previous template or instantiation?");
|
|
|
|
assert(!isa<ClassTemplateSpecializationDecl>(this));
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(false && "Not a class template or member class specialization");
|
|
|
|
}
|
|
|
|
|
2009-06-20 03:55:27 +08:00
|
|
|
CXXConstructorDecl *
|
|
|
|
CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
|
|
|
|
QualType ClassType = Context.getTypeDeclType(this);
|
|
|
|
DeclarationName ConstructorName
|
|
|
|
= Context.DeclarationNames.getCXXConstructorName(
|
|
|
|
Context.getCanonicalType(ClassType.getUnqualifiedType()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 03:55:27 +08:00
|
|
|
DeclContext::lookup_const_iterator Con, ConEnd;
|
2009-06-30 10:36:12 +08:00
|
|
|
for (llvm::tie(Con, ConEnd) = lookup(ConstructorName);
|
2009-06-20 03:55:27 +08:00
|
|
|
Con != ConEnd; ++Con) {
|
2009-09-04 22:46:39 +08:00
|
|
|
// FIXME: In C++0x, a constructor template can be a default constructor.
|
|
|
|
if (isa<FunctionTemplateDecl>(*Con))
|
|
|
|
continue;
|
|
|
|
|
2009-06-20 03:55:27 +08:00
|
|
|
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
|
|
|
|
if (Constructor->isDefaultConstructor())
|
|
|
|
return Constructor;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-23 08:48:20 +08:00
|
|
|
CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) const {
|
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
|
|
|
|
2010-02-23 08:48:20 +08:00
|
|
|
DeclContext::lookup_const_iterator I, E;
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::tie(I, E) = lookup(Name);
|
2009-05-30 05:03:38 +08:00
|
|
|
assert(I != E && "Did not find a destructor!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-03 01:15:43 +08:00
|
|
|
CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
|
2009-05-30 05:03:38 +08:00
|
|
|
assert(++I == E && "Found more than one destructor!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-30 05:03:38 +08:00
|
|
|
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).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
CXXMethodDecl *
|
|
|
|
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2008-11-18 06:58:34 +08:00
|
|
|
SourceLocation L, DeclarationName N,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2009-08-19 09:27:57 +08:00
|
|
|
bool isStatic, bool isInline) {
|
2009-12-07 10:54:59 +08:00
|
|
|
return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo,
|
2009-08-19 09:27:57 +08:00
|
|
|
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).
llvm-svn: 55839
2008-09-06 01:16:31 +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.
|
|
|
|
for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
|
|
|
|
R.first != R.second; ++R.first) {
|
|
|
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*R.first))
|
|
|
|
if (FD->getNumParams() == 1)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
typedef llvm::DenseMap<const CXXMethodDecl*,
|
|
|
|
std::vector<const CXXMethodDecl *> *>
|
2009-05-17 07:58:37 +08:00
|
|
|
OverriddenMethodsMapTy;
|
|
|
|
|
2009-08-21 09:45:00 +08:00
|
|
|
// FIXME: We hate static data. This doesn't survive PCH saving/loading, and
|
|
|
|
// the vtable building code uses it at CG time.
|
2009-05-17 07:58:37 +08:00
|
|
|
static OverriddenMethodsMapTy *OverriddenMethods = 0;
|
|
|
|
|
|
|
|
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!");
|
|
|
|
|
2009-05-17 07:58:37 +08:00
|
|
|
// FIXME: The CXXMethodDecl dtor needs to remove and free the entry.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-17 07:58:37 +08:00
|
|
|
if (!OverriddenMethods)
|
|
|
|
OverriddenMethods = new OverriddenMethodsMapTy();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-17 07:58:37 +08:00
|
|
|
std::vector<const CXXMethodDecl *> *&Methods = (*OverriddenMethods)[this];
|
|
|
|
if (!Methods)
|
|
|
|
Methods = new std::vector<const CXXMethodDecl *>;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-17 07:58:37 +08:00
|
|
|
Methods->push_back(MD);
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const {
|
|
|
|
if (!OverriddenMethods)
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-17 07:58:37 +08:00
|
|
|
OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this);
|
2009-08-02 07:40:20 +08:00
|
|
|
if (it == OverriddenMethods->end() || it->second->empty())
|
2009-05-17 07:58:37 +08:00
|
|
|
return 0;
|
2009-08-02 07:40:20 +08:00
|
|
|
|
2009-05-17 07:58:37 +08:00
|
|
|
return &(*it->second)[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const {
|
|
|
|
if (!OverriddenMethods)
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-17 07:58:37 +08:00
|
|
|
OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this);
|
2009-08-02 07:40:20 +08:00
|
|
|
if (it == OverriddenMethods->end() || it->second->empty())
|
2009-05-17 07:58:37 +08:00
|
|
|
return 0;
|
|
|
|
|
2009-08-02 09:48:29 +08:00
|
|
|
return &(*it->second)[0] + it->second->size();
|
2009-05-17 07:58:37 +08: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).
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
|
|
|
|
|
|
|
QualType ClassTy;
|
|
|
|
if (ClassTemplateDecl *TD = getParent()->getDescribedClassTemplate())
|
|
|
|
ClassTy = TD->getInjectedClassNameType(C);
|
|
|
|
else
|
2009-08-08 02:05:12 +08:00
|
|
|
ClassTy = C.getTagDeclType(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-01-06 03:06:31 +08:00
|
|
|
return CheckFn->getBody(fn) && !fn->isOutOfLine();
|
2009-12-07 04:50:05 +08:00
|
|
|
}
|
|
|
|
|
2008-11-05 12:29:56 +08:00
|
|
|
CXXBaseOrMemberInitializer::
|
2009-12-03 06:36:29 +08:00
|
|
|
CXXBaseOrMemberInitializer(ASTContext &Context,
|
Rework base and member initialization in constructors, with several
(necessarily simultaneous) changes:
- CXXBaseOrMemberInitializer now contains only a single initializer
rather than a set of initialiation arguments + a constructor. The
single initializer covers all aspects of initialization, including
constructor calls as necessary but also cleanup of temporaries
created by the initializer (which we never handled
before!).
- Rework + simplify code generation for CXXBaseOrMemberInitializers,
since we can now just emit the initializer as an initializer.
- Switched base and member initialization over to the new
initialization code (InitializationSequence), so that it
- Improved diagnostics for the new initialization code when
initializing bases and members, to match the diagnostics produced
by the previous (special-purpose) code.
- Simplify the representation of type-checked constructor initializers in
templates; instead of keeping the fully-type-checked AST, which is
rather hard to undo at template instantiation time, throw away the
type-checked AST and store the raw expressions in the AST. This
simplifies instantiation, but loses a little but of information in
the AST.
- When type-checking implicit base or member initializers within a
dependent context, don't add the generated initializers into the
AST, because they'll look like they were explicit.
- Record in CXXConstructExpr when the constructor call is to
initialize a base class, so that CodeGen does not have to infer it
from context. This ensures that we call the right kind of
constructor.
There are also a few "opportunity" fixes here that were needed to not
regress, for example:
- Diagnose default-initialization of a const-qualified class that
does not have a user-declared default constructor. We had this
diagnostic specifically for bases and members, but missed it for
variables. That's fixed now.
- When defining the implicit constructors, destructor, and
copy-assignment operator, set the CurContext to that constructor
when we're defining the body.
llvm-svn: 94952
2010-01-31 17:12:51 +08:00
|
|
|
TypeSourceInfo *TInfo,
|
|
|
|
SourceLocation L, Expr *Init, SourceLocation R)
|
|
|
|
: BaseOrMember(TInfo), Init(Init), AnonUnionMember(0),
|
2009-12-03 06:36:29 +08:00
|
|
|
LParenLoc(L), RParenLoc(R)
|
|
|
|
{
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXBaseOrMemberInitializer::
|
2009-12-03 06:36:29 +08:00
|
|
|
CXXBaseOrMemberInitializer(ASTContext &Context,
|
|
|
|
FieldDecl *Member, SourceLocation MemberLoc,
|
Rework base and member initialization in constructors, with several
(necessarily simultaneous) changes:
- CXXBaseOrMemberInitializer now contains only a single initializer
rather than a set of initialiation arguments + a constructor. The
single initializer covers all aspects of initialization, including
constructor calls as necessary but also cleanup of temporaries
created by the initializer (which we never handled
before!).
- Rework + simplify code generation for CXXBaseOrMemberInitializers,
since we can now just emit the initializer as an initializer.
- Switched base and member initialization over to the new
initialization code (InitializationSequence), so that it
- Improved diagnostics for the new initialization code when
initializing bases and members, to match the diagnostics produced
by the previous (special-purpose) code.
- Simplify the representation of type-checked constructor initializers in
templates; instead of keeping the fully-type-checked AST, which is
rather hard to undo at template instantiation time, throw away the
type-checked AST and store the raw expressions in the AST. This
simplifies instantiation, but loses a little but of information in
the AST.
- When type-checking implicit base or member initializers within a
dependent context, don't add the generated initializers into the
AST, because they'll look like they were explicit.
- Record in CXXConstructExpr when the constructor call is to
initialize a base class, so that CodeGen does not have to infer it
from context. This ensures that we call the right kind of
constructor.
There are also a few "opportunity" fixes here that were needed to not
regress, for example:
- Diagnose default-initialization of a const-qualified class that
does not have a user-declared default constructor. We had this
diagnostic specifically for bases and members, but missed it for
variables. That's fixed now.
- When defining the implicit constructors, destructor, and
copy-assignment operator, set the CurContext to that constructor
when we're defining the body.
llvm-svn: 94952
2010-01-31 17:12:51 +08:00
|
|
|
SourceLocation L, Expr *Init, SourceLocation R)
|
|
|
|
: BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
|
|
|
|
AnonUnionMember(0), LParenLoc(L), RParenLoc(R)
|
2009-12-03 06:36:29 +08:00
|
|
|
{
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
2009-12-03 06:36:29 +08:00
|
|
|
void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) {
|
Rework base and member initialization in constructors, with several
(necessarily simultaneous) changes:
- CXXBaseOrMemberInitializer now contains only a single initializer
rather than a set of initialiation arguments + a constructor. The
single initializer covers all aspects of initialization, including
constructor calls as necessary but also cleanup of temporaries
created by the initializer (which we never handled
before!).
- Rework + simplify code generation for CXXBaseOrMemberInitializers,
since we can now just emit the initializer as an initializer.
- Switched base and member initialization over to the new
initialization code (InitializationSequence), so that it
- Improved diagnostics for the new initialization code when
initializing bases and members, to match the diagnostics produced
by the previous (special-purpose) code.
- Simplify the representation of type-checked constructor initializers in
templates; instead of keeping the fully-type-checked AST, which is
rather hard to undo at template instantiation time, throw away the
type-checked AST and store the raw expressions in the AST. This
simplifies instantiation, but loses a little but of information in
the AST.
- When type-checking implicit base or member initializers within a
dependent context, don't add the generated initializers into the
AST, because they'll look like they were explicit.
- Record in CXXConstructExpr when the constructor call is to
initialize a base class, so that CodeGen does not have to infer it
from context. This ensures that we call the right kind of
constructor.
There are also a few "opportunity" fixes here that were needed to not
regress, for example:
- Diagnose default-initialization of a const-qualified class that
does not have a user-declared default constructor. We had this
diagnostic specifically for bases and members, but missed it for
variables. That's fixed now.
- When defining the implicit constructors, destructor, and
copy-assignment operator, set the CurContext to that constructor
when we're defining the body.
llvm-svn: 94952
2010-01-31 17:12:51 +08:00
|
|
|
if (Init)
|
|
|
|
Init->Destroy(Context);
|
2009-12-03 06:36:29 +08:00
|
|
|
this->~CXXBaseOrMemberInitializer();
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeLoc CXXBaseOrMemberInitializer::getBaseClassLoc() const {
|
|
|
|
if (isBaseInitializer())
|
2009-12-07 10:54:59 +08:00
|
|
|
return BaseOrMember.get<TypeSourceInfo*>()->getTypeLoc();
|
2009-12-03 06:36:29 +08:00
|
|
|
else
|
|
|
|
return TypeLoc();
|
|
|
|
}
|
|
|
|
|
|
|
|
Type *CXXBaseOrMemberInitializer::getBaseClass() {
|
|
|
|
if (isBaseInitializer())
|
2009-12-07 10:54:59 +08:00
|
|
|
return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr();
|
2009-12-03 06:36:29 +08:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Type *CXXBaseOrMemberInitializer::getBaseClass() const {
|
|
|
|
if (isBaseInitializer())
|
2009-12-07 10:54:59 +08:00
|
|
|
return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr();
|
2009-12-03 06:36:29 +08:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const {
|
|
|
|
if (isMemberInitializer())
|
|
|
|
return getMemberLocation();
|
|
|
|
|
|
|
|
return getBaseClassLoc().getSourceRange().getBegin();
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceRange CXXBaseOrMemberInitializer::getSourceRange() const {
|
|
|
|
return SourceRange(getSourceLocation(), getRParenLoc());
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
2008-10-31 17:07:45 +08:00
|
|
|
CXXConstructorDecl *
|
|
|
|
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2008-11-17 22:58:09 +08:00
|
|
|
SourceLocation L, DeclarationName N,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2009-08-19 09:27:57 +08:00
|
|
|
bool isExplicit,
|
2008-10-31 17:07:45 +08:00
|
|
|
bool isInline, bool isImplicitlyDeclared) {
|
2008-11-17 22:58:09 +08:00
|
|
|
assert(N.getNameKind() == DeclarationName::CXXConstructorName &&
|
|
|
|
"Name must refer to a constructor");
|
2009-12-07 10:54:59 +08:00
|
|
|
return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline,
|
2008-10-31 17:07:45 +08:00
|
|
|
isImplicitlyDeclared);
|
|
|
|
}
|
|
|
|
|
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 {
|
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).
|
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;
|
|
|
|
|
|
|
|
const ParmVarDecl *Param = getParamDecl(0);
|
|
|
|
|
2009-03-17 07:22:08 +08:00
|
|
|
// Do we have a reference type? Rvalue references don't count.
|
2009-11-14 07:59:09 +08:00
|
|
|
const LValueReferenceType *ParamRefType =
|
|
|
|
Param->getType()->getAs<LValueReferenceType>();
|
|
|
|
if (!ParamRefType)
|
|
|
|
return false;
|
2008-11-01 04:25:05 +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;
|
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// FIXME: other qualifiers?
|
|
|
|
|
2008-11-01 04:25:05 +08:00
|
|
|
// We have a copy constructor.
|
|
|
|
TypeQuals = PointeeType.getCVRQualifiers();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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) ||
|
2009-06-06 12:14:07 +08:00
|
|
|
(getNumParams() > 1 && getParamDecl(1)->hasDefaultArg());
|
2008-11-01 00:23:19 +08:00
|
|
|
}
|
2008-10-31 17:07:45 +08:00
|
|
|
|
2009-11-14 09:20:54 +08:00
|
|
|
bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const {
|
|
|
|
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());
|
|
|
|
|
|
|
|
// Strip off the lvalue reference, if any.
|
|
|
|
if (CanQual<LValueReferenceType> ParamRefType
|
|
|
|
= ParamType->getAs<LValueReferenceType>())
|
|
|
|
ParamType = ParamRefType->getPointeeType();
|
|
|
|
|
|
|
|
|
|
|
|
// Is it the same as our our class type?
|
|
|
|
CanQualType ClassTy
|
|
|
|
= Context.getCanonicalType(Context.getTagDeclType(getParent()));
|
|
|
|
if (ParamType.getUnqualifiedType() != ClassTy)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-11-06 04:51:48 +08:00
|
|
|
CXXDestructorDecl *
|
|
|
|
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2008-11-17 22:58:09 +08:00
|
|
|
SourceLocation L, DeclarationName N,
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType T, bool isInline,
|
2008-11-06 04:51:48 +08:00
|
|
|
bool isImplicitlyDeclared) {
|
2008-11-17 22:58:09 +08:00
|
|
|
assert(N.getNameKind() == DeclarationName::CXXDestructorName &&
|
|
|
|
"Name must refer to a destructor");
|
2009-09-09 23:08:12 +08:00
|
|
|
return new (C) CXXDestructorDecl(RD, L, N, T, isInline,
|
2009-01-28 05:25:57 +08:00
|
|
|
isImplicitlyDeclared);
|
2008-11-06 04:51:48 +08:00
|
|
|
}
|
|
|
|
|
2009-07-02 07:35:25 +08:00
|
|
|
void
|
|
|
|
CXXConstructorDecl::Destroy(ASTContext& C) {
|
|
|
|
C.Deallocate(BaseOrMemberInitializers);
|
2009-07-08 00:24:08 +08:00
|
|
|
CXXMethodDecl::Destroy(C);
|
2009-07-02 07:35:25 +08:00
|
|
|
}
|
|
|
|
|
2008-11-08 04:08:42 +08:00
|
|
|
CXXConversionDecl *
|
|
|
|
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2008-11-17 22:58:09 +08:00
|
|
|
SourceLocation L, DeclarationName N,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2009-08-19 09:27:57 +08:00
|
|
|
bool isInline, bool isExplicit) {
|
2008-11-17 22:58:09 +08:00
|
|
|
assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName &&
|
|
|
|
"Name must refer to a conversion function");
|
2009-12-07 10:54:59 +08:00
|
|
|
return new (C) CXXConversionDecl(RD, L, N, T, TInfo, isInline, isExplicit);
|
2008-11-08 04:08:42 +08:00
|
|
|
}
|
|
|
|
|
2009-08-28 15:59:38 +08:00
|
|
|
FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L,
|
|
|
|
FriendUnion Friend,
|
|
|
|
SourceLocation FriendL) {
|
2009-09-01 03:16:38 +08:00
|
|
|
#ifndef NDEBUG
|
2009-08-28 15:59:38 +08:00
|
|
|
if (Friend.is<NamedDecl*>()) {
|
|
|
|
NamedDecl *D = Friend.get<NamedDecl*>();
|
|
|
|
assert(isa<FunctionDecl>(D) ||
|
|
|
|
isa<CXXRecordDecl>(D) ||
|
|
|
|
isa<FunctionTemplateDecl>(D) ||
|
|
|
|
isa<ClassTemplateDecl>(D));
|
2009-12-18 07:21:11 +08:00
|
|
|
|
|
|
|
// As a temporary hack, we permit template instantiation to point
|
|
|
|
// to the original declaration when instantiating members.
|
|
|
|
assert(D->getFriendObjectKind() ||
|
|
|
|
(cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
|
2009-08-28 15:59:38 +08:00
|
|
|
}
|
2009-09-01 03:16:38 +08:00
|
|
|
#endif
|
2009-08-12 05:13:21 +08:00
|
|
|
|
2009-08-28 15:59:38 +08:00
|
|
|
return new (C) FriendDecl(DC, L, Friend, FriendL);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-08-11 14:59:38 +08:00
|
|
|
|
2008-11-05 00:51:42 +08:00
|
|
|
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclContext *DC,
|
2008-11-05 00:51:42 +08:00
|
|
|
SourceLocation L,
|
2009-01-06 03:45:36 +08:00
|
|
|
LanguageIDs Lang, bool Braces) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) LinkageSpecDecl(DC, L, Lang, Braces);
|
2008-12-17 06:23:02 +08:00
|
|
|
}
|
2009-02-04 03:21:40 +08:00
|
|
|
|
|
|
|
UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L,
|
|
|
|
SourceLocation NamespaceLoc,
|
2009-05-30 14:31:56 +08:00
|
|
|
SourceRange QualifierRange,
|
|
|
|
NestedNameSpecifier *Qualifier,
|
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();
|
2009-09-09 23:08:12 +08:00
|
|
|
return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange,
|
2009-05-30 14:31:56 +08:00
|
|
|
Qualifier, IdentLoc, Used, CommonAncestor);
|
2009-02-04 03:21:40 +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);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L,
|
|
|
|
SourceLocation AliasLoc,
|
|
|
|
IdentifierInfo *Alias,
|
2009-05-30 14:48:27 +08:00
|
|
|
SourceRange QualifierRange,
|
|
|
|
NestedNameSpecifier *Qualifier,
|
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();
|
2009-09-09 23:08:12 +08:00
|
|
|
return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange,
|
2009-05-30 14:48:27 +08:00
|
|
|
Qualifier, IdentLoc, Namespace);
|
2009-03-29 06:58:02 +08:00
|
|
|
}
|
|
|
|
|
2009-06-20 08:51:54 +08:00
|
|
|
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC,
|
2009-11-17 13:59:44 +08:00
|
|
|
SourceLocation L, SourceRange NNR, SourceLocation UL,
|
|
|
|
NestedNameSpecifier* TargetNNS, DeclarationName Name,
|
|
|
|
bool IsTypeNameArg) {
|
|
|
|
return new (C) UsingDecl(DC, L, NNR, UL, TargetNNS, Name, IsTypeNameArg);
|
2009-06-20 08:51:54 +08:00
|
|
|
}
|
|
|
|
|
2009-11-18 10:36:19 +08:00
|
|
|
UnresolvedUsingValueDecl *
|
|
|
|
UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation UsingLoc,
|
|
|
|
SourceRange TargetNNR,
|
|
|
|
NestedNameSpecifier *TargetNNS,
|
|
|
|
SourceLocation TargetNameLoc,
|
|
|
|
DeclarationName TargetName) {
|
|
|
|
return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
|
|
|
|
TargetNNR, TargetNNS,
|
|
|
|
TargetNameLoc, TargetName);
|
|
|
|
}
|
|
|
|
|
|
|
|
UnresolvedUsingTypenameDecl *
|
|
|
|
UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation UsingLoc,
|
|
|
|
SourceLocation TypenameLoc,
|
|
|
|
SourceRange TargetNNR,
|
|
|
|
NestedNameSpecifier *TargetNNS,
|
|
|
|
SourceLocation TargetNameLoc,
|
|
|
|
DeclarationName TargetName) {
|
|
|
|
return new (C) UnresolvedUsingTypenameDecl(DC, UsingLoc, TypenameLoc,
|
|
|
|
TargetNNR, TargetNNS,
|
|
|
|
TargetNameLoc,
|
|
|
|
TargetName.getAsIdentifierInfo());
|
2009-08-28 13:30:28 +08:00
|
|
|
}
|
|
|
|
|
2009-03-14 08:25:26 +08: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 07:46:50 +08: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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|