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-03-12 09:19:31 +08:00
|
|
|
Definition(D), FirstFriend(0) {
|
2010-02-05 06:26:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2010-03-29 13:13:12 +08:00
|
|
|
// The set of seen virtual base types.
|
2010-03-30 03:49:09 +08:00
|
|
|
llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes;
|
2010-03-29 13:13:12 +08:00
|
|
|
|
|
|
|
// The virtual bases of this class.
|
|
|
|
llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-05 06:26:26 +08:00
|
|
|
data().Bases = new(C) CXXBaseSpecifier [NumBases];
|
|
|
|
data().NumBases = NumBases;
|
2009-07-11 04:13:23 +08:00
|
|
|
for (unsigned i = 0; i < NumBases; ++i) {
|
2010-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());
|
2010-03-29 13:13:12 +08:00
|
|
|
|
|
|
|
// Now go through all virtual bases of this base and add them.
|
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) {
|
2010-03-29 13:13:12 +08:00
|
|
|
// Add this base if it's not already in the list.
|
2010-03-30 03:49:09 +08:00
|
|
|
if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
|
2010-03-29 13:13:12 +08:00
|
|
|
VBases.push_back(VBase);
|
2009-07-11 04:13:23 +08:00
|
|
|
}
|
2010-03-29 13:13:12 +08:00
|
|
|
|
|
|
|
if (Base->isVirtual()) {
|
|
|
|
// Add this base if it's not already in the list.
|
2010-03-30 03:49:09 +08:00
|
|
|
if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
|
2010-03-29 13:13:12 +08:00
|
|
|
VBases.push_back(Base);
|
2009-07-11 04:13:23 +08:00
|
|
|
}
|
2010-03-29 13:13:12 +08:00
|
|
|
|
2009-07-11 04:13:23 +08:00
|
|
|
}
|
2010-03-29 13:13:12 +08:00
|
|
|
|
|
|
|
if (VBases.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create base specifier for any direct or indirect virtual bases.
|
|
|
|
data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
|
|
|
|
data().NumVBases = VBases.size();
|
|
|
|
for (int I = 0, E = VBases.size(); I != E; ++I) {
|
|
|
|
QualType VBaseType = VBases[I]->getType();
|
|
|
|
|
|
|
|
// Skip dependent types; we can't do any checking on them now.
|
|
|
|
if (VBaseType->isDependentType())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CXXRecordDecl *VBaseClassDecl
|
|
|
|
= cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
|
|
|
|
|
|
|
|
data().VBases[I] =
|
|
|
|
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
|
|
|
|
VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
|
|
|
|
VBases[I]->getAccessSpecifier(), VBaseType);
|
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
|
|
|
}
|
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
|
|
|
|
QualType T;
|
|
|
|
if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
|
|
|
|
T = ConvTemp->getTemplatedDecl()->getResultType();
|
|
|
|
else
|
|
|
|
T = cast<CXXConversionDecl>(Conv)->getConversionType();
|
|
|
|
return Context.getCanonicalType(T);
|
2009-10-08 04:43:36 +08:00
|
|
|
}
|
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
/// Collect the visible conversions of a base class.
|
|
|
|
///
|
|
|
|
/// \param Base a base class of the class we're considering
|
|
|
|
/// \param InVirtual whether this base class is a virtual base (or a base
|
|
|
|
/// of a virtual base)
|
|
|
|
/// \param Access the access along the inheritance path to this base
|
|
|
|
/// \param ParentHiddenTypes the conversions provided by the inheritors
|
|
|
|
/// of this base
|
|
|
|
/// \param Output the set to which to add conversions from non-virtual bases
|
|
|
|
/// \param VOutput the set to which to add conversions from virtual bases
|
|
|
|
/// \param HiddenVBaseCs the set of conversions which were hidden in a
|
|
|
|
/// virtual base along some inheritance path
|
|
|
|
static void CollectVisibleConversions(ASTContext &Context,
|
|
|
|
CXXRecordDecl *Record,
|
|
|
|
bool InVirtual,
|
|
|
|
AccessSpecifier Access,
|
|
|
|
const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
|
|
|
|
UnresolvedSetImpl &Output,
|
|
|
|
UnresolvedSetImpl &VOutput,
|
|
|
|
llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
|
|
|
|
// The set of types which have conversions in this class or its
|
|
|
|
// subclasses. As an optimization, we don't copy the derived set
|
|
|
|
// unless it might change.
|
|
|
|
const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes;
|
|
|
|
llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer;
|
|
|
|
|
|
|
|
// Collect the direct conversions and figure out which conversions
|
|
|
|
// will be hidden in the subclasses.
|
|
|
|
UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
|
|
|
|
if (!Cs.empty()) {
|
|
|
|
HiddenTypesBuffer = ParentHiddenTypes;
|
|
|
|
HiddenTypes = &HiddenTypesBuffer;
|
|
|
|
|
|
|
|
for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) {
|
|
|
|
bool Hidden =
|
|
|
|
!HiddenTypesBuffer.insert(GetConversionType(Context, I.getDecl()));
|
|
|
|
|
|
|
|
// If this conversion is hidden and we're in a virtual base,
|
|
|
|
// remember that it's hidden along some inheritance path.
|
|
|
|
if (Hidden && InVirtual)
|
|
|
|
HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()));
|
|
|
|
|
|
|
|
// If this conversion isn't hidden, add it to the appropriate output.
|
|
|
|
else if (!Hidden) {
|
|
|
|
AccessSpecifier IAccess
|
|
|
|
= CXXRecordDecl::MergeAccess(Access, I.getAccess());
|
|
|
|
|
|
|
|
if (InVirtual)
|
|
|
|
VOutput.addDecl(I.getDecl(), IAccess);
|
2009-09-13 02:26:03 +08:00
|
|
|
else
|
2010-03-15 17:07:48 +08:00
|
|
|
Output.addDecl(I.getDecl(), IAccess);
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
// Collect information recursively from any base classes.
|
|
|
|
for (CXXRecordDecl::base_class_iterator
|
|
|
|
I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
|
|
|
|
const RecordType *RT = I->getType()->getAs<RecordType>();
|
|
|
|
if (!RT) continue;
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
AccessSpecifier BaseAccess
|
|
|
|
= CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier());
|
|
|
|
bool BaseInVirtual = InVirtual || I->isVirtual();
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess,
|
|
|
|
*HiddenTypes, Output, VOutput, HiddenVBaseCs);
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
2010-03-15 17:07:48 +08:00
|
|
|
}
|
2009-10-26 01:03:50 +08:00
|
|
|
|
2010-03-15 17:07:48 +08:00
|
|
|
/// Collect the visible conversions of a class.
|
|
|
|
///
|
|
|
|
/// This would be extremely straightforward if it weren't for virtual
|
|
|
|
/// bases. It might be worth special-casing that, really.
|
|
|
|
static void CollectVisibleConversions(ASTContext &Context,
|
|
|
|
CXXRecordDecl *Record,
|
|
|
|
UnresolvedSetImpl &Output) {
|
|
|
|
// The collection of all conversions in virtual bases that we've
|
|
|
|
// found. These will be added to the output as long as they don't
|
|
|
|
// appear in the hidden-conversions set.
|
|
|
|
UnresolvedSet<8> VBaseCs;
|
|
|
|
|
|
|
|
// The set of conversions in virtual bases that we've determined to
|
|
|
|
// be hidden.
|
|
|
|
llvm::SmallPtrSet<NamedDecl*, 8> HiddenVBaseCs;
|
|
|
|
|
|
|
|
// The set of types hidden by classes derived from this one.
|
|
|
|
llvm::SmallPtrSet<CanQualType, 8> HiddenTypes;
|
|
|
|
|
|
|
|
// Go ahead and collect the direct conversions and add them to the
|
|
|
|
// hidden-types set.
|
|
|
|
UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
|
|
|
|
Output.append(Cs.begin(), Cs.end());
|
|
|
|
for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I)
|
|
|
|
HiddenTypes.insert(GetConversionType(Context, I.getDecl()));
|
|
|
|
|
|
|
|
// Recursively collect conversions from base classes.
|
|
|
|
for (CXXRecordDecl::base_class_iterator
|
|
|
|
I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
|
|
|
|
const RecordType *RT = I->getType()->getAs<RecordType>();
|
|
|
|
if (!RT) continue;
|
|
|
|
|
|
|
|
CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()),
|
|
|
|
I->isVirtual(), I->getAccessSpecifier(),
|
|
|
|
HiddenTypes, Output, VBaseCs, HiddenVBaseCs);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add any unhidden conversions provided by virtual bases.
|
|
|
|
for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())))
|
|
|
|
Output.addDecl(I.getDecl(), I.getAccess());
|
2009-09-12 05:44:33 +08:00
|
|
|
}
|
2009-09-13 02:26:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getVisibleConversionFunctions - get all conversion functions visible
|
|
|
|
/// in current class; including conversion function templates.
|
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;
|
2010-03-15 17:07:48 +08:00
|
|
|
CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
|
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 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-03-15 17:07:48 +08:00
|
|
|
assert(ConvDecl->getDeclContext() == this &&
|
|
|
|
"conversion function does not belong to this record");
|
|
|
|
|
|
|
|
// We intentionally don't use the decl's access here because it
|
|
|
|
// hasn't been set yet. That's really just a misdesign in Sema.
|
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-03-15 17:07:48 +08:00
|
|
|
assert(ConvDecl->getDeclContext() == this &&
|
|
|
|
"conversion function does not belong to this record");
|
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-05-17 07:58:37 +08:00
|
|
|
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
|
2009-12-04 13:51:56 +08:00
|
|
|
assert(MD->isCanonicalDecl() && "Method is not canonical!");
|
2010-01-31 01:42:34 +08:00
|
|
|
assert(!MD->getParent()->isDependentContext() &&
|
|
|
|
"Can't add an overridden method to a class template!");
|
|
|
|
|
2010-03-03 07:58:15 +08:00
|
|
|
getASTContext().addOverriddenMethod(this, MD);
|
2009-05-17 07:58:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const {
|
2010-03-03 07:58:15 +08:00
|
|
|
return getASTContext().overridden_methods_begin(this);
|
2009-05-17 07:58:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const {
|
2010-03-03 07:58:15 +08:00
|
|
|
return getASTContext().overridden_methods_end(this);
|
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
|
|
|
|
2010-03-10 11:28:59 +08:00
|
|
|
QualType ClassTy = C.getTypeDeclType(getParent());
|
|
|
|
|
|
|
|
// Aesthetically we prefer not to synthesize a type as the
|
|
|
|
// InjectedClassNameType of a template pattern: injected class names
|
|
|
|
// are printed without template arguments, which might
|
|
|
|
// surprise/confuse/distract our poor users if they didn't
|
|
|
|
// explicitly write one.
|
|
|
|
if (isa<InjectedClassNameType>(ClassTy))
|
|
|
|
ClassTy = cast<InjectedClassNameType>(ClassTy)->getUnderlyingType();
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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);
|
2010-03-15 18:12:16 +08:00
|
|
|
Decl::Destroy(C);
|
2009-03-14 08:25:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|