[cfe-commits] r52956 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/DiagnosticKinds.def lib/AST/Expr.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/CXXFieldCollector.h lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp test/Sema/cxx-class.cpp test/Sema/cxx-this.cpp
Argiris Kirtzidis
akyrtzi at gmail.com
Tue Jul 1 03:37:31 PDT 2008
Author: akirtzidis
Date: Tue Jul 1 05:37:29 2008
New Revision: 52956
URL: http://llvm.org/viewvc/llvm-project?rev=52956&view=rev
Log:
Add Sema support for C++ classes.
Added:
cfe/trunk/lib/Sema/CXXFieldCollector.h
cfe/trunk/test/Sema/cxx-class.cpp
cfe/trunk/test/Sema/cxx-this.cpp
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Tue Jul 1 05:37:29 2008
@@ -223,6 +223,7 @@
Func,
Function,
PrettyFunction,
+ CXXThis,
ObjCSuper // super
};
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Jul 1 05:37:29 2008
@@ -589,6 +589,18 @@
DIAG(err_bad_language, ERROR,
"unknown linkage language")
+// C++ class members
+DIAG(err_storageclass_invalid_for_member, ERROR,
+ "storage class specified for a member declaration")
+DIAG(err_not_bitfield_type, ERROR,
+ "cannot declare '%0' to be a bit-field type")
+DIAG(err_static_not_bitfield, ERROR,
+ "static member '%0' cannot be a bit-field")
+DIAG(err_not_integral_type_bitfield, ERROR,
+ "bit-field '%0' with non-integral type")
+DIAG(err_member_initialization, ERROR,
+ "'%0' can only be initialized if it is a static const integral data member")
+
// Attributes
DIAG(err_attribute_wrong_number_arguments, ERROR,
"attribute requires %0 argument(s)")
@@ -898,6 +910,13 @@
DIAG(err_typecheck_assign_const, ERROR,
"read-only variable is not assignable")
+DIAG(err_invalid_this_use, ERROR,
+ "invalid use of 'this' outside of a nonstatic member function")
+DIAG(err_invalid_member_use_in_static_method, ERROR,
+ "invalid use of member '%0' in static member function")
+DIAG(err_invalid_non_static_member_use, ERROR,
+ "invalid use of nonstatic data member '%0'")
+
// assignment related diagnostics (also for argument passing, returning, etc).
DIAG(err_typecheck_convert_incompatible, ERROR,
"incompatible type %2 '%1', expected '%0'")
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Tue Jul 1 05:37:29 2008
@@ -420,7 +420,9 @@
case ObjCPropertyRefExprClass: // FIXME: check if read-only property.
return LV_Valid;
case PreDefinedExprClass:
- return LV_Valid;
+ return (cast<PreDefinedExpr>(this)->getIdentType() == PreDefinedExpr::CXXThis
+ ? LV_InvalidExpression
+ : LV_Valid);
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue();
default:
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Jul 1 05:37:29 2008
@@ -229,11 +229,9 @@
// If there is a body, parse it and inform the actions module.
if (Tok.is(tok::l_brace))
- // FIXME: Temporarily disable parsing for C++ classes until the Sema support
- // is in place.
- //if (getLang().CPlusPlus)
- // ParseCXXMemberSpecification(StartLoc, TagType, TagDecl);
- //else
+ if (getLang().CPlusPlus)
+ ParseCXXMemberSpecification(StartLoc, TagType, TagDecl);
+ else
ParseStructUnionBody(StartLoc, TagType, TagDecl);
else if (TK == Action::TK_Definition) {
// FIXME: Complain that we have a base-specifier list but no
@@ -411,7 +409,7 @@
return 0;
}
}
-
+
Declarator DeclaratorInfo(DS, Declarator::MemberContext);
if (Tok.isNot(tok::colon)) {
@@ -492,6 +490,10 @@
if (Tok.is(tok::kw___attribute))
DeclaratorInfo.AddAttributes(ParseAttributes());
+ // NOTE: If Sema is the Action module and declarator is an instance field,
+ // this call will *not* return the created decl; LastDeclInGroup will be
+ // returned instead.
+ // See Sema::ActOnCXXMemberDeclarator for details.
LastDeclInGroup = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
DeclaratorInfo,
BitfieldSize, Init,
Added: cfe/trunk/lib/Sema/CXXFieldCollector.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CXXFieldCollector.h?rev=52956&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/CXXFieldCollector.h (added)
+++ cfe/trunk/lib/Sema/CXXFieldCollector.h Tue Jul 1 05:37:29 2008
@@ -0,0 +1,76 @@
+//===- CXXFieldCollector.h - Utility class for C++ class semantic analysis ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides CXXFieldCollector that is used during parsing & semantic
+// analysis of C++ classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H
+#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H
+
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+ class CXXFieldDecl;
+
+/// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of
+/// C++ classes.
+class CXXFieldCollector {
+ /// Fields - Contains all CXXFieldDecls collected during parsing of a C++
+ /// class. When a nested class is entered, its fields are appended to the
+ /// fields of its parent class, when it is exited its fields are removed.
+ llvm::SmallVector<CXXFieldDecl*, 32> Fields;
+
+ /// FieldCount - Each entry represents the number of fields collected during
+ /// the parsing of a C++ class. When a nested class is entered, a new field
+ /// count is pushed, when it is exited, the field count is popped.
+ llvm::SmallVector<size_t, 4> FieldCount;
+
+ // Example:
+ //
+ // class C {
+ // int x,y;
+ // class NC {
+ // int q;
+ // // At this point, Fields contains [x,y,q] decls and FieldCount contains
+ // // [2,1].
+ // };
+ // int z;
+ // // At this point, Fields contains [x,y,z] decls and FieldCount contains
+ // // [3].
+ // };
+
+public:
+ /// StartClass - Called by Sema::ActOnStartCXXClassDef.
+ void StartClass() { FieldCount.push_back(0); }
+
+ /// Add - Called by Sema::ActOnCXXMemberDeclarator.
+ void Add(CXXFieldDecl *D) {
+ Fields.push_back(D);
+ ++FieldCount.back();
+ }
+
+ /// getNumField - The number of fields added to the currently parsed class.
+ size_t getCurNumFields() const { return FieldCount.back(); }
+
+ /// getFields - Pointer to array of fields added to the currently parsed
+ /// class.
+ CXXFieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); }
+
+ /// FinishClass - Called by Sema::ActOnFinishCXXClassDef.
+ void FinishClass() {
+ Fields.resize(Fields.size() - getCurNumFields());
+ FieldCount.pop_back();
+ }
+};
+
+} // end namespace clang
+
+#endif
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Jul 1 05:37:29 2008
@@ -116,6 +116,8 @@
KnownFunctionIDs[id_vprintf] = &IT.get("vprintf");
TUScope = 0;
+ if (getLangOptions().CPlusPlus)
+ FieldCollector.reset(new CXXFieldCollector());
}
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Jul 1 05:37:29 2008
@@ -16,11 +16,13 @@
#define LLVM_CLANG_AST_SEMA_H
#include "IdentifierResolver.h"
+#include "CXXFieldCollector.h"
#include "clang/Parse/Action.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/OwningPtr.h"
#include <vector>
#include <string>
@@ -109,6 +111,9 @@
ObjCCompatibleAliasDecl*> ObjCAliasTy;
ObjCAliasTy ObjCAliasDecls;
+ /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
+ llvm::OwningPtr<CXXFieldCollector> FieldCollector;
+
IdentifierResolver IdResolver;
// Enum values used by KnownFunctionIDs (see below).
@@ -215,9 +220,7 @@
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
- // Until 'real' implementation is in place, override both
- // 'ActOnStartOfFunctionDef' to satisfy the compiler.
- virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, DeclTy *D) { return D; }
+ virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, DeclTy *D);
virtual void ObjCActOnStartOfMethodDef(Scope *S, DeclTy *D);
virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body);
@@ -258,6 +261,8 @@
virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
DeclTy **Elements, unsigned NumElements);
private:
+ DeclContext *getDCParent(DeclContext *DC);
+
/// Set the current declaration context until it gets popped.
void PushDeclContext(DeclContext *DC);
void PopDeclContext();
@@ -545,6 +550,9 @@
SourceLocation LParenLoc, ExprTy *E,
SourceLocation RParenLoc);
+ //// ActOnCXXThis - Parse 'this' pointer.
+ virtual ExprResult ActOnCXXThis(SourceLocation ThisLoc);
+
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
virtual ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
tok::TokenKind Kind);
@@ -585,6 +593,20 @@
bool Virtual, AccessSpecifier Access,
DeclTy *basetype, SourceLocation BaseLoc);
+ virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
+ SourceLocation LBrace);
+
+ virtual DeclTy *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
+ Declarator &D, ExprTy *BitfieldWidth,
+ ExprTy *Init, DeclTy *LastInGroup);
+
+ virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
+ DeclTy *TagDecl,
+ SourceLocation LBrac,
+ SourceLocation RBrac);
+
+ virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl,SourceLocation RBrace);
+
// Objective-C declarations.
virtual DeclTy *ActOnStartClassInterface(
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jul 1 05:37:29 2008
@@ -44,19 +44,38 @@
return 0;
}
+DeclContext *Sema::getDCParent(DeclContext *DC) {
+ // If CurContext is a ObjC method, getParent() will return NULL.
+ if (isa<ObjCMethodDecl>(DC))
+ return Context.getTranslationUnitDecl();
+
+ // A C++ inline method is parsed *after* the topmost class it was declared in
+ // is fully parsed (it's "complete").
+ // The parsing of a C++ inline method happens at the declaration context of
+ // the topmost (non-nested) class it is declared in.
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
+ assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record.");
+ DC = MD->getParent();
+ while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getParent()))
+ DC = RD;
+
+ // Return the declaration context of the topmost class the inline method is
+ // declared in.
+ return DC;
+ }
+
+ return DC->getParent();
+}
+
void Sema::PushDeclContext(DeclContext *DC) {
- assert( ( (isa<ObjCMethodDecl>(DC) && isa<TranslationUnitDecl>(CurContext))
- || DC->getParent() == CurContext ) &&
- "The next DeclContext should be directly contained in the current one.");
+ assert(getDCParent(DC) == CurContext &&
+ "The next DeclContext should be directly contained in the current one.");
CurContext = DC;
}
void Sema::PopDeclContext() {
assert(CurContext && "DeclContext imbalance!");
- // If CurContext is a ObjC method, getParent() will return NULL.
- CurContext = isa<ObjCMethodDecl>(CurContext)
- ? Context.getTranslationUnitDecl()
- : CurContext->getParent();
+ CurContext = getDCParent(CurContext);
}
/// Add this decl to the scope shadowed decl chains.
@@ -646,10 +665,19 @@
}
bool isInline = D.getDeclSpec().isInlineSpecified();
- FunctionDecl *NewFD = FunctionDecl::Create(Context, CurContext,
- D.getIdentifierLoc(),
- II, R, SC, isInline,
- LastDeclarator);
+ FunctionDecl *NewFD;
+ if (D.getContext() == Declarator::MemberContext) {
+ // This is a C++ method declaration.
+ NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
+ D.getIdentifierLoc(), II, R,
+ (SC == FunctionDecl::Static), isInline,
+ LastDeclarator);
+ } else {
+ NewFD = FunctionDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(),
+ II, R, SC, isInline,
+ LastDeclarator);
+ }
// Handle attributes.
ProcessDeclAttributes(NewFD, D);
@@ -728,19 +756,27 @@
case DeclSpec::SCS_register: SC = VarDecl::Register; break;
case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
}
- if (S->getFnParent() == 0) {
- // C99 6.9p2: The storage-class specifiers auto and register shall not
- // appear in the declaration specifiers in an external declaration.
- if (SC == VarDecl::Auto || SC == VarDecl::Register) {
- Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope,
- R.getAsString());
- InvalidDecl = true;
- }
- NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
- II, R, SC, LastDeclarator);
+ if (D.getContext() == Declarator::MemberContext) {
+ assert(SC == VarDecl::Static && "Invalid storage class for member!");
+ // This is a static data member for a C++ class.
+ NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
+ D.getIdentifierLoc(), II,
+ R, LastDeclarator);
} else {
- NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
- II, R, SC, LastDeclarator);
+ if (S->getFnParent() == 0) {
+ // C99 6.9p2: The storage-class specifiers auto and register shall not
+ // appear in the declaration specifiers in an external declaration.
+ if (SC == VarDecl::Auto || SC == VarDecl::Register) {
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope,
+ R.getAsString());
+ InvalidDecl = true;
+ }
+ NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
+ II, R, SC, LastDeclarator);
+ } else {
+ NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
+ II, R, SC, LastDeclarator);
+ }
}
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(NewVD, D);
@@ -1506,7 +1542,13 @@
}
}
}
- Decl *decl = static_cast<Decl*>(ActOnDeclarator(GlobalScope, D, 0));
+
+ return ActOnStartOfFunctionDef(FnBodyScope,
+ ActOnDeclarator(GlobalScope, D, 0));
+}
+
+Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
+ Decl *decl = static_cast<Decl*>(D);
FunctionDecl *FD = cast<FunctionDecl>(decl);
PushDeclContext(FD);
@@ -1707,8 +1749,12 @@
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// struct X { int A; } D; D should chain to X.
- New = RecordDecl::Create(Context, Kind, CurContext, Loc, Name, 0);
- }
+ if (getLangOptions().CPlusPlus)
+ // FIXME: Look for a way to use RecordDecl for simple structs.
+ New = CXXRecordDecl::Create(Context, Kind, CurContext, Loc, Name, 0);
+ else
+ New = RecordDecl::Create(Context, Kind, CurContext, Loc, Name, 0);
+ }
// If this has an identifier, add it to the scope stack.
if (Name) {
@@ -1843,7 +1889,17 @@
}
}
// FIXME: Chain fielddecls together.
- FieldDecl *NewFD = FieldDecl::Create(Context, Loc, II, T, BitWidth);
+ FieldDecl *NewFD;
+
+ if (getLangOptions().CPlusPlus) {
+ // FIXME: Replace CXXFieldDecls with FieldDecls for simple structs.
+ NewFD = CXXFieldDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
+ Loc, II, T, BitWidth);
+ if (II)
+ PushOnScopeChains(NewFD, S);
+ }
+ else
+ NewFD = FieldDecl::Create(Context, Loc, II, T, BitWidth);
ProcessDeclAttributes(NewFD, D);
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jul 1 05:37:29 2008
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "clang/Basic/LangOptions.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
@@ -307,6 +308,175 @@
// FIXME: Attach base class to the record.
}
+//===----------------------------------------------------------------------===//
+// C++ class member Handling
+//===----------------------------------------------------------------------===//
+
+/// ActOnStartCXXClassDef - This is called at the start of a class/struct/union
+/// definition, when on C++.
+void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) {
+ Decl *Dcl = static_cast<Decl *>(D);
+ PushDeclContext(cast<CXXRecordDecl>(Dcl));
+ FieldCollector->StartClass();
+}
+
+/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
+/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
+/// bitfield width if there is one and 'InitExpr' specifies the initializer if
+/// any. 'LastInGroup' is non-null for cases where one declspec has multiple
+/// declarators on it.
+///
+/// NOTE: Because of CXXFieldDecl's inability to be chained like ScopedDecls, if
+/// an instance field is declared, a new CXXFieldDecl is created but the method
+/// does *not* return it; it returns LastInGroup instead. The other C++ members
+/// (which are all ScopedDecls) are returned after appending them to
+/// LastInGroup.
+Sema::DeclTy *
+Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
+ ExprTy *BW, ExprTy *InitExpr,
+ DeclTy *LastInGroup) {
+ const DeclSpec &DS = D.getDeclSpec();
+ IdentifierInfo *II = D.getIdentifier();
+ Expr *BitWidth = static_cast<Expr*>(BW);
+ Expr *Init = static_cast<Expr*>(InitExpr);
+ SourceLocation Loc = D.getIdentifierLoc();
+
+ // C++ 9.2p6: A member shall not be declared to have automatic storage
+ // duration (auto, register) or with the extern storage-class-specifier.
+ switch (DS.getStorageClassSpec()) {
+ case DeclSpec::SCS_unspecified:
+ case DeclSpec::SCS_typedef:
+ case DeclSpec::SCS_static:
+ // FALL THROUGH.
+ break;
+ default:
+ if (DS.getStorageClassSpecLoc().isValid())
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_storageclass_invalid_for_member);
+ else
+ Diag(DS.getThreadSpecLoc(), diag::err_storageclass_invalid_for_member);
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
+ }
+
+ QualType T = GetTypeForDeclarator(D, S);
+
+ // T->isFunctionType() is used instead of D.isFunctionDeclarator() to cover
+ // this case:
+ //
+ // typedef int f();
+ // f a;
+ bool isInstField = (DS.getStorageClassSpec() == DeclSpec::SCS_unspecified &&
+ !T->isFunctionType());
+
+ Decl *Member;
+ bool InvalidDecl = false;
+
+ if (isInstField)
+ Member = static_cast<Decl*>(ActOnField(S, Loc, D, BitWidth));
+ else
+ Member = static_cast<Decl*>(ActOnDeclarator(S, D, LastInGroup));
+
+ if (!Member) return LastInGroup;
+
+ assert(II || isInstField && "No identifier for non-field ?");
+
+ // set/getAccess is not part of Decl's interface to avoid bloating it with C++
+ // specific methods. Use a wrapper class that can be used with all C++ class
+ // member decls.
+ CXXClassMemberWrapper(Member).setAccess(AS);
+
+ if (BitWidth) {
+ // C++ 9.6p2: Only when declaring an unnamed bit-field may the
+ // constant-expression be a value equal to zero.
+ // FIXME: Check this.
+
+ if (D.isFunctionDeclarator()) {
+ // FIXME: Emit diagnostic about only constructors taking base initializers
+ // or something similar, when constructor support is in place.
+ Diag(Loc, diag::err_not_bitfield_type,
+ II->getName(), BitWidth->getSourceRange());
+ InvalidDecl = true;
+
+ } else if (isInstField || isa<FunctionDecl>(Member)) {
+ // An instance field or a function typedef ("typedef int f(); f a;").
+ // C++ 9.6p3: A bit-field shall have integral or enumeration type.
+ if (!T->isIntegralType()) {
+ Diag(Loc, diag::err_not_integral_type_bitfield,
+ II->getName(), BitWidth->getSourceRange());
+ InvalidDecl = true;
+ }
+
+ } else if (isa<TypedefDecl>(Member)) {
+ // "cannot declare 'A' to be a bit-field type"
+ Diag(Loc, diag::err_not_bitfield_type, II->getName(),
+ BitWidth->getSourceRange());
+ InvalidDecl = true;
+
+ } else {
+ assert(isa<CXXClassVarDecl>(Member) &&
+ "Didn't we cover all member kinds?");
+ // C++ 9.6p3: A bit-field shall not be a static member.
+ // "static member 'A' cannot be a bit-field"
+ Diag(Loc, diag::err_static_not_bitfield, II->getName(),
+ BitWidth->getSourceRange());
+ InvalidDecl = true;
+ }
+ }
+
+ if (Init) {
+ // C++ 9.2p4: A member-declarator can contain a constant-initializer only
+ // if it declares a static member of const integral or const enumeration
+ // type.
+ if (CXXClassVarDecl *CVD =
+ dyn_cast<CXXClassVarDecl>(Member)) { // ...static member of...
+ CVD->setInit(Init);
+ QualType MemberTy = CVD->getType().getCanonicalType();
+ // ...const integral or const enumeration type.
+ if (MemberTy.isConstQualified() && MemberTy->isIntegralType()) {
+ if (CheckForConstantInitializer(Init, MemberTy)) // constant-initializer
+ InvalidDecl = true;
+
+ } else {
+ // not const integral.
+ Diag(Loc, diag::err_member_initialization,
+ II->getName(), Init->getSourceRange());
+ InvalidDecl = true;
+ }
+
+ } else {
+ // not static member.
+ Diag(Loc, diag::err_member_initialization,
+ II->getName(), Init->getSourceRange());
+ InvalidDecl = true;
+ }
+ }
+
+ if (InvalidDecl)
+ Member->setInvalidDecl();
+
+ if (isInstField) {
+ FieldCollector->Add(cast<CXXFieldDecl>(Member));
+ return LastInGroup;
+ }
+ return Member;
+}
+
+void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
+ DeclTy *TagDecl,
+ SourceLocation LBrac,
+ SourceLocation RBrac) {
+ ActOnFields(S, RLoc, TagDecl,
+ (DeclTy**)FieldCollector->getCurFields(),
+ FieldCollector->getCurNumFields(), LBrac, RBrac);
+}
+
+void Sema::ActOnFinishCXXClassDef(DeclTy *D,SourceLocation RBrace) {
+ Decl *Dcl = static_cast<Decl *>(D);
+ assert(isa<CXXRecordDecl>(Dcl) &&
+ "Invalid parameter, expected CXXRecordDecl");
+ FieldCollector->FinishClass();
+ PopDeclContext();
+}
//===----------------------------------------------------------------------===//
// Namespace Handling
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jul 1 05:37:29 2008
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "SemaUtil.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -130,6 +131,29 @@
return true;
return new DeclRefExpr(VD, VD->getType(), Loc);
}
+
+ if (CXXFieldDecl *FD = dyn_cast<CXXFieldDecl>(D)) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+ if (MD->isStatic())
+ // "invalid use of member 'x' in static member function"
+ return Diag(Loc, diag::err_invalid_member_use_in_static_method,
+ FD->getName());
+ if (cast<CXXRecordDecl>(MD->getParent()) != FD->getParent())
+ // "invalid use of nonstatic data member 'x'"
+ return Diag(Loc, diag::err_invalid_non_static_member_use,
+ FD->getName());
+
+ if (FD->isInvalidDecl())
+ return true;
+
+ // FIXME: Use DeclRefExpr or a new Expr for a direct CXXField reference.
+ ExprResult ThisExpr = ActOnCXXThis(SourceLocation());
+ return new MemberExpr(static_cast<Expr*>(ThisExpr.Val),
+ true, FD, Loc, FD->getType());
+ }
+
+ return Diag(Loc, diag::err_invalid_non_static_member_use, FD->getName());
+ }
if (isa<TypedefDecl>(D))
return Diag(Loc, diag::err_unexpected_typedef, II.getName());
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=52956&r1=52955&r2=52956&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jul 1 05:37:29 2008
@@ -49,3 +49,21 @@
Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprTy *E) {
return new CXXThrowExpr((Expr*)E, Context.VoidTy, OpLoc);
}
+
+Action::ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
+ /// C++ 9.3.2: In the body of a non-static member function, the keyword this
+ /// is a non-lvalue expression whose value is the address of the object for
+ /// which the function is called.
+
+ if (!isa<FunctionDecl>(CurContext)) {
+ Diag(ThisLoc, diag::err_invalid_this_use);
+ return ExprResult(true);
+ }
+
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext))
+ if (MD->isInstance())
+ return new PreDefinedExpr(ThisLoc, MD->getThisType(Context),
+ PreDefinedExpr::CXXThis);
+
+ return Diag(ThisLoc, diag::err_invalid_this_use);
+}
Added: cfe/trunk/test/Sema/cxx-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/cxx-class.cpp?rev=52956&view=auto
==============================================================================
--- cfe/trunk/test/Sema/cxx-class.cpp (added)
+++ cfe/trunk/test/Sema/cxx-class.cpp Tue Jul 1 05:37:29 2008
@@ -0,0 +1,70 @@
+// RUN: clang -fsyntax-only -verify %s
+class C {
+public:
+ auto int errx; // expected-error {{error: storage class specified for a member declaration}}
+ register int erry; // expected-error {{error: storage class specified for a member declaration}}
+ extern int errz; // expected-error {{error: storage class specified for a member declaration}}
+
+ static void sm() {
+ sx = 0;
+ this->x = 0; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+ x = 0; // expected-error {{error: invalid use of member 'x' in static member function}}
+ }
+
+ class NestedC {
+ void m() {
+ sx = 0;
+ x = 0; // expected-error {{error: invalid use of nonstatic data member 'x'}}
+ }
+ };
+
+ int b : 1, w : 2;
+ int : 1, : 2;
+ typedef int E : 1; // expected-error {{error: cannot declare 'E' to be a bit-field type}}
+ static int sb : 1; // expected-error {{error: static member 'sb' cannot be a bit-field}}
+ static int vs;
+
+ typedef int func();
+ func tm;
+ func btm : 1; // expected-error {{error: bit-field 'btm' with non-integral type}}
+ NestedC bc : 1; // expected-error {{error: bit-field 'bc' with non-integral type}}
+
+ enum E { en1, en2 };
+
+ int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}}
+ static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}}
+ static const NestedC ci = 0; // expected-error {{error: 'ci' can only be initialized if it is a static const integral data member}}
+ static const int nci = vs; // expected-error {{error: initializer element is not constant}}
+ static const int vi = 0;
+ static const E evi = 0;
+
+ void m() {
+ sx = 0;
+ this->x = 0;
+ y = 0;
+ this = 0; // expected-error {{error: expression is not assignable}}
+ }
+
+ int f1(int p) {
+ A z = 6;
+ return p + x + this->y + z;
+ }
+
+ typedef int A;
+
+private:
+ int x,y;
+ static int sx;
+};
+
+class C2 {
+ void f() {
+ static int lx;
+ class LC1 {
+ int m() { return lx; }
+ };
+ class LC2 {
+ int m() { return lx; }
+ };
+ }
+};
Added: cfe/trunk/test/Sema/cxx-this.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/cxx-this.cpp?rev=52956&view=auto
==============================================================================
--- cfe/trunk/test/Sema/cxx-this.cpp (added)
+++ cfe/trunk/test/Sema/cxx-this.cpp Tue Jul 1 05:37:29 2008
@@ -0,0 +1,6 @@
+// RUN: clang -fsyntax-only -verify %s
+int x = this; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+
+void f() {
+ int x = this; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+}
More information about the cfe-commits
mailing list