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"
|
2010-09-29 08:15:42 +08:00
|
|
|
#include "clang/AST/CXXInheritance.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),
|
2010-07-03 08:47:00 +08:00
|
|
|
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
|
2010-07-03 05:50:04 +08:00
|
|
|
DeclaredCopyAssignment(false), DeclaredDestructor(false),
|
2009-09-13 02:26:03 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-07-02 19:54:55 +08:00
|
|
|
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, EmptyShell Empty) {
|
|
|
|
return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), 0, 0,
|
|
|
|
SourceLocation());
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2010-09-29 03:45:33 +08:00
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is [...] a class with [...] no base classes [...].
|
|
|
|
data().Aggregate = false;
|
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class...
|
|
|
|
data().PlainOldData = false;
|
|
|
|
|
2010-09-29 04:38:10 +08:00
|
|
|
// A class with a non-empty base class is not empty.
|
|
|
|
// FIXME: Standard ref?
|
|
|
|
if (!BaseClassDecl->isEmpty())
|
|
|
|
data().Empty = false;
|
|
|
|
|
2010-09-29 04:50:54 +08:00
|
|
|
// C++ [class.virtual]p1:
|
|
|
|
// A class that declares or inherits a virtual function is called a
|
|
|
|
// polymorphic class.
|
|
|
|
if (BaseClassDecl->isPolymorphic())
|
|
|
|
data().Polymorphic = true;
|
|
|
|
|
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);
|
2010-09-29 04:38:10 +08:00
|
|
|
|
|
|
|
// C++0x [meta.unary.prop] is_empty:
|
|
|
|
// T is a class type, but not a union type, with ... no virtual base
|
|
|
|
// classes
|
|
|
|
data().Empty = false;
|
2010-09-29 04:50:54 +08:00
|
|
|
|
|
|
|
// C++ [class.ctor]p5:
|
|
|
|
// A constructor is trivial if its class has no virtual base classes.
|
|
|
|
data().HasTrivialConstructor = false;
|
|
|
|
|
|
|
|
// C++ [class.copy]p6:
|
|
|
|
// A copy constructor is trivial if its class has no virtual base
|
|
|
|
// classes.
|
|
|
|
data().HasTrivialCopyConstructor = false;
|
|
|
|
|
|
|
|
// C++ [class.copy]p11:
|
|
|
|
// A copy assignment operator is trivial if its class has no virtual
|
|
|
|
// base classes.
|
|
|
|
data().HasTrivialCopyAssignment = false;
|
|
|
|
} else {
|
|
|
|
// C++ [class.ctor]p5:
|
|
|
|
// A constructor is trivial if all the direct base classes of its
|
|
|
|
// class have trivial constructors.
|
|
|
|
if (!BaseClassDecl->hasTrivialConstructor())
|
|
|
|
data().HasTrivialConstructor = false;
|
|
|
|
|
|
|
|
// C++ [class.copy]p6:
|
|
|
|
// A copy constructor is trivial if all the direct base classes of its
|
|
|
|
// class have trivial copy constructors.
|
|
|
|
if (!BaseClassDecl->hasTrivialCopyConstructor())
|
|
|
|
data().HasTrivialCopyConstructor = false;
|
|
|
|
|
|
|
|
// C++ [class.copy]p11:
|
|
|
|
// A copy assignment operator is trivial if all the direct base classes
|
|
|
|
// of its class have trivial copy assignment operators.
|
|
|
|
if (!BaseClassDecl->hasTrivialCopyAssignment())
|
|
|
|
data().HasTrivialCopyAssignment = false;
|
2009-07-11 04:13:23 +08:00
|
|
|
}
|
2010-09-29 04:50:54 +08:00
|
|
|
|
|
|
|
// C++ [class.ctor]p3:
|
|
|
|
// A destructor is trivial if all the direct base classes of its class
|
|
|
|
// have trivial destructors.
|
|
|
|
if (!BaseClassDecl->hasTrivialDestructor())
|
|
|
|
data().HasTrivialDestructor = false;
|
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) {
|
2010-07-27 00:56:01 +08:00
|
|
|
TypeSourceInfo *VBaseTypeInfo = VBases[I]->getTypeSourceInfo();
|
|
|
|
|
2010-03-29 13:13:12 +08:00
|
|
|
// Skip dependent types; we can't do any checking on them now.
|
2010-07-27 00:56:01 +08:00
|
|
|
if (VBaseTypeInfo->getType()->isDependentType())
|
2010-03-29 13:13:12 +08:00
|
|
|
continue;
|
|
|
|
|
2010-07-27 00:56:01 +08:00
|
|
|
CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>(
|
|
|
|
VBaseTypeInfo->getType()->getAs<RecordType>()->getDecl());
|
2010-03-29 13:13:12 +08:00
|
|
|
|
|
|
|
data().VBases[I] =
|
|
|
|
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
|
2010-05-12 05:36:43 +08:00
|
|
|
VBaseClassDecl->getTagKind() == TTK_Class,
|
2010-07-27 00:56:01 +08:00
|
|
|
VBases[I]->getAccessSpecifier(), VBaseTypeInfo);
|
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
|
|
|
}
|
|
|
|
|
2010-07-02 04:59:04 +08:00
|
|
|
/// \brief Perform a simplistic form of overload resolution that only considers
|
|
|
|
/// cv-qualifiers on a single parameter, and return the best overload candidate
|
|
|
|
/// (if there is one).
|
|
|
|
static CXXMethodDecl *
|
|
|
|
GetBestOverloadCandidateSimple(
|
|
|
|
const llvm::SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) {
|
|
|
|
if (Cands.empty())
|
|
|
|
return 0;
|
|
|
|
if (Cands.size() == 1)
|
|
|
|
return Cands[0].first;
|
|
|
|
|
|
|
|
unsigned Best = 0, N = Cands.size();
|
|
|
|
for (unsigned I = 1; I != N; ++I)
|
|
|
|
if (Cands[Best].second.isSupersetOf(Cands[I].second))
|
|
|
|
Best = I;
|
|
|
|
|
|
|
|
for (unsigned I = 1; I != N; ++I)
|
|
|
|
if (Cands[Best].second.isSupersetOf(Cands[I].second))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return Cands[Best].first;
|
|
|
|
}
|
|
|
|
|
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;
|
2010-07-02 04:59:04 +08:00
|
|
|
llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
|
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;
|
|
|
|
|
2010-07-02 04:59:04 +08:00
|
|
|
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
|
|
|
|
if (Constructor->isCopyConstructor(FoundTQs)) {
|
2009-09-25 03:53:00 +08:00
|
|
|
if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) ||
|
|
|
|
(!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const)))
|
2010-07-02 04:59:04 +08:00
|
|
|
Found.push_back(std::make_pair(
|
|
|
|
const_cast<CXXConstructorDecl *>(Constructor),
|
|
|
|
Qualifiers::fromCVRMask(FoundTQs)));
|
2009-06-23 07:34:40 +08:00
|
|
|
}
|
2008-11-04 01:51:48 +08:00
|
|
|
}
|
2010-07-02 04:59:04 +08:00
|
|
|
|
|
|
|
return cast_or_null<CXXConstructorDecl>(
|
|
|
|
GetBestOverloadCandidateSimple(Found));
|
2008-11-04 01:51:48 +08:00
|
|
|
}
|
|
|
|
|
2010-07-02 01:48:08 +08:00
|
|
|
CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
|
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
|
|
|
|
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
|
|
|
|
|
|
|
|
llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
|
|
|
|
DeclContext::lookup_const_iterator Op, OpEnd;
|
|
|
|
for (llvm::tie(Op, OpEnd) = this->lookup(Name); Op != OpEnd; ++Op) {
|
|
|
|
// C++ [class.copy]p9:
|
|
|
|
// A user-declared copy assignment operator is a non-static non-template
|
|
|
|
// member function of class X with exactly one parameter of type X, X&,
|
|
|
|
// const X&, volatile X& or const volatile X&.
|
|
|
|
const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op);
|
|
|
|
if (!Method || Method->isStatic() || Method->getPrimaryTemplate())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const FunctionProtoType *FnType
|
|
|
|
= Method->getType()->getAs<FunctionProtoType>();
|
|
|
|
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;
|
|
|
|
|
|
|
|
QualType ArgType = FnType->getArgType(0);
|
|
|
|
Qualifiers Quals;
|
|
|
|
if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) {
|
|
|
|
ArgType = Ref->getPointeeType();
|
|
|
|
// If we have a const argument and we have a reference to a non-const,
|
|
|
|
// this function does not match.
|
|
|
|
if (ArgIsConst && !ArgType.isConstQualified())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Quals = ArgType.getQualifiers();
|
|
|
|
} else {
|
|
|
|
// By-value copy-assignment operators are treated like const X&
|
|
|
|
// copy-assignment operators.
|
|
|
|
Quals = Qualifiers::fromCVRMask(Qualifiers::Const);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Context.hasSameUnqualifiedType(ArgType, Class))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Save this copy-assignment operator. It might be "the one".
|
|
|
|
Found.push_back(std::make_pair(const_cast<CXXMethodDecl *>(Method), Quals));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use a simplistic form of overload resolution to find the candidate.
|
|
|
|
return GetBestOverloadCandidateSimple(Found);
|
|
|
|
}
|
|
|
|
|
2010-09-29 05:55:22 +08:00
|
|
|
void CXXRecordDecl::markedVirtualFunctionPure() {
|
|
|
|
// C++ [class.abstract]p2:
|
|
|
|
// A class is abstract if it has at least one pure virtual function.
|
|
|
|
data().Abstract = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CXXRecordDecl::addedMember(Decl *D) {
|
2010-09-28 06:06:20 +08:00
|
|
|
// Ignore friends and invalid declarations.
|
|
|
|
if (D->getFriendObjectKind() || D->isInvalidDecl())
|
2010-09-28 05:17:54 +08:00
|
|
|
return;
|
|
|
|
|
2010-09-28 06:06:20 +08:00
|
|
|
FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
|
|
|
|
if (FunTmpl)
|
|
|
|
D = FunTmpl->getTemplatedDecl();
|
|
|
|
|
2010-09-29 03:45:33 +08:00
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
|
|
|
|
if (Method->isVirtual()) {
|
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is an array or a class with [...] no virtual functions.
|
|
|
|
data().Aggregate = false;
|
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class...
|
|
|
|
data().PlainOldData = false;
|
2010-09-29 04:38:10 +08:00
|
|
|
|
|
|
|
// Virtual functions make the class non-empty.
|
|
|
|
// FIXME: Standard ref?
|
|
|
|
data().Empty = false;
|
2010-09-29 04:50:54 +08:00
|
|
|
|
|
|
|
// C++ [class.virtual]p1:
|
|
|
|
// A class that declares or inherits a virtual function is called a
|
|
|
|
// polymorphic class.
|
|
|
|
data().Polymorphic = true;
|
|
|
|
|
|
|
|
// None of the special member functions are trivial.
|
|
|
|
data().HasTrivialConstructor = false;
|
|
|
|
data().HasTrivialCopyConstructor = false;
|
|
|
|
data().HasTrivialCopyAssignment = false;
|
|
|
|
// FIXME: Destructor?
|
2010-09-29 03:45:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-28 06:06:20 +08:00
|
|
|
if (D->isImplicit()) {
|
2010-10-21 07:48:42 +08:00
|
|
|
// Notify the serializer that an implicit member changed the definition.
|
|
|
|
// A chained PCH will write the whole definition again.
|
|
|
|
// FIXME: Make a notification about the specific change (through a listener
|
|
|
|
// interface) so the changes that the serializer records are more
|
|
|
|
// fine grained.
|
|
|
|
data().Definition->setChangedSinceDeserialization(true);
|
|
|
|
|
2010-09-28 06:06:20 +08:00
|
|
|
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
|
|
|
// If this is the implicit default constructor, note that we have now
|
|
|
|
// declared it.
|
|
|
|
if (Constructor->isDefaultConstructor())
|
|
|
|
data().DeclaredDefaultConstructor = true;
|
|
|
|
// If this is the implicit copy constructor, note that we have now
|
|
|
|
// declared it.
|
|
|
|
else if (Constructor->isCopyConstructor())
|
|
|
|
data().DeclaredCopyConstructor = true;
|
2010-09-29 04:38:10 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isa<CXXDestructorDecl>(D)) {
|
2010-09-28 06:48:58 +08:00
|
|
|
data().DeclaredDestructor = true;
|
2010-09-29 04:38:10 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
|
2010-09-28 06:06:20 +08:00
|
|
|
// If this is the implicit copy constructor, note that we have now
|
|
|
|
// declared it.
|
|
|
|
// FIXME: Move constructors
|
2010-09-28 06:37:28 +08:00
|
|
|
if (Method->getOverloadedOperator() == OO_Equal)
|
2010-09-28 06:06:20 +08:00
|
|
|
data().DeclaredCopyAssignment = true;
|
2010-09-29 04:38:10 +08:00
|
|
|
return;
|
2010-09-28 06:06:20 +08:00
|
|
|
}
|
2010-09-29 04:38:10 +08:00
|
|
|
|
|
|
|
// Any other implicit declarations are handled like normal declarations.
|
2010-09-28 05:17:54 +08:00
|
|
|
}
|
|
|
|
|
2010-09-28 06:06:20 +08:00
|
|
|
// Handle (user-declared) constructors.
|
|
|
|
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
|
|
|
// Note that we have a user-declared constructor.
|
|
|
|
data().UserDeclaredConstructor = true;
|
2009-06-18 06:44:31 +08:00
|
|
|
|
2010-09-28 06:06:20 +08:00
|
|
|
// Note that we have no need of an implicitly-declared default constructor.
|
|
|
|
data().DeclaredDefaultConstructor = true;
|
2010-07-03 07:41:54 +08:00
|
|
|
|
2010-09-28 06:06:20 +08:00
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is an array or a class (clause 9) with no
|
|
|
|
// user-declared constructors (12.1) [...].
|
|
|
|
data().Aggregate = false;
|
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class [...]
|
|
|
|
data().PlainOldData = false;
|
|
|
|
|
|
|
|
// C++ [class.ctor]p5:
|
|
|
|
// A constructor is trivial if it is an implicitly-declared default
|
|
|
|
// constructor.
|
|
|
|
// FIXME: C++0x: don't do this for "= default" default constructors.
|
|
|
|
data().HasTrivialConstructor = false;
|
|
|
|
|
|
|
|
// Note when we have a user-declared copy constructor, which will
|
|
|
|
// suppress the implicit declaration of a copy constructor.
|
|
|
|
if (!FunTmpl && Constructor->isCopyConstructor()) {
|
|
|
|
data().UserDeclaredCopyConstructor = true;
|
|
|
|
data().DeclaredCopyConstructor = true;
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
data().HasTrivialCopyConstructor = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
2009-07-23 02:25:24 +08:00
|
|
|
}
|
2008-11-01 04:25:05 +08:00
|
|
|
|
2010-09-28 06:48:58 +08:00
|
|
|
// Handle (user-declared) destructors.
|
|
|
|
if (isa<CXXDestructorDecl>(D)) {
|
|
|
|
data().DeclaredDestructor = true;
|
|
|
|
data().UserDeclaredDestructor = true;
|
2010-09-29 03:45:33 +08:00
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class that has [...] no user-defined
|
|
|
|
// destructor.
|
|
|
|
data().PlainOldData = false;
|
|
|
|
|
2010-09-29 04:50:54 +08:00
|
|
|
// C++ [class.dtor]p3:
|
|
|
|
// A destructor is trivial if it is an implicitly-declared destructor and
|
|
|
|
// [...].
|
|
|
|
//
|
|
|
|
// FIXME: C++0x: don't do this for "= default" destructors
|
|
|
|
data().HasTrivialDestructor = false;
|
|
|
|
|
2010-09-28 06:48:58 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 07:45:19 +08:00
|
|
|
|
2010-09-28 06:48:58 +08:00
|
|
|
// Handle (user-declared) member functions.
|
2010-09-28 06:06:20 +08:00
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
|
|
|
|
if (Method->getOverloadedOperator() == OO_Equal) {
|
|
|
|
// We're interested specifically in copy assignment operators.
|
|
|
|
const FunctionProtoType *FnType
|
|
|
|
= Method->getType()->getAs<FunctionProtoType>();
|
|
|
|
assert(FnType && "Overloaded operator has no proto function type.");
|
|
|
|
assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
|
|
|
|
|
|
|
|
// Copy assignment operators must be non-templates.
|
|
|
|
if (Method->getPrimaryTemplate() || FunTmpl)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
QualType ArgType = FnType->getArgType(0);
|
|
|
|
if (const LValueReferenceType *Ref =ArgType->getAs<LValueReferenceType>())
|
|
|
|
ArgType = Ref->getPointeeType();
|
|
|
|
|
|
|
|
ArgType = ArgType.getUnqualifiedType();
|
|
|
|
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
|
|
|
|
const_cast<CXXRecordDecl*>(this)));
|
|
|
|
|
|
|
|
if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// This is a copy assignment operator.
|
2010-09-28 06:37:28 +08:00
|
|
|
// FIXME: Move assignment operators.
|
2010-09-28 06:06:20 +08:00
|
|
|
|
|
|
|
// Suppress the implicit declaration of a copy constructor.
|
|
|
|
data().UserDeclaredCopyAssignment = true;
|
|
|
|
data().DeclaredCopyAssignment = true;
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
data().HasTrivialCopyAssignment = false;
|
|
|
|
|
|
|
|
// C++ [class]p4:
|
|
|
|
// A POD-struct is an aggregate class that [...] has no user-defined copy
|
|
|
|
// assignment operator [...].
|
|
|
|
data().PlainOldData = false;
|
|
|
|
}
|
|
|
|
|
2010-09-29 12:25:11 +08:00
|
|
|
// Keep the list of conversion functions up-to-date.
|
|
|
|
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
|
|
|
|
// We don't record specializations.
|
|
|
|
if (Conversion->getPrimaryTemplate())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// FIXME: 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.
|
|
|
|
|
|
|
|
if (FunTmpl) {
|
|
|
|
if (FunTmpl->getPreviousDeclaration())
|
|
|
|
data().Conversions.replace(FunTmpl->getPreviousDeclaration(),
|
|
|
|
FunTmpl);
|
|
|
|
else
|
|
|
|
data().Conversions.addDecl(FunTmpl);
|
|
|
|
} else {
|
|
|
|
if (Conversion->getPreviousDeclaration())
|
|
|
|
data().Conversions.replace(Conversion->getPreviousDeclaration(),
|
|
|
|
Conversion);
|
|
|
|
else
|
|
|
|
data().Conversions.addDecl(Conversion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-06 04:52:13 +08:00
|
|
|
return;
|
2010-09-28 06:06:20 +08:00
|
|
|
}
|
2010-09-29 03:45:33 +08:00
|
|
|
|
|
|
|
// Handle non-static data members.
|
|
|
|
if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
|
|
|
|
// C++ [dcl.init.aggr]p1:
|
|
|
|
// An aggregate is an array or a class (clause 9) with [...] no
|
|
|
|
// private or protected non-static data members (clause 11).
|
|
|
|
//
|
|
|
|
// A POD must be an aggregate.
|
|
|
|
if (D->getAccess() == AS_private || D->getAccess() == AS_protected) {
|
|
|
|
data().Aggregate = false;
|
|
|
|
data().PlainOldData = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ [class]p9:
|
|
|
|
// A POD struct is a class that is both a trivial class and a
|
|
|
|
// standard-layout class, and has no non-static data members of type
|
|
|
|
// non-POD struct, non-POD union (or array of such types).
|
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
QualType T = Context.getBaseElementType(Field->getType());
|
|
|
|
if (!T->isPODType())
|
|
|
|
data().PlainOldData = false;
|
2010-09-29 04:50:54 +08:00
|
|
|
if (T->isReferenceType())
|
|
|
|
data().HasTrivialConstructor = false;
|
|
|
|
|
|
|
|
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
|
|
|
|
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
|
|
|
|
if (FieldRec->getDefinition()) {
|
|
|
|
if (!FieldRec->hasTrivialConstructor())
|
|
|
|
data().HasTrivialConstructor = false;
|
|
|
|
if (!FieldRec->hasTrivialCopyConstructor())
|
|
|
|
data().HasTrivialCopyConstructor = false;
|
|
|
|
if (!FieldRec->hasTrivialCopyAssignment())
|
|
|
|
data().HasTrivialCopyAssignment = false;
|
|
|
|
if (!FieldRec->hasTrivialDestructor())
|
|
|
|
data().HasTrivialDestructor = false;
|
|
|
|
}
|
|
|
|
}
|
2010-09-29 04:38:10 +08:00
|
|
|
|
|
|
|
// If this is not a zero-length bit-field, then the class is not empty.
|
|
|
|
if (data().Empty) {
|
|
|
|
if (!Field->getBitWidth())
|
|
|
|
data().Empty = false;
|
|
|
|
else if (!Field->getBitWidth()->isTypeDependent() &&
|
|
|
|
!Field->getBitWidth()->isValueDependent()) {
|
|
|
|
llvm::APSInt Bits;
|
|
|
|
if (Field->getBitWidth()->isIntegerConstantExpr(Bits, Context))
|
|
|
|
if (!!Bits)
|
|
|
|
data().Empty = false;
|
|
|
|
}
|
|
|
|
}
|
2010-09-29 03:45:33 +08:00
|
|
|
}
|
2010-09-29 12:25:11 +08:00
|
|
|
|
|
|
|
// Handle using declarations of conversion functions.
|
|
|
|
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
|
|
|
|
if (Shadow->getDeclName().getNameKind()
|
|
|
|
== DeclarationName::CXXConversionFunctionName)
|
|
|
|
data().Conversions.addDecl(Shadow, Shadow->getAccess());
|
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;
|
2010-03-31 09:36:47 +08:00
|
|
|
if (isa<UsingShadowDecl>(Conv))
|
|
|
|
Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl();
|
2010-03-15 17:07:48 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-03-31 09:36:47 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
void CXXRecordDecl::CheckConversionFunction(NamedDecl *ConvDecl) {
|
2010-03-15 17:07:48 +08:00
|
|
|
assert(ConvDecl->getDeclContext() == this &&
|
|
|
|
"conversion function does not belong to this record");
|
|
|
|
|
2010-03-31 09:36:47 +08:00
|
|
|
ConvDecl = ConvDecl->getUnderlyingDecl();
|
|
|
|
if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(ConvDecl)) {
|
|
|
|
assert(isa<CXXConversionDecl>(Temp->getTemplatedDecl()));
|
|
|
|
} else {
|
|
|
|
assert(isa<CXXConversionDecl>(ConvDecl));
|
|
|
|
}
|
2008-11-08 04:08:42 +08:00
|
|
|
}
|
2010-03-31 09:36:47 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
|
|
|
|
// This operation is O(N) but extremely rare. Sema only uses it to
|
|
|
|
// remove UsingShadowDecls in a class that were followed by a direct
|
|
|
|
// declaration, e.g.:
|
|
|
|
// class A : B {
|
|
|
|
// using B::operator int;
|
|
|
|
// operator int();
|
|
|
|
// };
|
|
|
|
// This is uncommon by itself and even more uncommon in conjunction
|
|
|
|
// with sufficiently large numbers of directly-declared conversions
|
|
|
|
// that asymptotic behavior matters.
|
|
|
|
|
|
|
|
UnresolvedSetImpl &Convs = *getConversionFunctions();
|
|
|
|
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
|
|
|
|
if (Convs[I].getDecl() == ConvDecl) {
|
|
|
|
Convs.erase(I);
|
|
|
|
assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end()
|
|
|
|
&& "conversion was found multiple times in unresolved set");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2008-11-08 04:08:42 +08:00
|
|
|
|
2010-03-31 09:36:47 +08:00
|
|
|
llvm_unreachable("conversion not found in set!");
|
2009-08-22 07:19:43 +08:00
|
|
|
}
|
2009-06-20 03:55:27 +08:00
|
|
|
|
2009-10-08 23:14:33 +08:00
|
|
|
CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
|
2009-10-13 04:18:28 +08:00
|
|
|
if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo())
|
2009-10-08 23:14:33 +08:00
|
|
|
return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2010-07-01 22:13:13 +08:00
|
|
|
CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
|
|
|
|
ASTContext &Context = getASTContext();
|
2009-05-30 05:03:38 +08:00
|
|
|
QualType ClassType = Context.getTypeDeclType(this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
DeclarationName Name
|
2009-08-05 13:36:45 +08:00
|
|
|
= Context.DeclarationNames.getCXXDestructorName(
|
|
|
|
Context.getCanonicalType(ClassType));
|
2009-05-30 05:03:38 +08:00
|
|
|
|
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);
|
2010-09-03 07:19:42 +08:00
|
|
|
if (I == E)
|
|
|
|
return 0;
|
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;
|
|
|
|
}
|
|
|
|
|
2010-09-29 08:15:42 +08:00
|
|
|
void CXXRecordDecl::completeDefinition() {
|
|
|
|
completeDefinition(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
|
|
|
|
RecordDecl::completeDefinition();
|
|
|
|
|
|
|
|
// If the class may be abstract (but hasn't been marked as such), check for
|
|
|
|
// any pure final overriders.
|
|
|
|
if (mayBeAbstract()) {
|
|
|
|
CXXFinalOverriderMap MyFinalOverriders;
|
|
|
|
if (!FinalOverriders) {
|
|
|
|
getFinalOverriders(MyFinalOverriders);
|
|
|
|
FinalOverriders = &MyFinalOverriders;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Done = false;
|
|
|
|
for (CXXFinalOverriderMap::iterator M = FinalOverriders->begin(),
|
|
|
|
MEnd = FinalOverriders->end();
|
|
|
|
M != MEnd && !Done; ++M) {
|
|
|
|
for (OverridingMethods::iterator SO = M->second.begin(),
|
|
|
|
SOEnd = M->second.end();
|
|
|
|
SO != SOEnd && !Done; ++SO) {
|
|
|
|
assert(SO->second.size() > 0 &&
|
|
|
|
"All virtual functions have overridding virtual functions");
|
|
|
|
|
|
|
|
// C++ [class.abstract]p4:
|
|
|
|
// A class is abstract if it contains or inherits at least one
|
|
|
|
// pure virtual function for which the final overrider is pure
|
|
|
|
// virtual.
|
|
|
|
if (SO->second.front().Method->isPure()) {
|
|
|
|
data().Abstract = true;
|
|
|
|
Done = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-29 12:25:11 +08:00
|
|
|
|
|
|
|
// Set access bits correctly on the directly-declared conversions.
|
|
|
|
for (UnresolvedSetIterator I = data().Conversions.begin(),
|
|
|
|
E = data().Conversions.end();
|
|
|
|
I != E; ++I)
|
|
|
|
data().Conversions.setAccess(I, (*I)->getAccess());
|
2010-09-29 08:15:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CXXRecordDecl::mayBeAbstract() const {
|
|
|
|
if (data().Abstract || isInvalidDecl() || !data().Polymorphic ||
|
|
|
|
isDependentContext())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (CXXRecordDecl::base_class_const_iterator B = bases_begin(),
|
|
|
|
BEnd = bases_end();
|
|
|
|
B != BEnd; ++B) {
|
|
|
|
CXXRecordDecl *BaseDecl
|
|
|
|
= cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl());
|
|
|
|
if (BaseDecl->isAbstract())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2010-04-20 06:54:31 +08:00
|
|
|
bool isStatic, StorageClass SCAsWritten, bool isInline) {
|
2010-08-12 06:01:17 +08:00
|
|
|
return new (C) CXXMethodDecl(CXXMethod, RD, NameInfo, T, TInfo,
|
2010-04-20 06:54:31 +08:00
|
|
|
isStatic, SCAsWritten, 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;
|
|
|
|
}
|
|
|
|
|
Complete reimplementation of the synthesis for implicitly-defined copy
assignment operators.
Previously, Sema provided type-checking and template instantiation for
copy assignment operators, then CodeGen would synthesize the actual
body of the copy constructor. Unfortunately, the two were not in sync,
and CodeGen might pick a copy-assignment operator that is different
from what Sema chose, leading to strange failures, e.g., link-time
failures when CodeGen called a copy-assignment operator that was not
instantiation, run-time failures when copy-assignment operators were
overloaded for const/non-const references and the wrong one was
picked, and run-time failures when by-value copy-assignment operators
did not have their arguments properly copy-initialized.
This implementation synthesizes the implicitly-defined copy assignment
operator bodies in Sema, so that the resulting ASTs encode exactly
what CodeGen needs to do; there is no longer any special code in
CodeGen to synthesize copy-assignment operators. The synthesis of the
body is relatively simple, and we generate one of three different
kinds of copy statements for each base or member:
- For a class subobject, call the appropriate copy-assignment
operator, after overload resolution has determined what that is.
- For an array of scalar types or an array of class types that have
trivial copy assignment operators, construct a call to
__builtin_memcpy.
- For an array of class types with non-trivial copy assignment
operators, synthesize a (possibly nested!) for loop whose inner
statement calls the copy constructor.
- For a scalar type, use built-in assignment.
This patch fixes at least a few tests cases in Boost.Spirit that were
failing because CodeGen picked the wrong copy-assignment operator
(leading to link-time failures), and I suspect a number of undiagnosed
problems will also go away with this change.
Some of the diagnostics we had previously have gotten worse with this
change, since we're going through generic code for our
type-checking. I will improve this in a subsequent patch.
llvm-svn: 102853
2010-05-02 04:49:11 +08:00
|
|
|
bool CXXMethodDecl::isCopyAssignmentOperator() const {
|
|
|
|
// C++0x [class.copy]p19:
|
|
|
|
// A user-declared copy assignment operator X::operator= is a non-static
|
|
|
|
// non-template member function of class X with exactly one parameter of
|
|
|
|
// type X, X&, const X&, volatile X& or const volatile X&.
|
|
|
|
if (/*operator=*/getOverloadedOperator() != OO_Equal ||
|
|
|
|
/*non-static*/ isStatic() ||
|
|
|
|
/*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
|
|
|
|
/*exactly one parameter*/getNumParams() != 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QualType ParamType = getParamDecl(0)->getType();
|
|
|
|
if (const LValueReferenceType *Ref = ParamType->getAs<LValueReferenceType>())
|
|
|
|
ParamType = Ref->getPointeeType();
|
|
|
|
|
|
|
|
ASTContext &Context = getASTContext();
|
|
|
|
QualType ClassType
|
|
|
|
= Context.getCanonicalType(Context.getTypeDeclType(getParent()));
|
|
|
|
return Context.hasSameUnqualifiedType(ClassType, ParamType);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-07-05 05:44:35 +08:00
|
|
|
unsigned CXXMethodDecl::size_overridden_methods() const {
|
|
|
|
return getASTContext().overridden_methods_size(this);
|
|
|
|
}
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
QualType CXXMethodDecl::getThisType(ASTContext &C) const {
|
2008-10-25 06:28:18 +08:00
|
|
|
// C++ 9.3.2p1: The type of this in a member function of a class X is X*.
|
|
|
|
// If the member function is declared const, the type of this is const X*,
|
|
|
|
// if the member function is declared volatile, the type of this is
|
|
|
|
// volatile X*, and if the member function is declared const volatile,
|
|
|
|
// the type of this is const volatile X*.
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
assert(isInstance() && "No 'this' for static methods!");
|
2009-06-13 10:59:33 +08:00
|
|
|
|
2010-03-10 11:28:59 +08:00
|
|
|
QualType ClassTy = C.getTypeDeclType(getParent());
|
2009-09-25 03:53:00 +08:00
|
|
|
ClassTy = C.getQualifiedType(ClassTy,
|
|
|
|
Qualifiers::fromCVRMask(getTypeQualifiers()));
|
2009-07-11 05:35:09 +08:00
|
|
|
return C.getPointerType(ClassTy);
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
}
|
|
|
|
|
2009-12-07 04:50:05 +08:00
|
|
|
bool CXXMethodDecl::hasInlineBody() const {
|
2010-01-06 03:06:31 +08:00
|
|
|
// If this function is a template instantiation, look at the template from
|
|
|
|
// which it was instantiated.
|
|
|
|
const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
|
|
|
|
if (!CheckFn)
|
|
|
|
CheckFn = this;
|
|
|
|
|
2009-12-07 04:50:05 +08:00
|
|
|
const FunctionDecl *fn;
|
2010-07-07 19:31:19 +08:00
|
|
|
return CheckFn->hasBody(fn) && !fn->isOutOfLine();
|
2009-12-07 04:50:05 +08:00
|
|
|
}
|
|
|
|
|
2008-11-05 12:29:56 +08:00
|
|
|
CXXBaseOrMemberInitializer::
|
2009-12-03 06:36:29 +08:00
|
|
|
CXXBaseOrMemberInitializer(ASTContext &Context,
|
2010-04-12 08:51:03 +08:00
|
|
|
TypeSourceInfo *TInfo, bool IsVirtual,
|
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)
|
2010-05-27 02:09:23 +08:00
|
|
|
: BaseOrMember(TInfo), Init(Init), AnonUnionMember(0),
|
|
|
|
LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false),
|
|
|
|
SourceOrderOrNumArrayIndices(0)
|
2009-12-03 06:36:29 +08:00
|
|
|
{
|
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)
|
2010-05-27 02:09:23 +08:00
|
|
|
: BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
|
|
|
|
AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false),
|
|
|
|
IsWritten(false), SourceOrderOrNumArrayIndices(0)
|
2009-12-03 06:36:29 +08:00
|
|
|
{
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
Reimplement code generation for copying fields in the
implicitly-generated copy constructor. Previously, Sema would perform
some checking and instantiation to determine which copy constructors,
etc., would be called, then CodeGen would attempt to figure out which
copy constructor to call... but would get it wrong, or poke at an
uninstantiated default argument, or fail in other ways.
The new scheme is similar to what we now do for the implicit
copy-assignment operator, where Sema performs all of the semantic
analysis and builds specific ASTs that look similar to the ASTs we'd
get from explicitly writing the copy constructor, so that CodeGen need
only do a direct translation.
However, it's not quite that simple because one cannot explicit write
elementwise copy-construction of an array. So, I've extended
CXXBaseOrMemberInitializer to contain a list of indexing variables
used to copy-construct the elements. For example, if we have:
struct A { A(const A&); };
struct B {
A array[2][3];
};
then we generate an implicit copy assignment operator for B that looks
something like this:
B::B(const B &other) : array[i0][i1](other.array[i0][i1]) { }
CodeGen will loop over the invented variables i0 and i1 to visit all
elements in the array, so that each element in the destination array
will be copy-constructed from the corresponding element in the source
array. Of course, if we're dealing with arrays of scalars or class
types with trivial copy-assignment operators, we just generate a
memcpy rather than a loop.
Fixes PR6928, PR5989, and PR6887. Boost.Regex now compiles and passes
all of its regression tests.
Conspicuously missing from this patch is handling for the exceptional
case, where we need to destruct those objects that we have
constructed. I'll address that case separately.
llvm-svn: 103079
2010-05-05 13:51:00 +08:00
|
|
|
CXXBaseOrMemberInitializer::
|
|
|
|
CXXBaseOrMemberInitializer(ASTContext &Context,
|
|
|
|
FieldDecl *Member, SourceLocation MemberLoc,
|
|
|
|
SourceLocation L, Expr *Init, SourceLocation R,
|
|
|
|
VarDecl **Indices,
|
|
|
|
unsigned NumIndices)
|
|
|
|
: BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
|
2010-05-27 02:09:23 +08:00
|
|
|
AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false),
|
|
|
|
IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices)
|
Reimplement code generation for copying fields in the
implicitly-generated copy constructor. Previously, Sema would perform
some checking and instantiation to determine which copy constructors,
etc., would be called, then CodeGen would attempt to figure out which
copy constructor to call... but would get it wrong, or poke at an
uninstantiated default argument, or fail in other ways.
The new scheme is similar to what we now do for the implicit
copy-assignment operator, where Sema performs all of the semantic
analysis and builds specific ASTs that look similar to the ASTs we'd
get from explicitly writing the copy constructor, so that CodeGen need
only do a direct translation.
However, it's not quite that simple because one cannot explicit write
elementwise copy-construction of an array. So, I've extended
CXXBaseOrMemberInitializer to contain a list of indexing variables
used to copy-construct the elements. For example, if we have:
struct A { A(const A&); };
struct B {
A array[2][3];
};
then we generate an implicit copy assignment operator for B that looks
something like this:
B::B(const B &other) : array[i0][i1](other.array[i0][i1]) { }
CodeGen will loop over the invented variables i0 and i1 to visit all
elements in the array, so that each element in the destination array
will be copy-constructed from the corresponding element in the source
array. Of course, if we're dealing with arrays of scalars or class
types with trivial copy-assignment operators, we just generate a
memcpy rather than a loop.
Fixes PR6928, PR5989, and PR6887. Boost.Regex now compiles and passes
all of its regression tests.
Conspicuously missing from this patch is handling for the exceptional
case, where we need to destruct those objects that we have
constructed. I'll address that case separately.
llvm-svn: 103079
2010-05-05 13:51:00 +08:00
|
|
|
{
|
|
|
|
VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1);
|
|
|
|
memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *));
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXBaseOrMemberInitializer *
|
|
|
|
CXXBaseOrMemberInitializer::Create(ASTContext &Context,
|
|
|
|
FieldDecl *Member,
|
|
|
|
SourceLocation MemberLoc,
|
|
|
|
SourceLocation L,
|
|
|
|
Expr *Init,
|
|
|
|
SourceLocation R,
|
|
|
|
VarDecl **Indices,
|
|
|
|
unsigned NumIndices) {
|
|
|
|
void *Mem = Context.Allocate(sizeof(CXXBaseOrMemberInitializer) +
|
|
|
|
sizeof(VarDecl *) * NumIndices,
|
|
|
|
llvm::alignof<CXXBaseOrMemberInitializer>());
|
|
|
|
return new (Mem) CXXBaseOrMemberInitializer(Context, Member, MemberLoc,
|
|
|
|
L, Init, R, Indices, NumIndices);
|
|
|
|
}
|
|
|
|
|
2009-12-03 06:36:29 +08:00
|
|
|
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();
|
|
|
|
|
2010-05-20 18:00:11 +08:00
|
|
|
return getBaseClassLoc().getLocalSourceRange().getBegin();
|
2009-12-03 06:36:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SourceRange CXXBaseOrMemberInitializer::getSourceRange() const {
|
|
|
|
return SourceRange(getSourceLocation(), getRParenLoc());
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
2010-05-08 05:43:38 +08:00
|
|
|
CXXConstructorDecl *
|
|
|
|
CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) {
|
2010-08-12 06:01:17 +08:00
|
|
|
return new (C) CXXConstructorDecl(0, DeclarationNameInfo(),
|
2010-05-08 05:43:38 +08:00
|
|
|
QualType(), 0, false, false, false);
|
|
|
|
}
|
|
|
|
|
2008-10-31 17:07:45 +08:00
|
|
|
CXXConstructorDecl *
|
|
|
|
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2009-08-19 09:27:57 +08:00
|
|
|
bool isExplicit,
|
2010-04-20 06:54:31 +08:00
|
|
|
bool isInline,
|
|
|
|
bool isImplicitlyDeclared) {
|
2010-08-12 06:01:17 +08:00
|
|
|
assert(NameInfo.getName().getNameKind()
|
|
|
|
== DeclarationName::CXXConstructorName &&
|
2008-11-17 22:58:09 +08:00
|
|
|
"Name must refer to a constructor");
|
2010-08-12 06:01:17 +08:00
|
|
|
return new (C) CXXConstructorDecl(RD, NameInfo, T, TInfo, isExplicit,
|
2010-04-20 06:54:31 +08:00
|
|
|
isInline, isImplicitlyDeclared);
|
2008-10-31 17:07:45 +08:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-05-08 05:43:38 +08:00
|
|
|
CXXDestructorDecl *
|
|
|
|
CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) {
|
2010-08-12 06:01:17 +08:00
|
|
|
return new (C) CXXDestructorDecl(0, DeclarationNameInfo(),
|
2010-05-08 05:43:38 +08:00
|
|
|
QualType(), false, false);
|
|
|
|
}
|
|
|
|
|
2008-11-06 04:51:48 +08:00
|
|
|
CXXDestructorDecl *
|
|
|
|
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType T, bool isInline,
|
2008-11-06 04:51:48 +08:00
|
|
|
bool isImplicitlyDeclared) {
|
2010-08-12 06:01:17 +08:00
|
|
|
assert(NameInfo.getName().getNameKind()
|
|
|
|
== DeclarationName::CXXDestructorName &&
|
2008-11-17 22:58:09 +08:00
|
|
|
"Name must refer to a destructor");
|
2010-08-12 06:01:17 +08:00
|
|
|
return new (C) CXXDestructorDecl(RD, NameInfo, T, isInline,
|
|
|
|
isImplicitlyDeclared);
|
2008-11-06 04:51:48 +08:00
|
|
|
}
|
|
|
|
|
2010-05-08 05:43:38 +08:00
|
|
|
CXXConversionDecl *
|
|
|
|
CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) {
|
2010-08-12 06:01:17 +08:00
|
|
|
return new (C) CXXConversionDecl(0, DeclarationNameInfo(),
|
2010-05-08 05:43:38 +08:00
|
|
|
QualType(), 0, false, false);
|
|
|
|
}
|
|
|
|
|
2008-11-08 04:08:42 +08:00
|
|
|
CXXConversionDecl *
|
|
|
|
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2009-08-19 09:27:57 +08:00
|
|
|
bool isInline, bool isExplicit) {
|
2010-08-12 06:01:17 +08:00
|
|
|
assert(NameInfo.getName().getNameKind()
|
|
|
|
== DeclarationName::CXXConversionFunctionName &&
|
2008-11-17 22:58:09 +08:00
|
|
|
"Name must refer to a conversion function");
|
2010-08-12 06:01:17 +08:00
|
|
|
return new (C) CXXConversionDecl(RD, NameInfo, 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,
|
2010-09-01 11:07:18 +08:00
|
|
|
SourceLocation UsingLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
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();
|
2010-09-01 11:07:18 +08:00
|
|
|
return new (C) NamespaceAliasDecl(DC, UsingLoc, 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,
|
2010-08-12 19:46:03 +08:00
|
|
|
SourceRange NNR, SourceLocation UL,
|
|
|
|
NestedNameSpecifier* TargetNNS,
|
|
|
|
const DeclarationNameInfo &NameInfo,
|
|
|
|
bool IsTypeNameArg) {
|
|
|
|
return new (C) UsingDecl(DC, NNR, UL, TargetNNS, NameInfo, 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,
|
2010-08-12 19:46:03 +08:00
|
|
|
const DeclarationNameInfo &NameInfo) {
|
2009-11-18 10:36:19 +08:00
|
|
|
return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
|
2010-08-12 19:46:03 +08:00
|
|
|
TargetNNR, TargetNNS, NameInfo);
|
2009-11-18 10:36:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|