ObjCProtocol,
PropertyDecl,
// ScopedDecl
- CompatibleAlias,
+ ObjCCompatibleAlias,
// TypeDecl
ObjCInterface,
Typedef,
// 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,
case ParmVar:
case EnumConstant:
case ObjCInterface:
- case CompatibleAlias:
+ case ObjCCompatibleAlias:
return IDNS_Ordinary;
case Struct:
case Union:
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;
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)
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,
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; }
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;
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;
}
}
}
+//===----------------------------------------------------------------------===//
+// 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
}
}
-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;
}
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>())
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))
--- /dev/null
+// 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