From: Chris Lattner Date: Sat, 21 Jun 2008 19:39:06 +0000 (+0000) Subject: add parser and sema support for the funny ObjC '@defs' thing. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5a6ddbf295d2ea1c28cfb67d82db22f3893ede6f;p=clang add parser and sema support for the funny ObjC '@defs' thing. Patch by David Chisnall! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52586 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 92c0bde30a..8742379d7c 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -331,6 +331,8 @@ DIAG(err_expected_ident_lbrace, ERROR, "expected identifier or '{'") DIAG(err_expected_lbrace, ERROR, "expected '{'") +DIAG(err_expected_lparen, ERROR, + "expected '('") DIAG(err_expected_rparen, ERROR, "expected ')'") DIAG(err_expected_rsquare, ERROR, @@ -922,6 +924,8 @@ DIAG(err_typecheck_call_invalid_ordered_compare, ERROR, "ordered compare requires two args of floating point type ('%0' and '%1')") DIAG(err_typecheck_cond_expect_scalar, ERROR, "used type '%0' where arithmetic or pointer type is required") +DIAG(err_typecheck_invalid_union_cast, ERROR, + "'%0' is not a member of '%1'") DIAG(ext_typecheck_cond_one_void, EXTENSION, "C99 forbids conditional expressions with only one void side") DIAG(ext_typecheck_cast_nonscalar, EXTENSION, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 17899d41d7..56c72dc452 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -210,6 +210,11 @@ public: return 0; } + /// Act on @defs() element found when parsing a structure. ClassName is the + /// name of the referenced class. + virtual void ActOnDefs(Scope *S, SourceLocation DeclStart, + IdentifierInfo *ClassName, + llvm::SmallVector &Decls) {} virtual DeclTy *ActOnField(Scope *S, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth) { return 0; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 46246e64ba..95344c438e 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -707,7 +707,7 @@ ParseStructDeclaration(DeclSpec &DS, /// struct-declaration-list: /// struct-declaration /// struct-declaration-list struct-declaration -/// [OBC] '@' 'defs' '(' class-name ')' [TODO] +/// [OBC] '@' 'defs' '(' class-name ')' /// void Parser::ParseStructUnionBody(SourceLocation RecordLoc, unsigned TagType, DeclTy *TagDecl) { @@ -736,18 +736,39 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Parse all the comma separated declarators. DeclSpec DS; FieldDeclarators.clear(); - ParseStructDeclaration(DS, FieldDeclarators); - - // Convert them all to fields. - for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { - FieldDeclarator &FD = FieldDeclarators[i]; - // Install the declarator into the current TagDecl. - DeclTy *Field = Actions.ActOnField(CurScope, - DS.getSourceRange().getBegin(), - FD.D, FD.BitfieldSize); - FieldDecls.push_back(Field); - } - + if (!Tok.is(tok::at)) { + ParseStructDeclaration(DS, FieldDeclarators); + + // Convert them all to fields. + for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { + FieldDeclarator &FD = FieldDeclarators[i]; + // Install the declarator into the current TagDecl. + DeclTy *Field = Actions.ActOnField(CurScope, + DS.getSourceRange().getBegin(), + FD.D, FD.BitfieldSize); + FieldDecls.push_back(Field); + } + } else { // Handle @defs + ConsumeToken(); + if (!Tok.isObjCAtKeyword(tok::objc_defs)) { + Diag(Tok, diag::err_unexpected_at); + SkipUntil(tok::semi, true, true); + continue; + } + ConsumeToken(); + ExpectAndConsume(tok::l_paren, diag::err_expected_lparen); + if (!Tok.is(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi, true, true); + continue; + } + llvm::SmallVector Fields; + Actions.ActOnDefs(CurScope, Tok.getLocation(), Tok.getIdentifierInfo(), + Fields); + FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end()); + ConsumeToken(); + ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); + } if (Tok.is(tok::semi)) { ConsumeToken(); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b3b5941dc3..1d68160813 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -240,6 +240,8 @@ private: virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, SourceLocation KWLoc, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr); + virtual void ActOnDefs(Scope *S, SourceLocation DeclStart, IdentifierInfo + *ClassName, llvm::SmallVector &Decls); virtual DeclTy *ActOnField(Scope *S, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7af557b1a8..ee1aad54ed 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1731,6 +1731,35 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, return New; } +/// Collect the instance variables declared in an Objective-C object. Used in +/// the creation of structures from objects using the @defs directive. +static void CollectIvars(ObjCInterfaceDecl *Class, + llvm::SmallVector &ivars) { + if (Class->getSuperClass()) + CollectIvars(Class->getSuperClass(), ivars); + ivars.append(Class->ivar_begin(), Class->ivar_end()); +} + +/// Called whenever @defs(ClassName) is encountered in the source. Inserts the +/// instance variables of ClassName into Decls. +void Sema::ActOnDefs(Scope *S, SourceLocation DeclStart, + IdentifierInfo *ClassName, + llvm::SmallVector &Decls) { + // Check that ClassName is a valid class + ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName); + if (!Class) { + Diag(DeclStart, diag::err_undef_interface, ClassName->getName()); + return; + } + // Add the isa pointer + Decls.push_back(FieldDecl::Create(Context, SourceLocation(), + &Context.Idents.get("isa"), + Context.getObjCClassType())); + // Collect the instance variables + CollectIvars(Class, Decls); +} + + static bool CalcFakeICEVal(const Expr* Expr, llvm::APSInt& Result, ASTContext& Context) { diff --git a/test/Sema/objc-at-defs.m b/test/Sema/objc-at-defs.m new file mode 100644 index 0000000000..5bbdd6a715 --- /dev/null +++ b/test/Sema/objc-at-defs.m @@ -0,0 +1,29 @@ +// RUN: clang %s -fsyntax-only + +@interface Test { + double a; +} +@end +@implementation Test +@end +@interface TestObject : Test { +@public + float bar; + int foo; +} +@end +@implementation TestObject +@end +struct wibble { + @defs(TestObject) +}; + + +int main(void) +{ + TestObject * a = (id)malloc(100); + a->foo = 12; + printf("12: %d\n", ((struct wibble*)a)->foo); + printf("%d: %d\n", ((char*)&(((struct wibble*)a)->foo)) - (char*)a, ((char*)&(a->foo)) - (char*)a); + return 0; +}