diff options
-rw-r--r-- | include/clang/AST/Decl.h | 18 | ||||
-rw-r--r-- | include/clang/AST/DeclObjC.h | 4 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 39 | ||||
-rw-r--r-- | test/Sema/objc-ivar-lookup.m | 18 |
5 files changed, 102 insertions, 25 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 357ded624c..864a50e5c6 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -51,7 +51,7 @@ public: ObjCProtocol, PropertyDecl, // ScopedDecl - CompatibleAlias, + ObjCCompatibleAlias, // TypeDecl ObjCInterface, Typedef, @@ -78,7 +78,7 @@ public: // of the class, to allow efficient classof. NamedFirst = Field, NamedLast = ParmVar, FieldFirst = Field, FieldLast = ObjCIvar, - ScopedFirst = CompatibleAlias, ScopedLast = ParmVar, + ScopedFirst = ObjCCompatibleAlias, ScopedLast = ParmVar, TypeFirst = ObjCInterface, TypeLast = Class, TagFirst = Enum , TagLast = Class, RecordFirst = Struct , RecordLast = Class, @@ -161,7 +161,7 @@ public: case ParmVar: case EnumConstant: case ObjCInterface: - case CompatibleAlias: + case ObjCCompatibleAlias: return IDNS_Ordinary; case Struct: case Union: @@ -247,6 +247,12 @@ public: const ScopedDecl *getNextDeclarator() const { return NextDeclarator; } void setNextDeclarator(ScopedDecl *N) { NextDeclarator = N; } + // isDefinedOutsideFunctionOrMethod - This predicate returns true if this + // scoped decl is defined outside the current function or method. This is + // roughly global variables and functions, but also handles enums (which could + // be defined inside or outside a function etc). + bool isDefinedOutsideFunctionOrMethod() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= ScopedFirst && D->getKind() <= ScopedLast; @@ -348,7 +354,11 @@ protected: virtual void ReadImpl(llvm::Deserializer& S); }; -/// BlockVarDecl - Represent a local variable declaration. +/// BlockVarDecl - Represent a local variable declaration. Note that this +/// includes static variables inside of functions. +/// +/// void foo() { int x; static int y; extern int z; } +/// class BlockVarDecl : public VarDecl { BlockVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S, ScopedDecl *PrevDecl) diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 0cc966214a..81228075e3 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -877,7 +877,7 @@ class ObjCCompatibleAliasDecl : public ScopedDecl { ObjCCompatibleAliasDecl(SourceLocation L, IdentifierInfo *Id, ObjCInterfaceDecl* aliasedClass) - : ScopedDecl(CompatibleAlias, L, Id, 0), AliasedClass(aliasedClass) {} + : ScopedDecl(ObjCCompatibleAlias, L, Id, 0), AliasedClass(aliasedClass) {} public: static ObjCCompatibleAliasDecl *Create(ASTContext &C, SourceLocation L, IdentifierInfo *Id, @@ -887,7 +887,7 @@ public: ObjCInterfaceDecl *getClassInterface() { return AliasedClass; } static bool classof(const Decl *D) { - return D->getKind() == CompatibleAlias; + return D->getKind() == ObjCCompatibleAlias; } static bool classof(const ObjCCompatibleAliasDecl *D) { return true; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index df403ebd66..bad65cf84c 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -193,7 +193,7 @@ void Decl::addDeclKind(Kind k) { case ObjCIvar: nIvarDecls++; break; case ObjCImplementation: nObjCImplementationDecls++; break; case ObjCCategoryImpl: nObjCCategoryImpl++; break; - case CompatibleAlias: nObjCCompatibleAlias++; break; + case ObjCCompatibleAlias: nObjCCompatibleAlias++; break; case PropertyDecl: nObjCPropertyDecl++; break; case LinkageSpec: nLinkageSpecDecl++; break; case FileScopeAsm: nFileScopeAsmDecl++; break; @@ -319,12 +319,46 @@ const Attr *Decl::getAttrs() const { return (*DeclAttrs)[this]; } +//===----------------------------------------------------------------------===// +// NamedDecl Implementation +//===----------------------------------------------------------------------===// + const char *NamedDecl::getName() const { if (const IdentifierInfo *II = getIdentifier()) return II->getName(); return ""; } +//===----------------------------------------------------------------------===// +// ScopedDecl Implementation +//===----------------------------------------------------------------------===// + +// isDefinedOutsideFunctionOrMethod - This predicate returns true if this +// scoped decl is defined outside the current function or method. This is +// roughly global variables and functions, but also handles enums (which could +// be defined inside or outside a function etc). +bool ScopedDecl::isDefinedOutsideFunctionOrMethod() const { + if (const VarDecl *VD = dyn_cast<VarDecl>(this)) + return VD->hasGlobalStorage(); + if (isa<FunctionDecl>(this)) + return true; + + // FIXME: Why is ObjCCompatibleAlias a scopedecl? + if (isa<ObjCCompatibleAliasDecl>(this)) + return true; + + // FIXME: This needs to check the context the decl was defined in! + if (isa<TypeDecl>(this) || isa<EnumConstantDecl>(this)) + return true; + + assert(0 && "Unknown ScopedDecl!"); + return false; +} + +//===----------------------------------------------------------------------===// +// FunctionDecl Implementation +//===----------------------------------------------------------------------===// + FunctionDecl::~FunctionDecl() { delete[] ParamInfo; } @@ -346,6 +380,9 @@ void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { } } +//===----------------------------------------------------------------------===// +// RecordDecl Implementation +//===----------------------------------------------------------------------===// /// defineBody - When created, RecordDecl's correspond to a forward declared /// record. This method is used to mark the decl as being defined, with the @@ -360,14 +397,13 @@ void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) { } } -FieldDecl* RecordDecl::getMember(IdentifierInfo *name) { +FieldDecl *RecordDecl::getMember(IdentifierInfo *II) { if (Members == 0 || NumMembers < 0) return 0; - // linear search. When C++ classes come along, will likely need to revisit. - for (int i = 0; i < NumMembers; ++i) { - if (Members[i]->getIdentifier() == name) + // Linear search. When C++ classes come along, will likely need to revisit. + for (int i = 0; i != NumMembers; ++i) + if (Members[i]->getIdentifier() == II) return Members[i]; - } return 0; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1abbe801f2..c815b54868 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -74,31 +74,43 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, bool HasTrailingLParen) { - // Could be enum-constant or decl. + // Could be enum-constant, value decl, instance variable, etc. ScopedDecl *D = LookupScopedDecl(&II, Decl::IDNS_Ordinary, Loc, S); + + // If this reference is in an Objective-C method, then ivar lookup happens as + // well. + if (CurMethodDecl) { + // There are two cases to handle here. 1) scoped lookup could have failed, + // in which case we should look for an ivar. 2) scoped lookup could have + // found a decl, but that decl is outside the current method (i.e. a global + // variable). In these two cases, we do a lookup for an ivar with this + // name, if the lookup suceeds, we replace it our current decl. + if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) { + ObjCInterfaceDecl *IFace = CurMethodDecl->getClassInterface(), *DeclClass; + if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(&II, DeclClass)) { + // FIXME: This should use a new expr for a direct reference, don't turn + // this into Self->ivar, just return a BareIVarExpr or something. + IdentifierInfo &II = Context.Idents.get("self"); + ExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false); + return new ObjCIvarRefExpr(IV, IV->getType(), Loc, + static_cast<Expr*>(SelfExpr.Val), true, true); + } + } + } + if (D == 0) { // Otherwise, this could be an implicitly declared function reference (legal // in C90, extension in C99). if (HasTrailingLParen && - // Not in C++. - !getLangOptions().CPlusPlus) + !getLangOptions().CPlusPlus) // Not in C++. D = ImplicitlyDefineFunction(Loc, II, S); else { - if (CurMethodDecl) { - ObjCInterfaceDecl *IFace = CurMethodDecl->getClassInterface(); - ObjCInterfaceDecl *clsDeclared; - if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(&II, clsDeclared)) { - IdentifierInfo &II = Context.Idents.get("self"); - ExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false); - return new ObjCIvarRefExpr(IV, IV->getType(), Loc, - static_cast<Expr*>(SelfExpr.Val), true, true); - } - } // If this name wasn't predeclared and if this is not a function call, // diagnose the problem. return Diag(Loc, diag::err_undeclared_var_use, II.getName()); } } + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { // check if referencing an identifier with __attribute__((deprecated)). if (VD->getAttr<DeprecatedAttr>()) @@ -109,6 +121,7 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, return true; return new DeclRefExpr(VD, VD->getType(), Loc); } + if (isa<TypedefDecl>(D)) return Diag(Loc, diag::err_unexpected_typedef, II.getName()); if (isa<ObjCInterfaceDecl>(D)) diff --git a/test/Sema/objc-ivar-lookup.m b/test/Sema/objc-ivar-lookup.m new file mode 100644 index 0000000000..e599e9da01 --- /dev/null +++ b/test/Sema/objc-ivar-lookup.m @@ -0,0 +1,18 @@ +// RUN: clang %s -fsyntax-only -verify + +@interface Test { + int x; +} + +-(void) setX: (int) d; +@end + +extern struct foo x; + +@implementation Test + +-(void) setX: (int) n { + x = n; +} + +@end |