aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
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