aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2008-10-22 17:49:05 +0000
committerDouglas Gregor <dgregor@apple.com>2008-10-22 17:49:05 +0000
commitf8268ae3196002bbab6adb830302e79b0f368f13 (patch)
tree755160cb56f57dd7d7dafccc13858533037e619b /lib
parented2cb285522513d33b001900acf211cc5ee2175b (diff)
Add representation of base classes in the AST, and verify that we
don't have duplicated direct base classes. Seriliazation of base class specifiers is not yet implemented. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57991 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/DeclCXX.cpp14
-rw-r--r--lib/Parse/ParseDeclCXX.cpp24
-rw-r--r--lib/Sema/Sema.h10
-rw-r--r--lib/Sema/SemaDeclCXX.cpp75
-rw-r--r--lib/Sema/SemaOverload.cpp4
5 files changed, 103 insertions, 24 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 9fd7ff974e..86db8532c8 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -26,6 +26,14 @@ CXXFieldDecl *CXXFieldDecl::Create(ASTContext &C, CXXRecordDecl *RD,
return new (Mem) CXXFieldDecl(RD, L, Id, T, BW);
}
+CXXBaseSpecifier *CXXBaseSpecifier::Create(ASTContext &C, SourceRange R, bool V,
+ bool BC, AccessSpecifier A, QualType T)
+{
+ void *Mem = C.getAllocator().Allocate<CXXBaseSpecifier>();
+ CXXBaseSpecifier* BS = new (Mem) CXXBaseSpecifier(R, V, BC, A, T);
+ return BS;
+}
+
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
CXXRecordDecl* PrevDecl) {
@@ -35,6 +43,12 @@ CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
return R;
}
+CXXRecordDecl::~CXXRecordDecl() {
+ for (unsigned i = 0; i < NumBases; ++i)
+ delete Bases[i];
+ delete [] Bases;
+}
+
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, IdentifierInfo *Id,
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index abd432ce9f..21c7d6f0fe 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -256,12 +256,19 @@ void Parser::ParseBaseClause(DeclTy *ClassDecl)
assert(Tok.is(tok::colon) && "Not a base clause");
ConsumeToken();
+ // Build up an array of parsed base specifiers.
+ llvm::SmallVector<BaseTy *, 8> BaseInfo;
+
while (true) {
// Parse a base-specifier.
- if (ParseBaseSpecifier(ClassDecl)) {
+ BaseResult Result = ParseBaseSpecifier(ClassDecl);
+ if (Result.isInvalid) {
// Skip the rest of this base specifier, up until the comma or
// opening brace.
- SkipUntil(tok::comma, tok::l_brace);
+ SkipUntil(tok::comma, tok::l_brace, true, true);
+ } else {
+ // Add this to our array of base specifiers.
+ BaseInfo.push_back(Result.Val);
}
// If the next token is a comma, consume it and keep reading
@@ -271,6 +278,9 @@ void Parser::ParseBaseClause(DeclTy *ClassDecl)
// Consume the comma.
ConsumeToken();
}
+
+ // Attach the base specifiers
+ Actions.ActOnBaseSpecifiers(ClassDecl, &BaseInfo[0], BaseInfo.size());
}
/// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is
@@ -284,7 +294,7 @@ void Parser::ParseBaseClause(DeclTy *ClassDecl)
/// class-name
/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt]
/// class-name
-bool Parser::ParseBaseSpecifier(DeclTy *ClassDecl)
+Parser::BaseResult Parser::ParseBaseSpecifier(DeclTy *ClassDecl)
{
bool IsVirtual = false;
SourceLocation StartLoc = Tok.getLocation();
@@ -306,7 +316,8 @@ bool Parser::ParseBaseSpecifier(DeclTy *ClassDecl)
SourceLocation VirtualLoc = ConsumeToken();
if (IsVirtual) {
// Complain about duplicate 'virtual'
- Diag(VirtualLoc, diag::err_dup_virtual);
+ Diag(VirtualLoc, diag::err_dup_virtual,
+ SourceRange(VirtualLoc, VirtualLoc));
}
IsVirtual = true;
@@ -339,9 +350,8 @@ bool Parser::ParseBaseSpecifier(DeclTy *ClassDecl)
// Notify semantic analysis that we have parsed a complete
// base-specifier.
- Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, BaseType,
- BaseLoc);
- return false;
+ return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, BaseType,
+ BaseLoc);
}
/// getAccessSpecifierIfPresent - Determine whether the next token is
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b176bc9ceb..48b32e8ce1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -753,10 +753,14 @@ public:
// C++ Classes
//
/// ActOnBaseSpecifier - Parsed a base specifier
- virtual void ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
- bool Virtual, AccessSpecifier Access,
- TypeTy *basetype, SourceLocation BaseLoc);
+ virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl,
+ SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ TypeTy *basetype, SourceLocation BaseLoc);
+ virtual void ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
+ unsigned NumBases);
+
virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
SourceLocation LBrace);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index fef205cb11..7c4444fab6 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -20,6 +20,8 @@
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
#include <algorithm> // for std::equal
+#include <functional>
+#include <map>
using namespace clang;
@@ -260,23 +262,24 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
/// example:
/// class foo : public bar, virtual private baz {
/// 'public bar' and 'virtual private baz' are each base-specifiers.
-void Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
- bool Virtual, AccessSpecifier Access,
- TypeTy *basetype, SourceLocation BaseLoc) {
+Sema::BaseResult
+Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
+ bool Virtual, AccessSpecifier Access,
+ TypeTy *basetype, SourceLocation BaseLoc) {
RecordDecl *Decl = (RecordDecl*)classdecl;
QualType BaseType = Context.getTypeDeclType((TypeDecl*)basetype);
// Base specifiers must be record types.
if (!BaseType->isRecordType()) {
Diag(BaseLoc, diag::err_base_must_be_class, SpecifierRange);
- return;
+ return true;
}
// C++ [class.union]p1:
// A union shall not be used as a base class.
if (BaseType->isUnionType()) {
Diag(BaseLoc, diag::err_union_as_base_class, SpecifierRange);
- return;
+ return true;
}
// C++ [class.union]p1:
@@ -284,8 +287,7 @@ void Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
if (Decl->isUnion()) {
Diag(Decl->getLocation(), diag::err_base_clause_on_union,
SpecifierRange);
- Decl->setInvalidDecl();
- return;
+ return true;
}
// C++ [class.derived]p2:
@@ -293,14 +295,63 @@ void Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
// defined class.
if (BaseType->isIncompleteType()) {
Diag(BaseLoc, diag::err_incomplete_base_class, SpecifierRange);
- return;
+ return true;
+ }
+
+ // Create the base specifier.
+ CXXBaseSpecifier *BS = CXXBaseSpecifier::Create(Context, SpecifierRange,
+ Virtual,
+ BaseType->isClassType(),
+ Access, BaseType);
+ return BS;
+}
+
+/// QualTypeOrder - Function object that provides a total ordering on
+/// QualType values.
+struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
+ bool operator()(QualType T1, QualType T2) {
+ return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
}
+};
+
+/// ActOnBaseSpecifiers - Attach the given base specifiers to the
+/// class, after checking whether there are any duplicate base
+/// classes.
+void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
+ unsigned NumBases) {
+ if (NumBases == 0)
+ return;
- // FIXME: C++ [class.mi]p3:
- // A class shall not be specified as a direct base class of a
- // derived class more than once.
+ // Used to keep track of which base types we have already seen, so
+ // that we can properly diagnose redundant direct base types. Note
+ // that the key is always the canonical type.
+ std::map<QualType, CXXBaseSpecifier*, QualTypeOrdering> KnownBaseTypes;
+
+ // Copy non-redundant base specifiers into permanent storage.
+ CXXBaseSpecifier **InBaseSpecs = (CXXBaseSpecifier **)Bases;
+ CXXBaseSpecifier **StoredBaseSpecs = new CXXBaseSpecifier* [NumBases];
+ unsigned outIdx = 0;
+ for (unsigned inIdx = 0; inIdx < NumBases; ++inIdx) {
+ QualType NewBaseType
+ = Context.getCanonicalType(InBaseSpecs[inIdx]->getType());
+ if (KnownBaseTypes[NewBaseType]) {
+ // C++ [class.mi]p3:
+ // A class shall not be specified as a direct base class of a
+ // derived class more than once.
+ Diag(InBaseSpecs[inIdx]->getSourceRange().getBegin(),
+ diag::err_duplicate_base_class,
+ KnownBaseTypes[NewBaseType]->getType().getAsString(),
+ InBaseSpecs[inIdx]->getSourceRange());
+ } else {
+ // Okay, add this new base class.
+ KnownBaseTypes[NewBaseType] = InBaseSpecs[inIdx];
+ StoredBaseSpecs[outIdx++] = InBaseSpecs[inIdx];
+ }
+ }
- // FIXME: Attach base class to the record.
+ // Attach the remaining base class specifiers to the derived class.
+ CXXRecordDecl *Decl = (CXXRecordDecl*)ClassDecl;
+ Decl->setBases(StoredBaseSpecs, outIdx);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index cafdf8794a..19bc13a146 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -664,7 +664,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
// Within each iteration of the loop, we check the qualifiers to
// determine if this still looks like a qualification
// conversion. Then, if all is well, we unwrap one more level of
- // pointers (FIXME: or pointers-to-members) and do it all again
+ // pointers or pointers-to-members and do it all again
// until there are no more pointers or pointers-to-members left to
// unwrap.
UnwrappedAnyPointer = true;
@@ -839,7 +839,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// Within each iteration of the loop, we check the qualifiers to
// determine if this still looks like a qualification
// conversion. Then, if all is well, we unwrap one more level of
- // pointers (FIXME: or pointers-to-members) and do it all again
+ // pointers or pointers-to-members and do it all again
// until there are no more pointers or pointers-to-members left
// to unwrap. This essentially mimics what
// IsQualificationConversion does, but here we're checking for a