static bool classof(const CXXFieldDecl *D) { return true; }
};
+/// BaseSpecifier - A base class of a C++ class.
+class CXXBaseSpecifier {
+ SourceRange Range;
+
+ bool Virtual : 1;
+
+ /// BaseOfClass - Whether this is the base of a class (true) or of a
+ /// struct (false). This determines the mapping from the access
+ /// specifier as written in the source code to the access specifier
+ /// used for semantic analysis.
+ bool BaseOfClass : 1;
+
+ /// Access specifier as written in the source code (which may be
+ /// AS_none). The actual type of data stored here is an
+ /// AccessSpecifier, but we use "unsigned" here to work around a
+ /// VC++ bug.
+ unsigned Access : 2;
+
+ QualType BaseType;
+
+ CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, QualType T)
+ : Range(R), Virtual(V), BaseOfClass(BC), Access(A), BaseType(T) { }
+
+public:
+ static CXXBaseSpecifier *Create(ASTContext &C, SourceRange R, bool V, bool BC,
+ AccessSpecifier A, QualType T);
+
+ /// getSourceRange - Retrieves the source range that contains the
+ /// entire base specifier.
+ SourceRange getSourceRange() const { return Range; }
+
+ /// isVirtual - Determines whether the base class is a virtual base
+ /// class (or not).
+ bool isVirtual() const { return Virtual; }
+
+ /// getAccessSpecifier - Returns the access specifier for this base
+ /// specifier. This is the actual base specifier as used for
+ /// semantic analysis, so the result can never be AS_none. To
+ /// retrieve the access specifier as written in the source code, use
+ /// getAccessSpecifierAsWritten().
+ AccessSpecifier getAccessSpecifier() const {
+ if ((AccessSpecifier)Access == AS_none)
+ return BaseOfClass? AS_private : AS_public;
+ else
+ return (AccessSpecifier)Access;
+ }
+
+ /// getAccessSpecifierAsWritten - Retrieves the access specifier as
+ /// written in the source code (which may mean that no access
+ /// specifier was explicitly written). Use getAccessSpecifier() to
+ /// retrieve the access specifier for use in semantic analysis.
+ AccessSpecifier getAccessSpecifierAsWritten() const {
+ return (AccessSpecifier)Access;
+ }
+
+ /// getType - Retrieves the type of the base class. This type will
+ /// always be an unqualified class type.
+ QualType getType() const { return BaseType; }
+};
+
/// CXXRecordDecl - Represents a C++ struct/union/class.
-/// The only difference with RecordDecl is that CXXRecordDecl is a DeclContext.
+/// CXXRecordDecl differs from RecordDecl in several ways. First, it
+/// is a DeclContext, because it can contain other
+/// declarations. Second, it provides additional C++ fields, including
+/// storage for base classes.
class CXXRecordDecl : public RecordDecl, public DeclContext {
+ /// Bases - Base classes of this class.
+ /// FIXME: This is wasted space for a union.
+ CXXBaseSpecifier **Bases;
+
+ /// NumBases - The number of base class specifiers in Bases.
+ unsigned NumBases;
+
CXXRecordDecl(TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id)
- : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord) {}
+ : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord),
+ Bases(0), NumBases(0) {}
+
+ ~CXXRecordDecl();
+
public:
static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
CXXRecordDecl* PrevDecl=0);
+ /// setBases - Sets the base classes of this struct or class.
+ void setBases(CXXBaseSpecifier **Bases, unsigned NumBases) {
+ this->Bases = Bases;
+ this->NumBases = NumBases;
+ }
+
+ /// getNumBases - Retrieves the number of base classes of this
+ /// class.
+ unsigned getNumBases() const { return NumBases; }
+
+ /// getBase - Retrieve the ith base class.
+ CXXBaseSpecifier *getBase(unsigned i) {
+ assert(i < NumBases && "Base index out of range");
+ return Bases[i];
+ }
+
+ /// getBase - Retrieve the ith base class.
+ const CXXBaseSpecifier *getBase(unsigned i) const {
+ assert(i < NumBases && "Base index out of range");
+ return Bases[i];
+ }
+
const CXXFieldDecl *getMember(unsigned i) const {
return cast<const CXXFieldDecl>(RecordDecl::getMember(i));
}
"more than one matching function found in __builtin_overload")
// Classes.
-DIAG(err_dup_virtual, ERROR,
- "duplicate 'virtual' in base specifier")
DIAG(err_expected_class_name, ERROR,
"expected class name")
DIAG(err_anon_type_definition, ERROR,
"declaration of anonymous %0 must be a definition")
+
+// Derived classes.
+DIAG(err_dup_virtual, ERROR,
+ "duplicate 'virtual' in base specifier")
DIAG(err_base_clause_on_union, ERROR,
"unions cannot have base classes")
DIAG(err_base_must_be_class, ERROR,
"unions cannot be base classes")
DIAG(err_incomplete_base_class, ERROR,
"base class has incomplete type")
+DIAG(err_duplicate_base_class, ERROR,
+ "base class '%0' specified more than once as a direct base class")
DIAG(warn_not_compound_assign, WARNING,
"use of unary operator that may be intended as compound assignment (%0=)")
typedef void DeclTy;
typedef void TypeTy;
typedef void AttrTy;
-
+ typedef void BaseTy;
+
/// ActionResult - This structure is used while parsing/acting on expressions,
/// stmts, etc. It encapsulates both the object returned by the action, plus
/// a sense of whether or not it is valid.
}
};
- /// Expr/Stmt/TypeResult - Provide a unique type to wrap ExprTy/StmtTy/TypeTy,
- /// providing strong typing and allowing for failure.
+ /// Expr/Stmt/Type/BaseResult - Provide a unique type to wrap
+ /// ExprTy/StmtTy/TypeTy/BaseTy, providing strong typing and
+ /// allowing for failure.
typedef ActionResult<0> ExprResult;
typedef ActionResult<1> StmtResult;
typedef ActionResult<2> TypeResult;
-
+ typedef ActionResult<3> BaseResult;
+
/// Deletion callbacks - Since the parser doesn't know the concrete types of
/// the AST nodes being generated, it must do callbacks to delete objects when
/// recovering from errors.
//===---------------------------- 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) {
+ return 0;
}
+ virtual void ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases,
+ unsigned NumBases) {
+ }
+
/// ActOnStartCXXClassDef - This is called at the start of a class/struct/union
/// definition, when on C++.
virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
typedef Action::StmtTy StmtTy;
typedef Action::DeclTy DeclTy;
typedef Action::TypeTy TypeTy;
+ typedef Action::BaseTy BaseTy;
// Parsing methods.
typedef Action::ExprResult ExprResult;
typedef Action::StmtResult StmtResult;
+ typedef Action::BaseResult BaseResult;
//===--------------------------------------------------------------------===//
// Lexing and parsing of C++ inline methods.
//===--------------------------------------------------------------------===//
// C++ 10: Derived classes [class.derived]
void ParseBaseClause(DeclTy *ClassDecl);
- bool ParseBaseSpecifier(DeclTy *ClassDecl);
+ BaseResult ParseBaseSpecifier(DeclTy *ClassDecl);
AccessSpecifier getAccessSpecifierIfPresent() const;
};
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) {
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,
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
// 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
/// 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();
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;
// 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
// 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);
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
#include <algorithm> // for std::equal
+#include <functional>
+#include <map>
using namespace clang;
/// 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:
if (Decl->isUnion()) {
Diag(Decl->getLocation(), diag::err_base_clause_on_union,
SpecifierRange);
- Decl->setInvalidDecl();
- return;
+ return true;
}
// C++ [class.derived]p2:
// 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);
}
//===----------------------------------------------------------------------===//
// 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;
// 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
union U2 {};\r
\r
class G : public U2 { }; // expected-error{{unions cannot be base classes}}\r
+\r
+typedef G G_copy;\r
+typedef G G_copy_2;\r
+typedef G_copy G_copy_3;\r
+\r
+class H : G_copy, A, G_copy_2, // expected-error{{base class 'G_copy' specified more than once as a direct base class}}\r
+ public G_copy_3 { }; // expected-error{{base class 'G_copy' specified more than once as a direct base class}}\r