2006-11-09 14:32:27 +08:00
|
|
|
//===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by Chris Lattner and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements semantic analysis for declarations.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2006-11-10 13:29:30 +08:00
|
|
|
#include "Sema.h"
|
2006-12-03 16:41:30 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2007-01-28 16:20:04 +08:00
|
|
|
#include "clang/AST/Builtins.h"
|
2006-11-10 13:29:30 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
2007-10-02 03:00:59 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2007-01-24 07:42:53 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2006-11-12 06:59:23 +08:00
|
|
|
#include "clang/AST/Type.h"
|
2006-11-20 07:16:18 +08:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
2006-11-10 13:29:30 +08:00
|
|
|
#include "clang/Parse/Scope.h"
|
2006-11-20 14:49:47 +08:00
|
|
|
#include "clang/Basic/LangOptions.h"
|
2007-01-28 16:20:04 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2007-09-19 07:55:05 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2007-01-27 14:24:01 +08:00
|
|
|
#include "llvm/ADT/SmallSet.h"
|
2007-10-06 02:00:57 +08:00
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2007-11-01 02:42:27 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2006-11-09 14:32:27 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2006-11-20 09:29:42 +08:00
|
|
|
Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const {
|
2007-10-13 00:34:10 +08:00
|
|
|
Decl *IIDecl = II.getFETokenInfo<Decl>();
|
|
|
|
// Find first occurance of none-tagged declaration
|
|
|
|
while(IIDecl && IIDecl->getIdentifierNamespace() != Decl::IDNS_Ordinary)
|
|
|
|
IIDecl = cast<ScopedDecl>(IIDecl)->getNext();
|
|
|
|
if (!IIDecl)
|
|
|
|
return 0;
|
|
|
|
if (isa<TypedefDecl>(IIDecl) || isa<ObjcInterfaceDecl>(IIDecl))
|
|
|
|
return IIDecl;
|
|
|
|
if (ObjcCompatibleAliasDecl *ADecl =
|
|
|
|
dyn_cast<ObjcCompatibleAliasDecl>(IIDecl))
|
|
|
|
return ADecl->getClassInterface();
|
2007-09-07 05:24:23 +08:00
|
|
|
return 0;
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2007-10-10 06:01:59 +08:00
|
|
|
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
|
2007-08-26 14:24:45 +08:00
|
|
|
if (S->decl_empty()) return;
|
|
|
|
assert((S->getFlags() & Scope::DeclScope) &&"Scope shouldn't contain decls!");
|
|
|
|
|
2006-11-19 10:31:38 +08:00
|
|
|
for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
|
|
|
|
I != E; ++I) {
|
2007-09-14 02:10:37 +08:00
|
|
|
Decl *TmpD = static_cast<Decl*>(*I);
|
|
|
|
assert(TmpD && "This decl didn't get pushed??");
|
|
|
|
ScopedDecl *D = dyn_cast<ScopedDecl>(TmpD);
|
|
|
|
assert(D && "This decl isn't a ScopedDecl?");
|
|
|
|
|
2007-01-23 09:33:16 +08:00
|
|
|
IdentifierInfo *II = D->getIdentifier();
|
|
|
|
if (!II) continue;
|
2006-11-19 10:31:38 +08:00
|
|
|
|
2007-01-23 09:33:16 +08:00
|
|
|
// Unlink this decl from the identifier. Because the scope contains decls
|
|
|
|
// in an unordered collection, and because we have multiple identifier
|
|
|
|
// namespaces (e.g. tag, normal, label),the decl may not be the first entry.
|
|
|
|
if (II->getFETokenInfo<Decl>() == D) {
|
|
|
|
// Normal case, no multiple decls in different namespaces.
|
|
|
|
II->setFETokenInfo(D->getNext());
|
|
|
|
} else {
|
|
|
|
// Scan ahead. There are only three namespaces in C, so this loop can
|
|
|
|
// never execute more than 3 times.
|
2007-09-14 02:10:37 +08:00
|
|
|
ScopedDecl *SomeDecl = II->getFETokenInfo<ScopedDecl>();
|
2007-01-23 09:33:16 +08:00
|
|
|
while (SomeDecl->getNext() != D) {
|
|
|
|
SomeDecl = SomeDecl->getNext();
|
|
|
|
assert(SomeDecl && "Didn't find this decl on its identifier's chain!");
|
|
|
|
}
|
|
|
|
SomeDecl->setNext(D->getNext());
|
|
|
|
}
|
2006-11-19 10:31:38 +08:00
|
|
|
|
2006-11-21 09:32:20 +08:00
|
|
|
// This will have to be revisited for C++: there we want to nest stuff in
|
|
|
|
// namespace decls etc. Even for C, we might want a top-level translation
|
|
|
|
// unit decl or something.
|
|
|
|
if (!CurFunctionDecl)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Chain this decl to the containing function, it now owns the memory for
|
|
|
|
// the decl.
|
|
|
|
D->setNext(CurFunctionDecl->getDeclChain());
|
|
|
|
CurFunctionDecl->setDeclChain(D);
|
2006-11-19 10:31:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-13 03:38:20 +08:00
|
|
|
/// LookupInterfaceDecl - Lookup interface declaration in the scope chain.
|
|
|
|
/// Return the first declaration found (which may or may not be a class
|
2007-10-13 03:53:08 +08:00
|
|
|
/// declaration. Caller is responsible for handling the none-class case.
|
2007-10-13 03:38:20 +08:00
|
|
|
/// Bypassing the alias of a class by returning the aliased class.
|
|
|
|
ScopedDecl *Sema::LookupInterfaceDecl(IdentifierInfo *ClassName) {
|
|
|
|
ScopedDecl *IDecl;
|
|
|
|
// Scan up the scope chain looking for a decl that matches this identifier
|
|
|
|
// that is in the appropriate namespace.
|
|
|
|
for (IDecl = ClassName->getFETokenInfo<ScopedDecl>(); IDecl;
|
|
|
|
IDecl = IDecl->getNext())
|
|
|
|
if (IDecl->getIdentifierNamespace() == Decl::IDNS_Ordinary)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (ObjcCompatibleAliasDecl *ADecl =
|
|
|
|
dyn_cast_or_null<ObjcCompatibleAliasDecl>(IDecl))
|
|
|
|
return ADecl->getClassInterface();
|
|
|
|
return IDecl;
|
|
|
|
}
|
|
|
|
|
2007-09-30 01:04:06 +08:00
|
|
|
/// getObjcInterfaceDecl - Look up a for a class declaration in the scope.
|
2007-09-29 08:54:24 +08:00
|
|
|
/// return 0 if one not found.
|
2007-10-03 04:01:56 +08:00
|
|
|
ObjcInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
|
2007-10-13 03:38:20 +08:00
|
|
|
ScopedDecl *IdDecl = LookupInterfaceDecl(Id);
|
|
|
|
return cast_or_null<ObjcInterfaceDecl>(IdDecl);
|
2007-09-29 08:54:24 +08:00
|
|
|
}
|
|
|
|
|
2007-01-22 15:39:13 +08:00
|
|
|
/// LookupScopedDecl - Look up the inner-most declaration in the specified
|
|
|
|
/// namespace.
|
2007-09-14 02:10:37 +08:00
|
|
|
ScopedDecl *Sema::LookupScopedDecl(IdentifierInfo *II, unsigned NSI,
|
|
|
|
SourceLocation IdLoc, Scope *S) {
|
2007-01-22 15:39:13 +08:00
|
|
|
if (II == 0) return 0;
|
2007-01-28 08:38:24 +08:00
|
|
|
Decl::IdentifierNamespace NS = (Decl::IdentifierNamespace)NSI;
|
2007-01-22 15:39:13 +08:00
|
|
|
|
|
|
|
// Scan up the scope chain looking for a decl that matches this identifier
|
|
|
|
// that is in the appropriate namespace. This search should not take long, as
|
|
|
|
// shadowing of names is uncommon, and deep shadowing is extremely uncommon.
|
2007-09-14 02:10:37 +08:00
|
|
|
for (ScopedDecl *D = II->getFETokenInfo<ScopedDecl>(); D; D = D->getNext())
|
2007-01-22 15:39:13 +08:00
|
|
|
if (D->getIdentifierNamespace() == NS)
|
|
|
|
return D;
|
2007-01-28 08:38:24 +08:00
|
|
|
|
2007-01-28 16:20:04 +08:00
|
|
|
// If we didn't find a use of this identifier, and if the identifier
|
|
|
|
// corresponds to a compiler builtin, create the decl object for the builtin
|
|
|
|
// now, injecting it into translation unit scope, and return it.
|
|
|
|
if (NS == Decl::IDNS_Ordinary) {
|
|
|
|
// If this is a builtin on some other target, or if this builtin varies
|
|
|
|
// across targets (e.g. in type), emit a diagnostic and mark the translation
|
|
|
|
// unit non-portable for using it.
|
|
|
|
if (II->isNonPortableBuiltin()) {
|
|
|
|
// Only emit this diagnostic once for this builtin.
|
|
|
|
II->setNonPortableBuiltin(false);
|
|
|
|
Context.Target.DiagnoseNonPortability(IdLoc,
|
|
|
|
diag::port_target_builtin_use);
|
|
|
|
}
|
|
|
|
// If this is a builtin on this (or all) targets, create the decl.
|
|
|
|
if (unsigned BuiltinID = II->getBuiltinID())
|
|
|
|
return LazilyCreateBuiltin(II, BuiltinID, S);
|
|
|
|
}
|
2007-01-22 15:39:13 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-16 04:28:48 +08:00
|
|
|
void Sema::InitBuiltinVaListType()
|
|
|
|
{
|
|
|
|
if (!Context.getBuiltinVaListType().isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
|
|
|
|
ScopedDecl *VaDecl = LookupScopedDecl(VaIdent, Decl::IDNS_Ordinary,
|
|
|
|
SourceLocation(), TUScope);
|
2007-10-19 06:17:45 +08:00
|
|
|
TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
|
2007-10-16 04:28:48 +08:00
|
|
|
Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
|
|
|
|
}
|
|
|
|
|
2007-01-28 16:20:04 +08:00
|
|
|
/// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope.
|
|
|
|
/// lazily create a decl for it.
|
2007-10-11 07:42:28 +08:00
|
|
|
ScopedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
|
|
|
|
Scope *S) {
|
2007-01-28 16:20:04 +08:00
|
|
|
Builtin::ID BID = (Builtin::ID)bid;
|
|
|
|
|
2007-10-16 04:28:48 +08:00
|
|
|
if (BID == Builtin::BI__builtin_va_start ||
|
2007-10-13 07:56:29 +08:00
|
|
|
BID == Builtin::BI__builtin_va_copy ||
|
2007-10-16 04:28:48 +08:00
|
|
|
BID == Builtin::BI__builtin_va_end)
|
|
|
|
InitBuiltinVaListType();
|
|
|
|
|
2007-10-11 09:00:40 +08:00
|
|
|
QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context);
|
2007-06-09 08:53:06 +08:00
|
|
|
FunctionDecl *New = new FunctionDecl(SourceLocation(), II, R,
|
2007-08-26 12:02:13 +08:00
|
|
|
FunctionDecl::Extern, false, 0);
|
2007-01-28 16:20:04 +08:00
|
|
|
|
|
|
|
// Find translation-unit scope to insert this function into.
|
2007-08-26 14:24:45 +08:00
|
|
|
if (Scope *FnS = S->getFnParent())
|
|
|
|
S = FnS->getParent(); // Skip all scopes in a function at once.
|
2007-01-28 16:20:04 +08:00
|
|
|
while (S->getParent())
|
|
|
|
S = S->getParent();
|
|
|
|
S->AddDecl(New);
|
|
|
|
|
|
|
|
// Add this decl to the end of the identifier info.
|
2007-09-14 02:10:37 +08:00
|
|
|
if (ScopedDecl *LastDecl = II->getFETokenInfo<ScopedDecl>()) {
|
2007-01-28 16:20:04 +08:00
|
|
|
// Scan until we find the last (outermost) decl in the id chain.
|
|
|
|
while (LastDecl->getNext())
|
|
|
|
LastDecl = LastDecl->getNext();
|
|
|
|
// Insert before (outside) it.
|
|
|
|
LastDecl->setNext(New);
|
|
|
|
} else {
|
|
|
|
II->setFETokenInfo(New);
|
|
|
|
}
|
|
|
|
// Make sure clients iterating over decls see this.
|
|
|
|
LastInGroupList.push_back(New);
|
|
|
|
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2007-01-28 03:27:06 +08:00
|
|
|
/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the same name
|
|
|
|
/// and scope as a previous declaration 'Old'. Figure out how to resolve this
|
|
|
|
/// situation, merging decls or emitting diagnostics as appropriate.
|
|
|
|
///
|
2007-09-14 05:41:19 +08:00
|
|
|
TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *OldD) {
|
2007-01-28 03:32:14 +08:00
|
|
|
// Verify the old decl was also a typedef.
|
|
|
|
TypedefDecl *Old = dyn_cast<TypedefDecl>(OldD);
|
|
|
|
if (!Old) {
|
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_kind,
|
|
|
|
New->getName());
|
|
|
|
Diag(OldD->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2007-11-01 02:42:27 +08:00
|
|
|
// Allow multiple definitions for ObjC built-in typedefs.
|
|
|
|
// FIXME: Verify the underlying types are equivalent!
|
|
|
|
if (PP.getLangOptions().ObjC1 && isBuiltinObjcType(New))
|
|
|
|
return Old;
|
|
|
|
|
2007-01-28 03:27:06 +08:00
|
|
|
// TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
|
|
|
|
// TODO: This is totally simplistic. It should handle merging functions
|
|
|
|
// together etc, merging extern int X; int X; ...
|
|
|
|
Diag(New->getLocation(), diag::err_redefinition, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// MergeFunctionDecl - We just parsed a function 'New' which has the same name
|
|
|
|
/// and scope as a previous declaration 'Old'. Figure out how to resolve this
|
|
|
|
/// situation, merging decls or emitting diagnostics as appropriate.
|
|
|
|
///
|
2007-09-14 05:41:19 +08:00
|
|
|
FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, ScopedDecl *OldD) {
|
2007-01-28 03:32:14 +08:00
|
|
|
// Verify the old decl was also a function.
|
|
|
|
FunctionDecl *Old = dyn_cast<FunctionDecl>(OldD);
|
|
|
|
if (!Old) {
|
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_kind,
|
|
|
|
New->getName());
|
|
|
|
Diag(OldD->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2007-01-28 03:35:39 +08:00
|
|
|
// This is not right, but it's a start. If 'Old' is a function prototype with
|
|
|
|
// the same type as 'New', silently allow this. FIXME: We should link up decl
|
|
|
|
// objects here.
|
2007-03-16 08:33:25 +08:00
|
|
|
if (Old->getBody() == 0 &&
|
|
|
|
Old->getCanonicalType() == New->getCanonicalType()) {
|
2007-01-28 03:35:39 +08:00
|
|
|
return New;
|
|
|
|
}
|
2007-01-28 03:32:14 +08:00
|
|
|
|
2007-01-28 03:27:06 +08:00
|
|
|
// TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
|
|
|
|
// TODO: This is totally simplistic. It should handle merging functions
|
|
|
|
// together etc, merging extern int X; int X; ...
|
|
|
|
Diag(New->getLocation(), diag::err_redefinition, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// MergeVarDecl - We just parsed a variable 'New' which has the same name
|
|
|
|
/// and scope as a previous declaration 'Old'. Figure out how to resolve this
|
|
|
|
/// situation, merging decls or emitting diagnostics as appropriate.
|
|
|
|
///
|
2007-04-02 05:27:45 +08:00
|
|
|
/// FIXME: Need to carefully consider tentative definition rules (C99 6.9.2p2).
|
|
|
|
/// For example, we incorrectly complain about i1, i4 from C99 6.9.2p4.
|
|
|
|
///
|
2007-09-14 05:41:19 +08:00
|
|
|
VarDecl *Sema::MergeVarDecl(VarDecl *New, ScopedDecl *OldD) {
|
2007-01-28 03:32:14 +08:00
|
|
|
// Verify the old decl was also a variable.
|
|
|
|
VarDecl *Old = dyn_cast<VarDecl>(OldD);
|
|
|
|
if (!Old) {
|
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_kind,
|
|
|
|
New->getName());
|
|
|
|
Diag(OldD->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
2007-08-30 09:06:46 +08:00
|
|
|
FileVarDecl *OldFSDecl = dyn_cast<FileVarDecl>(Old);
|
|
|
|
FileVarDecl *NewFSDecl = dyn_cast<FileVarDecl>(New);
|
|
|
|
bool OldIsTentative = false;
|
|
|
|
|
|
|
|
if (OldFSDecl && NewFSDecl) { // C99 6.9.2
|
|
|
|
// Handle C "tentative" external object definitions. FIXME: finish!
|
|
|
|
if (!OldFSDecl->getInit() &&
|
|
|
|
(OldFSDecl->getStorageClass() == VarDecl::None ||
|
|
|
|
OldFSDecl->getStorageClass() == VarDecl::Static))
|
|
|
|
OldIsTentative = true;
|
|
|
|
}
|
2007-03-16 08:33:25 +08:00
|
|
|
// Verify the types match.
|
|
|
|
if (Old->getCanonicalType() != New->getCanonicalType()) {
|
|
|
|
Diag(New->getLocation(), diag::err_redefinition, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
// We've verified the types match, now check if Old is "extern".
|
2007-04-04 07:13:13 +08:00
|
|
|
if (Old->getStorageClass() != VarDecl::Extern) {
|
2007-03-16 08:33:25 +08:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
2007-01-28 03:27:06 +08:00
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2007-01-28 08:38:24 +08:00
|
|
|
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
|
|
|
|
/// no declarator (e.g. "struct foo;") is parsed.
|
|
|
|
Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
|
|
|
|
// TODO: emit error on 'int;' or 'const enum foo;'.
|
|
|
|
// TODO: emit error on 'typedef int;'
|
|
|
|
// if (!DS.isMissingDeclaratorOk()) Diag(...);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-17 08:52:43 +08:00
|
|
|
bool Sema::CheckSingleInitializer(Expr *&Init, bool isStatic,
|
|
|
|
QualType DeclType) {
|
|
|
|
SourceLocation loc;
|
|
|
|
|
|
|
|
// FIXME: Remove the isReferenceType check and handle assignment
|
|
|
|
// to a reference.
|
|
|
|
if (isStatic && !DeclType->isReferenceType() &&
|
|
|
|
!Init->isConstantExpr(Context, &loc)) { // C99 6.7.8p4.
|
|
|
|
Diag(loc, diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-09-02 10:04:30 +08:00
|
|
|
AssignmentCheckResult result;
|
2007-10-17 08:52:43 +08:00
|
|
|
loc = Init->getLocStart();
|
2007-09-02 10:04:30 +08:00
|
|
|
// Get the type before calling CheckSingleAssignmentConstraints(), since
|
|
|
|
// it can promote the expression.
|
|
|
|
QualType rhsType = Init->getType();
|
|
|
|
|
|
|
|
result = CheckSingleAssignmentConstraints(DeclType, Init);
|
|
|
|
|
|
|
|
// decode the result (notice that extensions still return a type).
|
|
|
|
switch (result) {
|
|
|
|
case Compatible:
|
|
|
|
break;
|
|
|
|
case Incompatible:
|
2007-09-02 23:34:30 +08:00
|
|
|
// FIXME: tighten up this check which should allow:
|
|
|
|
// char s[] = "abc", which is identical to char s[] = { 'a', 'b', 'c' };
|
|
|
|
if (rhsType == Context.getPointerType(Context.CharTy))
|
|
|
|
break;
|
2007-09-02 10:04:30 +08:00
|
|
|
Diag(loc, diag::err_typecheck_assign_incompatible,
|
|
|
|
DeclType.getAsString(), rhsType.getAsString(),
|
|
|
|
Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
case PointerFromInt:
|
|
|
|
// check for null pointer constant (C99 6.3.2.3p3)
|
|
|
|
if (!Init->isNullPointerConstant(Context)) {
|
|
|
|
Diag(loc, diag::ext_typecheck_assign_pointer_int,
|
|
|
|
DeclType.getAsString(), rhsType.getAsString(),
|
|
|
|
Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IntFromPointer:
|
|
|
|
Diag(loc, diag::ext_typecheck_assign_pointer_int,
|
|
|
|
DeclType.getAsString(), rhsType.getAsString(),
|
|
|
|
Init->getSourceRange());
|
|
|
|
break;
|
|
|
|
case IncompatiblePointer:
|
|
|
|
Diag(loc, diag::ext_typecheck_assign_incompatible_pointer,
|
|
|
|
DeclType.getAsString(), rhsType.getAsString(),
|
|
|
|
Init->getSourceRange());
|
|
|
|
break;
|
|
|
|
case CompatiblePointerDiscardsQualifiers:
|
|
|
|
Diag(loc, diag::ext_typecheck_assign_discards_qualifiers,
|
|
|
|
DeclType.getAsString(), rhsType.getAsString(),
|
|
|
|
Init->getSourceRange());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-04 22:36:54 +08:00
|
|
|
bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot,
|
|
|
|
bool isStatic, QualType ElementType) {
|
2007-09-04 10:20:04 +08:00
|
|
|
SourceLocation loc;
|
2007-09-04 22:36:54 +08:00
|
|
|
Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
|
2007-09-04 10:20:04 +08:00
|
|
|
|
|
|
|
if (isStatic && !expr->isConstantExpr(Context, &loc)) { // C99 6.7.8p4.
|
|
|
|
Diag(loc, diag::err_init_element_not_constant, expr->getSourceRange());
|
|
|
|
return true;
|
2007-10-17 08:52:43 +08:00
|
|
|
} else if (CheckSingleInitializer(expr, isStatic, ElementType)) {
|
2007-09-04 10:20:04 +08:00
|
|
|
return true; // types weren't compatible.
|
|
|
|
}
|
2007-09-04 22:36:54 +08:00
|
|
|
if (savExpr != expr) // The type was promoted, update initializer list.
|
|
|
|
IList->setInit(slot, expr);
|
2007-09-04 10:20:04 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::CheckVariableInitList(QualType DeclType, InitListExpr *IList,
|
|
|
|
QualType ElementType, bool isStatic,
|
|
|
|
int &nInitializers, bool &hadError) {
|
2007-09-02 23:34:30 +08:00
|
|
|
for (unsigned i = 0; i < IList->getNumInits(); i++) {
|
|
|
|
Expr *expr = IList->getInit(i);
|
|
|
|
|
2007-09-04 10:20:04 +08:00
|
|
|
if (InitListExpr *InitList = dyn_cast<InitListExpr>(expr)) {
|
|
|
|
if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) {
|
2007-09-05 05:13:33 +08:00
|
|
|
int maxElements = CAT->getMaximumElements();
|
2007-09-04 10:20:04 +08:00
|
|
|
CheckConstantInitList(DeclType, InitList, ElementType, isStatic,
|
|
|
|
maxElements, hadError);
|
|
|
|
}
|
|
|
|
} else {
|
2007-09-04 22:36:54 +08:00
|
|
|
hadError = CheckInitExpr(expr, IList, i, isStatic, ElementType);
|
2007-09-04 10:20:04 +08:00
|
|
|
}
|
|
|
|
nInitializers++;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Doesn't deal with arrays of structures yet.
|
|
|
|
void Sema::CheckConstantInitList(QualType DeclType, InitListExpr *IList,
|
|
|
|
QualType ElementType, bool isStatic,
|
|
|
|
int &totalInits, bool &hadError) {
|
|
|
|
int maxElementsAtThisLevel = 0;
|
|
|
|
int nInitsAtLevel = 0;
|
2007-09-03 04:30:18 +08:00
|
|
|
|
2007-09-04 10:20:04 +08:00
|
|
|
if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) {
|
|
|
|
// We have a constant array type, compute maxElements *at this level*.
|
2007-09-05 05:13:33 +08:00
|
|
|
maxElementsAtThisLevel = CAT->getMaximumElements();
|
|
|
|
// Set DeclType, used below to recurse (for multi-dimensional arrays).
|
|
|
|
DeclType = CAT->getElementType();
|
2007-09-04 10:20:04 +08:00
|
|
|
} else if (DeclType->isScalarType()) {
|
|
|
|
Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init,
|
|
|
|
IList->getSourceRange());
|
|
|
|
maxElementsAtThisLevel = 1;
|
|
|
|
}
|
|
|
|
// The empty init list "{ }" is treated specially below.
|
|
|
|
unsigned numInits = IList->getNumInits();
|
|
|
|
if (numInits) {
|
|
|
|
for (unsigned i = 0; i < numInits; i++) {
|
|
|
|
Expr *expr = IList->getInit(i);
|
|
|
|
|
|
|
|
if (InitListExpr *InitList = dyn_cast<InitListExpr>(expr)) {
|
|
|
|
CheckConstantInitList(DeclType, InitList, ElementType, isStatic,
|
|
|
|
totalInits, hadError);
|
|
|
|
} else {
|
2007-09-04 22:36:54 +08:00
|
|
|
hadError = CheckInitExpr(expr, IList, i, isStatic, ElementType);
|
2007-09-04 10:20:04 +08:00
|
|
|
nInitsAtLevel++; // increment the number of initializers at this level.
|
|
|
|
totalInits--; // decrement the total number of initializers.
|
|
|
|
|
|
|
|
// Check if we have space for another initializer.
|
|
|
|
if ((nInitsAtLevel > maxElementsAtThisLevel) || (totalInits < 0))
|
|
|
|
Diag(expr->getLocStart(), diag::warn_excess_initializers,
|
|
|
|
expr->getSourceRange());
|
2007-09-02 23:34:30 +08:00
|
|
|
}
|
|
|
|
}
|
2007-09-04 10:20:04 +08:00
|
|
|
if (nInitsAtLevel < maxElementsAtThisLevel) // fill the remaining elements.
|
|
|
|
totalInits -= (maxElementsAtThisLevel - nInitsAtLevel);
|
|
|
|
} else {
|
|
|
|
// we have an initializer list with no elements.
|
|
|
|
totalInits -= maxElementsAtThisLevel;
|
|
|
|
if (totalInits < 0)
|
|
|
|
Diag(IList->getLocStart(), diag::warn_excess_initializers,
|
|
|
|
IList->getSourceRange());
|
2007-09-02 23:34:30 +08:00
|
|
|
}
|
2007-09-03 09:24:23 +08:00
|
|
|
return;
|
2007-09-02 23:34:30 +08:00
|
|
|
}
|
|
|
|
|
2007-09-04 22:36:54 +08:00
|
|
|
bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) {
|
2007-09-02 10:04:30 +08:00
|
|
|
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
|
2007-09-03 09:24:23 +08:00
|
|
|
if (!InitList)
|
2007-10-17 08:52:43 +08:00
|
|
|
return CheckSingleInitializer(Init, isStatic, DeclType);
|
|
|
|
|
2007-09-02 10:04:30 +08:00
|
|
|
// We have an InitListExpr, make sure we set the type.
|
|
|
|
Init->setType(DeclType);
|
2007-09-03 09:24:23 +08:00
|
|
|
|
|
|
|
bool hadError = false;
|
2007-09-02 23:34:30 +08:00
|
|
|
|
2007-09-03 04:30:18 +08:00
|
|
|
// C99 6.7.8p3: The type of the entity to be initialized shall be an array
|
|
|
|
// of unknown size ("[]") or an object type that is not a variable array type.
|
|
|
|
if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) {
|
|
|
|
Expr *expr = VAT->getSizeExpr();
|
2007-09-03 09:24:23 +08:00
|
|
|
if (expr)
|
|
|
|
return Diag(expr->getLocStart(), diag::err_variable_object_no_init,
|
|
|
|
expr->getSourceRange());
|
|
|
|
|
2007-09-05 05:13:33 +08:00
|
|
|
// We have a VariableArrayType with unknown size. Note that only the first
|
|
|
|
// array can have unknown size. For example, "int [][]" is illegal.
|
2007-09-04 10:20:04 +08:00
|
|
|
int numInits = 0;
|
2007-09-05 05:13:33 +08:00
|
|
|
CheckVariableInitList(VAT->getElementType(), InitList, VAT->getBaseType(),
|
|
|
|
isStatic, numInits, hadError);
|
2007-09-03 09:24:23 +08:00
|
|
|
if (!hadError) {
|
|
|
|
// Return a new array type from the number of initializers (C99 6.7.8p22).
|
|
|
|
llvm::APSInt ConstVal(32);
|
2007-09-04 10:20:04 +08:00
|
|
|
ConstVal = numInits;
|
2007-10-18 11:27:23 +08:00
|
|
|
DeclType = Context.getConstantArrayType(VAT->getElementType(), ConstVal,
|
2007-09-03 09:24:23 +08:00
|
|
|
ArrayType::Normal, 0);
|
2007-09-03 04:30:18 +08:00
|
|
|
}
|
2007-09-03 09:24:23 +08:00
|
|
|
return hadError;
|
2007-09-03 04:30:18 +08:00
|
|
|
}
|
2007-09-03 09:24:23 +08:00
|
|
|
if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) {
|
2007-09-05 05:13:33 +08:00
|
|
|
int maxElements = CAT->getMaximumElements();
|
|
|
|
CheckConstantInitList(DeclType, InitList, CAT->getBaseType(),
|
|
|
|
isStatic, maxElements, hadError);
|
2007-09-03 09:24:23 +08:00
|
|
|
return hadError;
|
|
|
|
}
|
2007-09-04 10:20:04 +08:00
|
|
|
if (DeclType->isScalarType()) { // C99 6.7.8p11: Allow "int x = { 1, 2 };"
|
|
|
|
int maxElements = 1;
|
|
|
|
CheckConstantInitList(DeclType, InitList, DeclType, isStatic, maxElements,
|
|
|
|
hadError);
|
2007-09-03 09:24:23 +08:00
|
|
|
return hadError;
|
2007-09-03 04:30:18 +08:00
|
|
|
}
|
|
|
|
// FIXME: Handle struct/union types.
|
2007-09-03 09:24:23 +08:00
|
|
|
return hadError;
|
2007-09-02 10:04:30 +08:00
|
|
|
}
|
|
|
|
|
2007-06-09 08:53:06 +08:00
|
|
|
Sema::DeclTy *
|
2007-09-16 02:49:24 +08:00
|
|
|
Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
2007-09-14 07:52:58 +08:00
|
|
|
ScopedDecl *LastDeclarator = dyn_cast_or_null<ScopedDecl>((Decl *)lastDecl);
|
2006-11-10 13:29:30 +08:00
|
|
|
IdentifierInfo *II = D.getIdentifier();
|
2006-11-19 10:31:38 +08:00
|
|
|
|
2007-07-25 08:24:17 +08:00
|
|
|
// All of these full declarators require an identifier. If it doesn't have
|
|
|
|
// one, the ParsedFreeStandingDeclSpec action should be used.
|
|
|
|
if (II == 0) {
|
2007-10-17 06:36:42 +08:00
|
|
|
Diag(D.getDeclSpec().getSourceRange().getBegin(),
|
2007-08-28 14:17:15 +08:00
|
|
|
diag::err_declarator_need_ident,
|
2007-07-25 08:24:17 +08:00
|
|
|
D.getDeclSpec().getSourceRange(), D.getSourceRange());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-26 14:24:45 +08:00
|
|
|
// The scope passed in may not be a decl scope. Zip up the scope tree until
|
|
|
|
// we find one that is.
|
|
|
|
while ((S->getFlags() & Scope::DeclScope) == 0)
|
|
|
|
S = S->getParent();
|
|
|
|
|
2007-01-28 03:27:06 +08:00
|
|
|
// See if this is a redefinition of a variable in the same scope.
|
2007-09-14 02:10:37 +08:00
|
|
|
ScopedDecl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary,
|
|
|
|
D.getIdentifierLoc(), S);
|
2007-06-09 08:53:06 +08:00
|
|
|
if (PrevDecl && !S->isDeclScope(PrevDecl))
|
2007-01-28 03:27:06 +08:00
|
|
|
PrevDecl = 0; // If in outer scope, it isn't the same thing.
|
|
|
|
|
2007-09-14 02:10:37 +08:00
|
|
|
ScopedDecl *New;
|
2007-08-29 04:14:24 +08:00
|
|
|
bool InvalidDecl = false;
|
|
|
|
|
2007-01-26 07:09:03 +08:00
|
|
|
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
2007-06-09 08:53:06 +08:00
|
|
|
TypedefDecl *NewTD = ParseTypedefDecl(S, D, LastDeclarator);
|
2007-01-28 03:27:06 +08:00
|
|
|
if (!NewTD) return 0;
|
2007-06-11 08:35:03 +08:00
|
|
|
|
|
|
|
// Handle attributes prior to checking for duplicates in MergeVarDecl
|
|
|
|
HandleDeclAttributes(NewTD, D.getDeclSpec().getAttributes(),
|
|
|
|
D.getAttributes());
|
2007-01-28 03:27:06 +08:00
|
|
|
// Merge the decl with the existing one if appropriate.
|
|
|
|
if (PrevDecl) {
|
|
|
|
NewTD = MergeTypeDefDecl(NewTD, PrevDecl);
|
|
|
|
if (NewTD == 0) return 0;
|
|
|
|
}
|
|
|
|
New = NewTD;
|
2007-05-09 05:09:37 +08:00
|
|
|
if (S->getParent() == 0) {
|
|
|
|
// C99 6.7.7p2: If a typedef name specifies a variably modified type
|
|
|
|
// then it shall have block scope.
|
2007-09-01 01:20:07 +08:00
|
|
|
if (const VariableArrayType *VAT =
|
|
|
|
NewTD->getUnderlyingType()->getAsVariablyModifiedType()) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_typecheck_illegal_vla,
|
|
|
|
VAT->getSizeExpr()->getSourceRange());
|
|
|
|
InvalidDecl = true;
|
2007-05-09 05:09:37 +08:00
|
|
|
}
|
|
|
|
}
|
2007-01-26 07:09:03 +08:00
|
|
|
} else if (D.isFunctionDeclarator()) {
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType R = GetTypeForDeclarator(D, S);
|
2007-08-29 04:14:24 +08:00
|
|
|
assert(!R.isNull() && "GetTypeForDeclarator() returned null type");
|
2007-07-14 00:58:59 +08:00
|
|
|
|
2007-09-27 23:15:46 +08:00
|
|
|
FunctionDecl::StorageClass SC = FunctionDecl::None;
|
2007-04-04 07:13:13 +08:00
|
|
|
switch (D.getDeclSpec().getStorageClassSpec()) {
|
|
|
|
default: assert(0 && "Unknown storage class!");
|
|
|
|
case DeclSpec::SCS_auto:
|
|
|
|
case DeclSpec::SCS_register:
|
2007-05-17 02:09:54 +08:00
|
|
|
Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func,
|
|
|
|
R.getAsString());
|
2007-08-29 04:14:24 +08:00
|
|
|
InvalidDecl = true;
|
|
|
|
break;
|
2007-04-04 07:13:13 +08:00
|
|
|
case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
|
|
|
|
case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break;
|
|
|
|
case DeclSpec::SCS_static: SC = FunctionDecl::Static; break;
|
|
|
|
}
|
|
|
|
|
2007-06-09 08:53:06 +08:00
|
|
|
FunctionDecl *NewFD = new FunctionDecl(D.getIdentifierLoc(), II, R, SC,
|
2007-08-26 12:02:13 +08:00
|
|
|
D.getDeclSpec().isInlineSpecified(),
|
2007-06-09 08:53:06 +08:00
|
|
|
LastDeclarator);
|
2007-01-28 03:27:06 +08:00
|
|
|
|
|
|
|
// Merge the decl with the existing one if appropriate.
|
|
|
|
if (PrevDecl) {
|
|
|
|
NewFD = MergeFunctionDecl(NewFD, PrevDecl);
|
|
|
|
if (NewFD == 0) return 0;
|
|
|
|
}
|
|
|
|
New = NewFD;
|
2007-01-26 07:09:03 +08:00
|
|
|
} else {
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType R = GetTypeForDeclarator(D, S);
|
2007-08-29 02:45:29 +08:00
|
|
|
assert(!R.isNull() && "GetTypeForDeclarator() returned null type");
|
2007-10-13 06:10:42 +08:00
|
|
|
if (R.getTypePtr()->isObjcInterfaceType()) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object,
|
|
|
|
D.getIdentifier()->getName());
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
2007-01-28 03:27:06 +08:00
|
|
|
|
2007-04-04 07:13:13 +08:00
|
|
|
VarDecl *NewVD;
|
|
|
|
VarDecl::StorageClass SC;
|
2007-03-16 08:33:25 +08:00
|
|
|
switch (D.getDeclSpec().getStorageClassSpec()) {
|
|
|
|
default: assert(0 && "Unknown storage class!");
|
2007-04-04 07:13:13 +08:00
|
|
|
case DeclSpec::SCS_unspecified: SC = VarDecl::None; break;
|
|
|
|
case DeclSpec::SCS_extern: SC = VarDecl::Extern; break;
|
|
|
|
case DeclSpec::SCS_static: SC = VarDecl::Static; break;
|
|
|
|
case DeclSpec::SCS_auto: SC = VarDecl::Auto; break;
|
|
|
|
case DeclSpec::SCS_register: SC = VarDecl::Register; break;
|
|
|
|
}
|
2007-04-02 05:27:45 +08:00
|
|
|
if (S->getParent() == 0) {
|
2007-06-02 17:40:07 +08:00
|
|
|
// C99 6.9p2: The storage-class specifiers auto and register shall not
|
|
|
|
// appear in the declaration specifiers in an external declaration.
|
2007-04-04 07:13:13 +08:00
|
|
|
if (SC == VarDecl::Auto || SC == VarDecl::Register) {
|
2007-05-17 02:09:54 +08:00
|
|
|
Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope,
|
|
|
|
R.getAsString());
|
2007-08-29 02:45:29 +08:00
|
|
|
InvalidDecl = true;
|
2007-04-04 07:13:13 +08:00
|
|
|
}
|
2007-06-09 08:53:06 +08:00
|
|
|
NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator);
|
2007-09-02 10:04:30 +08:00
|
|
|
} else {
|
2007-06-09 08:53:06 +08:00
|
|
|
NewVD = new BlockVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator);
|
2007-08-29 02:45:29 +08:00
|
|
|
}
|
2007-06-11 08:35:03 +08:00
|
|
|
// Handle attributes prior to checking for duplicates in MergeVarDecl
|
|
|
|
HandleDeclAttributes(NewVD, D.getDeclSpec().getAttributes(),
|
|
|
|
D.getAttributes());
|
|
|
|
|
2007-01-28 03:27:06 +08:00
|
|
|
// Merge the decl with the existing one if appropriate.
|
|
|
|
if (PrevDecl) {
|
|
|
|
NewVD = MergeVarDecl(NewVD, PrevDecl);
|
|
|
|
if (NewVD == 0) return 0;
|
|
|
|
}
|
|
|
|
New = NewVD;
|
2007-01-26 07:09:03 +08:00
|
|
|
}
|
2006-11-19 10:31:38 +08:00
|
|
|
|
2006-11-10 13:29:30 +08:00
|
|
|
// If this has an identifier, add it to the scope stack.
|
|
|
|
if (II) {
|
2007-09-14 02:10:37 +08:00
|
|
|
New->setNext(II->getFETokenInfo<ScopedDecl>());
|
2006-11-10 13:29:30 +08:00
|
|
|
II->setFETokenInfo(New);
|
2007-01-22 06:37:37 +08:00
|
|
|
S->AddDecl(New);
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2007-03-22 05:08:52 +08:00
|
|
|
if (S->getParent() == 0)
|
2007-06-09 08:53:06 +08:00
|
|
|
AddTopLevelDecl(New, LastDeclarator);
|
2007-08-29 04:14:24 +08:00
|
|
|
|
|
|
|
// If any semantic error occurred, mark the decl as invalid.
|
|
|
|
if (D.getInvalidType() || InvalidDecl)
|
|
|
|
New->setInvalidDecl();
|
2006-11-10 13:29:30 +08:00
|
|
|
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2007-09-12 22:07:44 +08:00
|
|
|
void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) {
|
2007-09-13 04:13:48 +08:00
|
|
|
Decl *RealDecl = static_cast<Decl *>(dcl);
|
2007-09-12 22:07:44 +08:00
|
|
|
Expr *Init = static_cast<Expr *>(init);
|
2007-10-20 04:10:30 +08:00
|
|
|
assert(Init && "missing initializer");
|
2007-09-12 22:07:44 +08:00
|
|
|
|
2007-10-20 04:10:30 +08:00
|
|
|
// If there is no declaration, there was an error parsing it. Just ignore
|
|
|
|
// the initializer.
|
|
|
|
if (RealDecl == 0) {
|
|
|
|
delete Init;
|
|
|
|
return;
|
|
|
|
}
|
2007-09-12 22:07:44 +08:00
|
|
|
|
2007-09-13 04:13:48 +08:00
|
|
|
VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
|
|
|
|
if (!VDecl) {
|
2007-09-14 05:41:19 +08:00
|
|
|
Diag(dyn_cast<ScopedDecl>(RealDecl)->getLocation(),
|
|
|
|
diag::err_illegal_initializer);
|
2007-09-13 04:13:48 +08:00
|
|
|
RealDecl->setInvalidDecl();
|
|
|
|
return;
|
|
|
|
}
|
2007-09-12 22:07:44 +08:00
|
|
|
// Get the decls type and save a reference for later, since
|
|
|
|
// CheckInitializer may change it.
|
2007-09-13 04:13:48 +08:00
|
|
|
QualType DclT = VDecl->getType(), SavT = DclT;
|
|
|
|
if (BlockVarDecl *BVD = dyn_cast<BlockVarDecl>(VDecl)) {
|
2007-09-12 22:07:44 +08:00
|
|
|
VarDecl::StorageClass SC = BVD->getStorageClass();
|
|
|
|
if (SC == VarDecl::Extern) { // C99 6.7.8p5
|
2007-09-13 04:13:48 +08:00
|
|
|
Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
|
2007-09-12 22:07:44 +08:00
|
|
|
BVD->setInvalidDecl();
|
|
|
|
} else if (!BVD->isInvalidDecl()) {
|
|
|
|
CheckInitializer(Init, DclT, SC == VarDecl::Static);
|
|
|
|
}
|
2007-09-13 04:13:48 +08:00
|
|
|
} else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(VDecl)) {
|
2007-09-12 22:07:44 +08:00
|
|
|
if (FVD->getStorageClass() == VarDecl::Extern)
|
2007-09-13 04:13:48 +08:00
|
|
|
Diag(VDecl->getLocation(), diag::warn_extern_init);
|
2007-09-12 22:07:44 +08:00
|
|
|
if (!FVD->isInvalidDecl())
|
|
|
|
CheckInitializer(Init, DclT, true);
|
|
|
|
}
|
|
|
|
// If the type changed, it means we had an incomplete type that was
|
|
|
|
// completed by the initializer. For example:
|
|
|
|
// int ary[] = { 1, 3, 5 };
|
|
|
|
// "ary" transitions from a VariableArrayType to a ConstantArrayType.
|
2007-09-13 04:13:48 +08:00
|
|
|
if (!VDecl->isInvalidDecl() && (DclT != SavT))
|
|
|
|
VDecl->setType(DclT);
|
2007-09-12 22:07:44 +08:00
|
|
|
|
|
|
|
// Attach the initializer to the decl.
|
2007-09-13 04:13:48 +08:00
|
|
|
VDecl->setInit(Init);
|
2007-09-12 22:07:44 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-06-09 08:53:06 +08:00
|
|
|
/// The declarators are chained together backwards, reverse the list.
|
|
|
|
Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) {
|
|
|
|
// Often we have single declarators, handle them quickly.
|
2007-09-14 07:52:58 +08:00
|
|
|
Decl *GroupDecl = static_cast<Decl*>(group);
|
|
|
|
if (GroupDecl == 0)
|
2007-09-12 22:07:44 +08:00
|
|
|
return 0;
|
2007-09-14 07:52:58 +08:00
|
|
|
|
|
|
|
ScopedDecl *Group = dyn_cast<ScopedDecl>(GroupDecl);
|
|
|
|
ScopedDecl *NewGroup = 0;
|
2007-09-12 22:07:44 +08:00
|
|
|
if (Group->getNextDeclarator() == 0)
|
2007-06-09 08:53:06 +08:00
|
|
|
NewGroup = Group;
|
2007-09-12 22:07:44 +08:00
|
|
|
else { // reverse the list.
|
|
|
|
while (Group) {
|
2007-09-14 07:52:58 +08:00
|
|
|
ScopedDecl *Next = Group->getNextDeclarator();
|
2007-09-12 22:07:44 +08:00
|
|
|
Group->setNextDeclarator(NewGroup);
|
|
|
|
NewGroup = Group;
|
|
|
|
Group = Next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Perform semantic analysis that depends on having fully processed both
|
|
|
|
// the declarator and initializer.
|
2007-09-14 07:52:58 +08:00
|
|
|
for (ScopedDecl *ID = NewGroup; ID; ID = ID->getNextDeclarator()) {
|
2007-09-12 22:07:44 +08:00
|
|
|
VarDecl *IDecl = dyn_cast<VarDecl>(ID);
|
|
|
|
if (!IDecl)
|
|
|
|
continue;
|
|
|
|
FileVarDecl *FVD = dyn_cast<FileVarDecl>(IDecl);
|
|
|
|
BlockVarDecl *BVD = dyn_cast<BlockVarDecl>(IDecl);
|
|
|
|
QualType T = IDecl->getType();
|
|
|
|
|
|
|
|
// C99 6.7.5.2p2: If an identifier is declared to be an object with
|
|
|
|
// static storage duration, it shall not have a variable length array.
|
|
|
|
if ((FVD || BVD) && IDecl->getStorageClass() == VarDecl::Static) {
|
|
|
|
if (const VariableArrayType *VLA = T->getAsVariableArrayType()) {
|
|
|
|
if (VLA->getSizeExpr()) {
|
|
|
|
Diag(IDecl->getLocation(), diag::err_typecheck_illegal_vla);
|
|
|
|
IDecl->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Block scope. C99 6.7p7: If an identifier for an object is declared with
|
|
|
|
// no linkage (C99 6.2.2p6), the type for the object shall be complete...
|
|
|
|
if (BVD && IDecl->getStorageClass() != VarDecl::Extern) {
|
|
|
|
if (T->isIncompleteType()) {
|
|
|
|
Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type,
|
|
|
|
T.getAsString());
|
|
|
|
IDecl->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// File scope. C99 6.9.2p2: A declaration of an identifier for and
|
|
|
|
// object that has file scope without an initializer, and without a
|
|
|
|
// storage-class specifier or with the storage-class specifier "static",
|
|
|
|
// constitutes a tentative definition. Note: A tentative definition with
|
|
|
|
// external linkage is valid (C99 6.2.2p5).
|
|
|
|
if (FVD && !FVD->getInit() && FVD->getStorageClass() == VarDecl::Static) {
|
|
|
|
// C99 6.9.2p3: If the declaration of an identifier for an object is
|
|
|
|
// a tentative definition and has internal linkage (C99 6.2.2p3), the
|
|
|
|
// declared type shall not be an incomplete type.
|
|
|
|
if (T->isIncompleteType()) {
|
|
|
|
Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type,
|
|
|
|
T.getAsString());
|
|
|
|
IDecl->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
2007-06-09 08:53:06 +08:00
|
|
|
}
|
|
|
|
return NewGroup;
|
|
|
|
}
|
2007-08-28 11:03:08 +08:00
|
|
|
|
|
|
|
// Called from Sema::ParseStartOfFunctionDef().
|
2007-06-14 04:44:40 +08:00
|
|
|
ParmVarDecl *
|
2007-01-21 15:42:07 +08:00
|
|
|
Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo,
|
|
|
|
Scope *FnScope) {
|
|
|
|
const DeclaratorChunk::ParamInfo &PI = FTI.Fun.ArgInfo[ArgNo];
|
2006-11-19 10:43:37 +08:00
|
|
|
|
2007-01-21 15:42:07 +08:00
|
|
|
IdentifierInfo *II = PI.Ident;
|
2007-01-23 13:14:32 +08:00
|
|
|
// TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
|
|
|
|
// Can this happen for params? We already checked that they don't conflict
|
|
|
|
// among each other. Here they can only shadow globals, which is ok.
|
2007-07-13 11:05:23 +08:00
|
|
|
if (/*Decl *PrevDecl = */LookupScopedDecl(II, Decl::IDNS_Ordinary,
|
2007-01-28 16:20:04 +08:00
|
|
|
PI.IdentLoc, FnScope)) {
|
2007-01-21 15:42:07 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-03-16 08:33:25 +08:00
|
|
|
// FIXME: Handle storage class (auto, register). No declarator?
|
2007-06-09 08:53:06 +08:00
|
|
|
// TODO: Chain to previous parameter with the prevdeclarator chain?
|
2007-08-08 06:44:21 +08:00
|
|
|
|
|
|
|
// Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
|
|
|
|
// Doing the promotion here has a win and a loss. The win is the type for
|
|
|
|
// both Decl's and DeclRefExpr's will match (a convenient invariant for the
|
|
|
|
// code generator). The loss is the orginal type isn't preserved. For example:
|
|
|
|
//
|
|
|
|
// void func(int parmvardecl[5]) { // convert "int [5]" to "int *"
|
|
|
|
// int blockvardecl[5];
|
|
|
|
// sizeof(parmvardecl); // size == 4
|
|
|
|
// sizeof(blockvardecl); // size == 20
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// For expressions, all implicit conversions are captured using the
|
|
|
|
// ImplicitCastExpr AST node (we have no such mechanism for Decl's).
|
|
|
|
//
|
|
|
|
// FIXME: If a source translation tool needs to see the original type, then
|
|
|
|
// we need to consider storing both types (in ParmVarDecl)...
|
|
|
|
//
|
|
|
|
QualType parmDeclType = QualType::getFromOpaquePtr(PI.TypeInfo);
|
|
|
|
if (const ArrayType *AT = parmDeclType->getAsArrayType())
|
|
|
|
parmDeclType = Context.getPointerType(AT->getElementType());
|
|
|
|
else if (parmDeclType->isFunctionType())
|
|
|
|
parmDeclType = Context.getPointerType(parmDeclType);
|
|
|
|
|
|
|
|
ParmVarDecl *New = new ParmVarDecl(PI.IdentLoc, II, parmDeclType,
|
2007-08-29 02:45:29 +08:00
|
|
|
VarDecl::None, 0);
|
|
|
|
if (PI.InvalidType)
|
|
|
|
New->setInvalidDecl();
|
|
|
|
|
2007-01-21 15:42:07 +08:00
|
|
|
// If this has an identifier, add it to the scope stack.
|
|
|
|
if (II) {
|
2007-09-14 02:10:37 +08:00
|
|
|
New->setNext(II->getFETokenInfo<ScopedDecl>());
|
2007-01-21 15:42:07 +08:00
|
|
|
II->setFETokenInfo(New);
|
2007-01-22 06:37:37 +08:00
|
|
|
FnScope->AddDecl(New);
|
2007-01-21 15:42:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2006-11-21 09:21:07 +08:00
|
|
|
|
2007-10-10 01:14:05 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
|
2006-11-21 09:21:07 +08:00
|
|
|
assert(CurFunctionDecl == 0 && "Function parsing confused");
|
2006-12-03 16:41:30 +08:00
|
|
|
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
|
|
|
|
"Not a function declarator!");
|
|
|
|
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
|
|
|
|
|
|
|
|
// Verify 6.9.1p6: 'every identifier in the identifier list shall be declared'
|
|
|
|
// for a K&R function.
|
|
|
|
if (!FTI.hasPrototype) {
|
|
|
|
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
|
|
|
|
if (FTI.ArgInfo[i].TypeInfo == 0) {
|
2007-06-11 07:40:34 +08:00
|
|
|
Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared,
|
2006-12-03 16:41:30 +08:00
|
|
|
FTI.ArgInfo[i].Ident->getName());
|
|
|
|
// Implicitly declare the argument as type 'int' for lack of a better
|
|
|
|
// type.
|
|
|
|
FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since this is a function definition, act as though we have information
|
|
|
|
// about the arguments.
|
|
|
|
FTI.hasPrototype = true;
|
2006-12-04 15:40:24 +08:00
|
|
|
} else {
|
|
|
|
// FIXME: Diagnose arguments without names in C.
|
|
|
|
|
2006-12-03 16:41:30 +08:00
|
|
|
}
|
|
|
|
|
2007-01-21 15:42:07 +08:00
|
|
|
Scope *GlobalScope = FnBodyScope->getParent();
|
2006-12-04 15:40:24 +08:00
|
|
|
|
2007-01-21 15:42:07 +08:00
|
|
|
FunctionDecl *FD =
|
2007-09-16 02:49:24 +08:00
|
|
|
static_cast<FunctionDecl*>(ActOnDeclarator(GlobalScope, D, 0));
|
2007-01-21 15:42:07 +08:00
|
|
|
CurFunctionDecl = FD;
|
2006-12-04 15:40:24 +08:00
|
|
|
|
2007-01-21 15:42:07 +08:00
|
|
|
// Create Decl objects for each parameter, adding them to the FunctionDecl.
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<ParmVarDecl*, 16> Params;
|
2007-01-22 03:04:43 +08:00
|
|
|
|
|
|
|
// Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes
|
|
|
|
// no arguments, not a function that takes a single void argument.
|
|
|
|
if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
|
|
|
|
FTI.ArgInfo[0].TypeInfo == Context.VoidTy.getAsOpaquePtr()) {
|
2007-01-22 06:37:37 +08:00
|
|
|
// empty arg list, don't push any params.
|
2007-01-22 03:04:43 +08:00
|
|
|
} else {
|
|
|
|
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
|
|
|
|
Params.push_back(ParseParamDeclarator(D.getTypeObject(0), i,FnBodyScope));
|
|
|
|
}
|
2006-12-04 15:40:24 +08:00
|
|
|
|
2007-01-21 15:42:07 +08:00
|
|
|
FD->setParams(&Params[0], Params.size());
|
2006-12-04 15:40:24 +08:00
|
|
|
|
2006-11-21 09:21:07 +08:00
|
|
|
return FD;
|
|
|
|
}
|
|
|
|
|
2007-10-10 01:14:05 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnFunctionDefBody(DeclTy *D, StmtTy *Body) {
|
2006-11-21 09:21:07 +08:00
|
|
|
FunctionDecl *FD = static_cast<FunctionDecl*>(D);
|
2006-11-10 13:29:30 +08:00
|
|
|
FD->setBody((Stmt*)Body);
|
|
|
|
|
2006-11-21 09:21:07 +08:00
|
|
|
assert(FD == CurFunctionDecl && "Function parsing confused");
|
|
|
|
CurFunctionDecl = 0;
|
2007-05-28 14:28:18 +08:00
|
|
|
|
|
|
|
// Verify and clean out per-function state.
|
|
|
|
|
|
|
|
// Check goto/label use.
|
2007-06-16 07:05:46 +08:00
|
|
|
for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
|
|
|
|
I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) {
|
2007-05-28 14:28:18 +08:00
|
|
|
// Verify that we have no forward references left. If so, there was a goto
|
|
|
|
// or address of a label taken, but no definition of it. Label fwd
|
|
|
|
// definitions are indicated with a null substmt.
|
|
|
|
if (I->second->getSubStmt() == 0) {
|
|
|
|
LabelStmt *L = I->second;
|
|
|
|
// Emit error.
|
2007-05-28 14:56:27 +08:00
|
|
|
Diag(L->getIdentLoc(), diag::err_undeclared_label_use, L->getName());
|
2007-05-28 14:28:18 +08:00
|
|
|
|
|
|
|
// At this point, we have gotos that use the bogus label. Stitch it into
|
|
|
|
// the function body so that they aren't leaked and that the AST is well
|
|
|
|
// formed.
|
|
|
|
L->setSubStmt(new NullStmt(L->getIdentLoc()));
|
|
|
|
cast<CompoundStmt>((Stmt*)Body)->push_back(L);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LabelMap.clear();
|
|
|
|
|
2006-11-10 13:29:30 +08:00
|
|
|
return FD;
|
|
|
|
}
|
|
|
|
|
2006-11-21 09:21:07 +08:00
|
|
|
|
2006-11-20 14:49:47 +08:00
|
|
|
/// ImplicitlyDefineFunction - An undeclared identifier was used in a function
|
|
|
|
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
|
2007-09-17 00:16:00 +08:00
|
|
|
ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
|
|
|
|
IdentifierInfo &II, Scope *S) {
|
2006-11-20 14:49:47 +08:00
|
|
|
if (getLangOptions().C99) // Extension in C99.
|
|
|
|
Diag(Loc, diag::ext_implicit_function_decl, II.getName());
|
|
|
|
else // Legal in C90, but warn about it.
|
|
|
|
Diag(Loc, diag::warn_implicit_function_decl, II.getName());
|
|
|
|
|
|
|
|
// FIXME: handle stuff like:
|
|
|
|
// void foo() { extern float X(); }
|
|
|
|
// void bar() { X(); } <-- implicit decl for X in another scope.
|
|
|
|
|
|
|
|
// Set a Declarator for the implicit definition: int foo();
|
2006-11-28 12:50:12 +08:00
|
|
|
const char *Dummy;
|
2006-11-20 14:49:47 +08:00
|
|
|
DeclSpec DS;
|
2006-11-28 13:30:29 +08:00
|
|
|
bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy);
|
2007-02-11 16:19:57 +08:00
|
|
|
Error = Error; // Silence warning.
|
2006-11-28 12:50:12 +08:00
|
|
|
assert(!Error && "Error setting up implicit decl!");
|
2006-11-20 14:49:47 +08:00
|
|
|
Declarator D(DS, Declarator::BlockContext);
|
2006-12-02 14:43:02 +08:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, Loc));
|
2006-11-20 14:49:47 +08:00
|
|
|
D.SetIdentifier(&II, Loc);
|
|
|
|
|
2007-01-28 08:21:37 +08:00
|
|
|
// Find translation-unit scope to insert this function into.
|
2007-08-26 14:24:45 +08:00
|
|
|
if (Scope *FnS = S->getFnParent())
|
|
|
|
S = FnS->getParent(); // Skip all scopes in a function at once.
|
2007-01-28 08:21:37 +08:00
|
|
|
while (S->getParent())
|
|
|
|
S = S->getParent();
|
2006-11-20 14:49:47 +08:00
|
|
|
|
2007-09-17 00:16:00 +08:00
|
|
|
return dyn_cast<ScopedDecl>(static_cast<Decl*>(ActOnDeclarator(S, D, 0)));
|
2006-11-20 14:49:47 +08:00
|
|
|
}
|
|
|
|
|
2006-11-19 10:31:38 +08:00
|
|
|
|
2007-06-09 08:53:06 +08:00
|
|
|
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D,
|
2007-09-14 07:52:58 +08:00
|
|
|
ScopedDecl *LastDeclarator) {
|
2007-06-09 08:53:06 +08:00
|
|
|
assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
|
2006-11-19 10:31:38 +08:00
|
|
|
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType T = GetTypeForDeclarator(D, S);
|
2007-08-29 04:14:24 +08:00
|
|
|
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
2006-11-20 12:34:45 +08:00
|
|
|
|
2007-01-22 15:39:13 +08:00
|
|
|
// Scope manipulation handled by caller.
|
2007-08-29 04:14:24 +08:00
|
|
|
TypedefDecl *NewTD = new TypedefDecl(D.getIdentifierLoc(), D.getIdentifier(),
|
|
|
|
T, LastDeclarator);
|
|
|
|
if (D.getInvalidType())
|
|
|
|
NewTD->setInvalidDecl();
|
|
|
|
return NewTD;
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnStartClassInterface(
|
2007-09-26 02:38:09 +08:00
|
|
|
SourceLocation AtInterfaceLoc,
|
2007-09-07 05:24:23 +08:00
|
|
|
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
|
|
|
IdentifierInfo *SuperName, SourceLocation SuperLoc,
|
|
|
|
IdentifierInfo **ProtocolNames, unsigned NumProtocols,
|
2007-10-30 10:23:23 +08:00
|
|
|
SourceLocation EndProtoLoc, AttributeList *AttrList) {
|
2007-09-07 05:24:23 +08:00
|
|
|
assert(ClassName && "Missing class identifier");
|
2007-09-26 02:38:09 +08:00
|
|
|
|
|
|
|
// Check for another declaration kind with the same name.
|
2007-10-13 03:38:20 +08:00
|
|
|
ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName);
|
2007-10-10 02:03:53 +08:00
|
|
|
if (PrevDecl && !isa<ObjcInterfaceDecl>(PrevDecl)) {
|
2007-09-26 02:38:09 +08:00
|
|
|
Diag(ClassLoc, diag::err_redefinition_different_kind,
|
|
|
|
ClassName->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
|
2007-10-13 03:38:20 +08:00
|
|
|
ObjcInterfaceDecl* IDecl = dyn_cast_or_null<ObjcInterfaceDecl>(PrevDecl);
|
2007-09-21 04:26:44 +08:00
|
|
|
if (IDecl) {
|
|
|
|
// Class already seen. Is it a forward declaration?
|
2007-10-03 04:26:23 +08:00
|
|
|
if (!IDecl->isForwardDecl())
|
2007-10-13 03:38:20 +08:00
|
|
|
Diag(AtInterfaceLoc, diag::err_duplicate_class_def, IDecl->getName());
|
2007-09-22 08:01:35 +08:00
|
|
|
else {
|
2007-10-30 10:23:23 +08:00
|
|
|
IDecl->setLocation(AtInterfaceLoc);
|
2007-10-03 04:26:23 +08:00
|
|
|
IDecl->setForwardDecl(false);
|
2007-09-22 08:01:35 +08:00
|
|
|
IDecl->AllocIntfRefProtocols(NumProtocols);
|
|
|
|
}
|
2007-09-21 04:26:44 +08:00
|
|
|
}
|
|
|
|
else {
|
2007-09-22 08:01:35 +08:00
|
|
|
IDecl = new ObjcInterfaceDecl(AtInterfaceLoc, NumProtocols, ClassName);
|
2007-09-07 05:24:23 +08:00
|
|
|
|
2007-09-21 04:26:44 +08:00
|
|
|
// Chain & install the interface decl into the identifier.
|
|
|
|
IDecl->setNext(ClassName->getFETokenInfo<ScopedDecl>());
|
|
|
|
ClassName->setFETokenInfo(IDecl);
|
2007-10-16 03:16:57 +08:00
|
|
|
|
|
|
|
// Remember that this needs to be removed when the scope is popped.
|
|
|
|
TUScope->AddDecl(IDecl);
|
2007-09-21 04:26:44 +08:00
|
|
|
}
|
2007-09-21 01:54:07 +08:00
|
|
|
|
|
|
|
if (SuperName) {
|
2007-09-26 02:38:09 +08:00
|
|
|
ObjcInterfaceDecl* SuperClassEntry = 0;
|
|
|
|
// Check if a different kind of symbol declared in this scope.
|
2007-10-13 03:38:20 +08:00
|
|
|
PrevDecl = LookupInterfaceDecl(SuperName);
|
2007-10-10 02:03:53 +08:00
|
|
|
if (PrevDecl && !isa<ObjcInterfaceDecl>(PrevDecl)) {
|
2007-09-26 02:38:09 +08:00
|
|
|
Diag(SuperLoc, diag::err_redefinition_different_kind,
|
|
|
|
SuperName->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Check that super class is previously defined
|
2007-10-13 03:38:20 +08:00
|
|
|
SuperClassEntry = dyn_cast_or_null<ObjcInterfaceDecl>(PrevDecl);
|
2007-09-21 01:54:07 +08:00
|
|
|
|
2007-10-03 04:26:23 +08:00
|
|
|
if (!SuperClassEntry || SuperClassEntry->isForwardDecl()) {
|
2007-10-13 03:38:20 +08:00
|
|
|
Diag(AtInterfaceLoc, diag::err_undef_superclass,
|
|
|
|
SuperClassEntry ? SuperClassEntry->getName()
|
|
|
|
: SuperName->getName(),
|
2007-09-26 02:38:09 +08:00
|
|
|
ClassName->getName());
|
|
|
|
}
|
2007-09-21 01:54:07 +08:00
|
|
|
}
|
2007-09-26 02:38:09 +08:00
|
|
|
IDecl->setSuperClass(SuperClassEntry);
|
2007-10-30 10:23:23 +08:00
|
|
|
IDecl->setLocEnd(SuperLoc);
|
|
|
|
} else { // we have a root class.
|
|
|
|
IDecl->setLocEnd(ClassLoc);
|
2007-09-22 08:01:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Check then save referenced protocols
|
2007-10-30 10:23:23 +08:00
|
|
|
if (NumProtocols) {
|
|
|
|
for (unsigned int i = 0; i != NumProtocols; i++) {
|
|
|
|
ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtocolNames[i]];
|
|
|
|
if (!RefPDecl || RefPDecl->isForwardDecl())
|
|
|
|
Diag(ClassLoc, diag::err_undef_protocolref,
|
|
|
|
ProtocolNames[i]->getName(),
|
|
|
|
ClassName->getName());
|
|
|
|
IDecl->setIntfRefProtocols((int)i, RefPDecl);
|
|
|
|
}
|
|
|
|
IDecl->setLocEnd(EndProtoLoc);
|
2007-09-21 01:54:07 +08:00
|
|
|
}
|
2007-09-07 05:24:23 +08:00
|
|
|
return IDecl;
|
|
|
|
}
|
|
|
|
|
2007-10-12 07:42:27 +08:00
|
|
|
/// ActOnCompatiblityAlias - this action is called after complete parsing of
|
|
|
|
/// @compaatibility_alias declaration. It sets up the alias relationships.
|
|
|
|
Sema::DeclTy *Sema::ActOnCompatiblityAlias(
|
|
|
|
SourceLocation AtCompatibilityAliasLoc,
|
|
|
|
IdentifierInfo *AliasName, SourceLocation AliasLocation,
|
|
|
|
IdentifierInfo *ClassName, SourceLocation ClassLocation) {
|
|
|
|
// Look for previous declaration of alias name
|
|
|
|
ScopedDecl *ADecl = LookupScopedDecl(AliasName, Decl::IDNS_Ordinary,
|
|
|
|
AliasLocation, TUScope);
|
|
|
|
if (ADecl) {
|
|
|
|
if (isa<ObjcCompatibleAliasDecl>(ADecl)) {
|
|
|
|
Diag(AliasLocation, diag::warn_previous_alias_decl);
|
|
|
|
Diag(ADecl->getLocation(), diag::warn_previous_declaration);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Diag(AliasLocation, diag::err_conflicting_aliasing_type,
|
|
|
|
AliasName->getName());
|
|
|
|
Diag(ADecl->getLocation(), diag::err_previous_declaration);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// Check for class declaration
|
|
|
|
ScopedDecl *CDecl = LookupScopedDecl(ClassName, Decl::IDNS_Ordinary,
|
|
|
|
ClassLocation, TUScope);
|
|
|
|
if (!CDecl || !isa<ObjcInterfaceDecl>(CDecl)) {
|
|
|
|
Diag(ClassLocation, diag::warn_undef_interface,
|
|
|
|
ClassName->getName());
|
|
|
|
if (CDecl)
|
|
|
|
Diag(CDecl->getLocation(), diag::warn_previous_declaration);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// Everything checked out, instantiate a new alias declaration ast
|
|
|
|
ObjcCompatibleAliasDecl *AliasDecl =
|
|
|
|
new ObjcCompatibleAliasDecl(AtCompatibilityAliasLoc,
|
|
|
|
AliasName,
|
|
|
|
dyn_cast<ObjcInterfaceDecl>(CDecl));
|
|
|
|
|
|
|
|
// Chain & install the interface decl into the identifier.
|
|
|
|
AliasDecl->setNext(AliasName->getFETokenInfo<ScopedDecl>());
|
|
|
|
AliasName->setFETokenInfo(AliasDecl);
|
|
|
|
return AliasDecl;
|
|
|
|
}
|
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnStartProtocolInterface(
|
2007-10-04 08:45:27 +08:00
|
|
|
SourceLocation AtProtoInterfaceLoc,
|
2007-09-18 05:07:36 +08:00
|
|
|
IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
|
2007-10-30 10:23:23 +08:00
|
|
|
IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs,
|
|
|
|
SourceLocation EndProtoLoc) {
|
2007-09-18 05:07:36 +08:00
|
|
|
assert(ProtocolName && "Missing protocol identifier");
|
2007-10-10 02:03:53 +08:00
|
|
|
ObjcProtocolDecl *PDecl = ObjcProtocols[ProtocolName];
|
2007-09-21 23:40:54 +08:00
|
|
|
if (PDecl) {
|
|
|
|
// Protocol already seen. Better be a forward protocol declaration
|
2007-10-03 04:26:23 +08:00
|
|
|
if (!PDecl->isForwardDecl())
|
2007-09-21 23:40:54 +08:00
|
|
|
Diag(ProtocolLoc, diag::err_duplicate_protocol_def,
|
|
|
|
ProtocolName->getName());
|
|
|
|
else {
|
2007-10-03 04:26:23 +08:00
|
|
|
PDecl->setForwardDecl(false);
|
2007-09-21 23:40:54 +08:00
|
|
|
PDecl->AllocReferencedProtocols(NumProtoRefs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PDecl = new ObjcProtocolDecl(AtProtoInterfaceLoc, NumProtoRefs,
|
|
|
|
ProtocolName);
|
2007-10-10 02:03:53 +08:00
|
|
|
ObjcProtocols[ProtocolName] = PDecl;
|
2007-09-21 23:40:54 +08:00
|
|
|
}
|
|
|
|
|
2007-10-30 21:30:57 +08:00
|
|
|
if (NumProtoRefs) {
|
|
|
|
/// Check then save referenced protocols
|
|
|
|
for (unsigned int i = 0; i != NumProtoRefs; i++) {
|
|
|
|
ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtoRefNames[i]];
|
|
|
|
if (!RefPDecl || RefPDecl->isForwardDecl())
|
|
|
|
Diag(ProtocolLoc, diag::err_undef_protocolref,
|
|
|
|
ProtoRefNames[i]->getName(),
|
|
|
|
ProtocolName->getName());
|
|
|
|
PDecl->setReferencedProtocols((int)i, RefPDecl);
|
|
|
|
}
|
|
|
|
PDecl->setLocEnd(EndProtoLoc);
|
2007-09-21 23:40:54 +08:00
|
|
|
}
|
2007-09-18 05:07:36 +08:00
|
|
|
return PDecl;
|
|
|
|
}
|
|
|
|
|
2007-10-11 08:55:41 +08:00
|
|
|
/// FindProtocolDeclaration - This routine looks up protocols and
|
|
|
|
/// issuer error if they are not declared. It returns list of protocol
|
|
|
|
/// declarations in its 'Protocols' argument.
|
|
|
|
void
|
|
|
|
Sema::FindProtocolDeclaration(SourceLocation TypeLoc,
|
|
|
|
IdentifierInfo **ProtocolId,
|
|
|
|
unsigned NumProtocols,
|
|
|
|
llvm::SmallVector<DeclTy *,8> &Protocols) {
|
2007-10-06 05:01:53 +08:00
|
|
|
for (unsigned i = 0; i != NumProtocols; ++i) {
|
2007-10-10 02:03:53 +08:00
|
|
|
ObjcProtocolDecl *PDecl = ObjcProtocols[ProtocolId[i]];
|
2007-10-06 05:01:53 +08:00
|
|
|
if (!PDecl)
|
|
|
|
Diag(TypeLoc, diag::err_undeclared_protocol,
|
|
|
|
ProtocolId[i]->getName());
|
2007-10-11 08:55:41 +08:00
|
|
|
else
|
|
|
|
Protocols.push_back(PDecl);
|
2007-10-06 05:01:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-03 06:39:18 +08:00
|
|
|
/// ActOnForwardProtocolDeclaration -
|
2007-09-21 23:40:54 +08:00
|
|
|
Action::DeclTy *
|
2007-10-11 01:32:04 +08:00
|
|
|
Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
|
2007-09-21 23:40:54 +08:00
|
|
|
IdentifierInfo **IdentList, unsigned NumElts) {
|
2007-10-07 04:05:59 +08:00
|
|
|
llvm::SmallVector<ObjcProtocolDecl*, 32> Protocols;
|
2007-09-21 23:40:54 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0; i != NumElts; ++i) {
|
2007-10-07 15:05:08 +08:00
|
|
|
IdentifierInfo *P = IdentList[i];
|
2007-10-10 02:03:53 +08:00
|
|
|
ObjcProtocolDecl *PDecl = ObjcProtocols[P];
|
2007-10-07 15:05:08 +08:00
|
|
|
if (!PDecl) { // Not already seen?
|
|
|
|
// FIXME: Pass in the location of the identifier!
|
|
|
|
PDecl = new ObjcProtocolDecl(AtProtocolLoc, 0, P, true);
|
2007-10-10 02:03:53 +08:00
|
|
|
ObjcProtocols[P] = PDecl;
|
2007-09-21 23:40:54 +08:00
|
|
|
}
|
|
|
|
|
2007-10-07 04:05:59 +08:00
|
|
|
Protocols.push_back(PDecl);
|
2007-09-21 23:40:54 +08:00
|
|
|
}
|
2007-10-07 04:05:59 +08:00
|
|
|
return new ObjcForwardProtocolDecl(AtProtocolLoc,
|
|
|
|
&Protocols[0], Protocols.size());
|
2007-09-21 23:40:54 +08:00
|
|
|
}
|
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnStartCategoryInterface(
|
2007-10-04 08:45:27 +08:00
|
|
|
SourceLocation AtInterfaceLoc,
|
2007-09-19 04:26:58 +08:00
|
|
|
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
|
|
|
IdentifierInfo *CategoryName, SourceLocation CategoryLoc,
|
2007-10-30 21:30:57 +08:00
|
|
|
IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs,
|
|
|
|
SourceLocation EndProtoLoc) {
|
2007-10-07 06:53:46 +08:00
|
|
|
ObjcInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
|
2007-10-10 01:05:22 +08:00
|
|
|
|
2007-09-22 08:01:35 +08:00
|
|
|
/// Check that class of this category is already completely declared.
|
2007-10-09 00:07:03 +08:00
|
|
|
if (!IDecl || IDecl->isForwardDecl()) {
|
2007-09-22 08:01:35 +08:00
|
|
|
Diag(ClassLoc, diag::err_undef_interface, ClassName->getName());
|
2007-10-10 01:05:22 +08:00
|
|
|
return 0;
|
2007-10-09 00:07:03 +08:00
|
|
|
}
|
2007-10-10 02:22:59 +08:00
|
|
|
ObjcCategoryDecl *CDecl = new ObjcCategoryDecl(AtInterfaceLoc, NumProtoRefs,
|
|
|
|
CategoryName);
|
|
|
|
CDecl->setClassInterface(IDecl);
|
|
|
|
/// Check for duplicate interface declaration for this category
|
|
|
|
ObjcCategoryDecl *CDeclChain;
|
2007-10-15 02:27:41 +08:00
|
|
|
for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
|
2007-10-10 02:22:59 +08:00
|
|
|
CDeclChain = CDeclChain->getNextClassCategory()) {
|
|
|
|
if (CDeclChain->getIdentifier() == CategoryName) {
|
|
|
|
Diag(CategoryLoc, diag::err_dup_category_def, ClassName->getName(),
|
|
|
|
CategoryName->getName());
|
|
|
|
break;
|
2007-09-22 08:01:35 +08:00
|
|
|
}
|
|
|
|
}
|
2007-10-10 02:22:59 +08:00
|
|
|
if (!CDeclChain)
|
|
|
|
CDecl->insertNextClassCategory();
|
|
|
|
|
2007-10-30 21:30:57 +08:00
|
|
|
if (NumProtoRefs) {
|
|
|
|
/// Check then save referenced protocols
|
|
|
|
for (unsigned int i = 0; i != NumProtoRefs; i++) {
|
|
|
|
ObjcProtocolDecl* RefPDecl = ObjcProtocols[ProtoRefNames[i]];
|
|
|
|
if (!RefPDecl || RefPDecl->isForwardDecl()) {
|
|
|
|
Diag(CategoryLoc, diag::err_undef_protocolref,
|
|
|
|
ProtoRefNames[i]->getName(),
|
|
|
|
CategoryName->getName());
|
|
|
|
}
|
|
|
|
CDecl->setCatReferencedProtocols((int)i, RefPDecl);
|
2007-10-09 00:07:03 +08:00
|
|
|
}
|
2007-10-30 21:30:57 +08:00
|
|
|
CDecl->setLocEnd(EndProtoLoc);
|
2007-09-22 08:01:35 +08:00
|
|
|
}
|
2007-10-10 01:05:22 +08:00
|
|
|
return CDecl;
|
2007-09-19 04:26:58 +08:00
|
|
|
}
|
2007-09-21 04:26:44 +08:00
|
|
|
|
2007-10-04 05:00:46 +08:00
|
|
|
/// ActOnStartCategoryImplementation - Perform semantic checks on the
|
2007-10-03 00:38:50 +08:00
|
|
|
/// category implementation declaration and build an ObjcCategoryImplDecl
|
|
|
|
/// object.
|
2007-10-11 01:32:04 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnStartCategoryImplementation(
|
2007-10-03 00:38:50 +08:00
|
|
|
SourceLocation AtCatImplLoc,
|
|
|
|
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
|
|
|
IdentifierInfo *CatName, SourceLocation CatLoc) {
|
2007-10-03 04:01:56 +08:00
|
|
|
ObjcInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
|
2007-10-03 00:38:50 +08:00
|
|
|
ObjcCategoryImplDecl *CDecl = new ObjcCategoryImplDecl(AtCatImplLoc,
|
2007-10-07 07:12:31 +08:00
|
|
|
CatName, IDecl);
|
2007-10-03 00:38:50 +08:00
|
|
|
/// Check that class of this category is already completely declared.
|
2007-10-03 04:26:23 +08:00
|
|
|
if (!IDecl || IDecl->isForwardDecl())
|
2007-10-03 00:38:50 +08:00
|
|
|
Diag(ClassLoc, diag::err_undef_interface, ClassName->getName());
|
2007-11-01 02:42:27 +08:00
|
|
|
|
2007-10-03 00:38:50 +08:00
|
|
|
/// TODO: Check that CatName, category name, is not used in another
|
|
|
|
// implementation.
|
|
|
|
return CDecl;
|
|
|
|
}
|
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnStartClassImplementation(
|
2007-09-26 02:38:09 +08:00
|
|
|
SourceLocation AtClassImplLoc,
|
|
|
|
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
|
|
|
IdentifierInfo *SuperClassname,
|
|
|
|
SourceLocation SuperClassLoc) {
|
|
|
|
ObjcInterfaceDecl* IDecl = 0;
|
|
|
|
// Check for another declaration kind with the same name.
|
2007-10-13 03:38:20 +08:00
|
|
|
ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName);
|
2007-09-26 02:38:09 +08:00
|
|
|
if (PrevDecl && !isa<ObjcInterfaceDecl>(PrevDecl)) {
|
|
|
|
Diag(ClassLoc, diag::err_redefinition_different_kind,
|
|
|
|
ClassName->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Is there an interface declaration of this class; if not, warn!
|
2007-10-13 03:38:20 +08:00
|
|
|
IDecl = dyn_cast_or_null<ObjcInterfaceDecl>(PrevDecl);
|
2007-09-26 02:38:09 +08:00
|
|
|
if (!IDecl)
|
|
|
|
Diag(ClassLoc, diag::warn_undef_interface, ClassName->getName());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that super class name is valid class name
|
|
|
|
ObjcInterfaceDecl* SDecl = 0;
|
|
|
|
if (SuperClassname) {
|
|
|
|
// Check if a different kind of symbol declared in this scope.
|
2007-10-13 03:38:20 +08:00
|
|
|
PrevDecl = LookupInterfaceDecl(SuperClassname);
|
2007-10-10 02:03:53 +08:00
|
|
|
if (PrevDecl && !isa<ObjcInterfaceDecl>(PrevDecl)) {
|
2007-09-26 02:38:09 +08:00
|
|
|
Diag(SuperClassLoc, diag::err_redefinition_different_kind,
|
|
|
|
SuperClassname->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
else {
|
2007-10-13 03:38:20 +08:00
|
|
|
SDecl = dyn_cast_or_null<ObjcInterfaceDecl>(PrevDecl);
|
2007-09-26 02:38:09 +08:00
|
|
|
if (!SDecl)
|
|
|
|
Diag(SuperClassLoc, diag::err_undef_superclass,
|
|
|
|
SuperClassname->getName(), ClassName->getName());
|
|
|
|
else if (IDecl && IDecl->getSuperClass() != SDecl) {
|
|
|
|
// This implementation and its interface do not have the same
|
|
|
|
// super class.
|
|
|
|
Diag(SuperClassLoc, diag::err_conflicting_super_class,
|
2007-10-13 03:38:20 +08:00
|
|
|
SDecl->getName());
|
2007-09-26 02:38:09 +08:00
|
|
|
Diag(SDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-26 05:00:20 +08:00
|
|
|
if (!IDecl) {
|
|
|
|
// Legacy case of @implementation with no corresponding @interface.
|
|
|
|
// Build, chain & install the interface decl into the identifier.
|
2007-10-04 08:22:33 +08:00
|
|
|
IDecl = new ObjcInterfaceDecl(SourceLocation(), 0, ClassName);
|
2007-09-26 05:00:20 +08:00
|
|
|
IDecl->setNext(ClassName->getFETokenInfo<ScopedDecl>());
|
|
|
|
ClassName->setFETokenInfo(IDecl);
|
2007-10-27 04:50:24 +08:00
|
|
|
IDecl->setSuperClass(SDecl);
|
2007-09-26 05:00:20 +08:00
|
|
|
|
2007-10-16 03:16:57 +08:00
|
|
|
// Remember that this needs to be removed when the scope is popped.
|
|
|
|
TUScope->AddDecl(IDecl);
|
2007-09-26 05:00:20 +08:00
|
|
|
}
|
2007-09-26 02:38:09 +08:00
|
|
|
|
2007-10-19 06:09:03 +08:00
|
|
|
ObjcImplementationDecl* IMPDecl =
|
|
|
|
new ObjcImplementationDecl(AtClassImplLoc, ClassName, IDecl, SDecl);
|
|
|
|
|
2007-09-26 02:38:09 +08:00
|
|
|
// Check that there is no duplicate implementation of this class.
|
2007-10-07 09:13:46 +08:00
|
|
|
if (!ObjcImplementations.insert(ClassName))
|
|
|
|
Diag(ClassLoc, diag::err_dup_implementation_class, ClassName->getName());
|
2007-10-31 02:27:03 +08:00
|
|
|
|
2007-09-26 02:38:09 +08:00
|
|
|
return IMPDecl;
|
|
|
|
}
|
|
|
|
|
2007-10-03 05:43:37 +08:00
|
|
|
void Sema::CheckImplementationIvars(ObjcImplementationDecl *ImpDecl,
|
|
|
|
ObjcIvarDecl **ivars, unsigned numIvars) {
|
|
|
|
assert(ImpDecl && "missing implementation decl");
|
|
|
|
ObjcInterfaceDecl* IDecl = getObjCInterfaceDecl(ImpDecl->getIdentifier());
|
2007-10-27 04:50:24 +08:00
|
|
|
if (!IDecl)
|
|
|
|
return;
|
|
|
|
/// Check case of non-existing @interface decl.
|
2007-10-04 08:22:33 +08:00
|
|
|
/// (legacy objective-c @implementation decl without an @interface decl).
|
2007-10-27 04:50:24 +08:00
|
|
|
/// Add implementations's ivar to the synthesize class's ivar list.
|
|
|
|
if (IDecl->ImplicitInterfaceDecl()) {
|
2007-10-30 05:38:07 +08:00
|
|
|
IDecl->addInstanceVariablesToClass(ivars, numIvars, SourceLocation());
|
2007-10-03 05:43:37 +08:00
|
|
|
return;
|
2007-10-27 04:50:24 +08:00
|
|
|
}
|
|
|
|
|
2007-09-27 02:27:25 +08:00
|
|
|
assert(ivars && "missing @implementation ivars");
|
|
|
|
|
2007-10-03 05:43:37 +08:00
|
|
|
// Check interface's Ivar list against those in the implementation.
|
|
|
|
// names and types must match.
|
|
|
|
//
|
2007-09-27 02:27:25 +08:00
|
|
|
ObjcIvarDecl** IntfIvars = IDecl->getIntfDeclIvars();
|
|
|
|
int IntfNumIvars = IDecl->getIntfDeclNumIvars();
|
|
|
|
unsigned j = 0;
|
|
|
|
bool err = false;
|
|
|
|
while (numIvars > 0 && IntfNumIvars > 0) {
|
|
|
|
ObjcIvarDecl* ImplIvar = ivars[j];
|
|
|
|
ObjcIvarDecl* ClsIvar = IntfIvars[j++];
|
|
|
|
assert (ImplIvar && "missing implementation ivar");
|
|
|
|
assert (ClsIvar && "missing class ivar");
|
|
|
|
if (ImplIvar->getCanonicalType() != ClsIvar->getCanonicalType()) {
|
|
|
|
Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type,
|
|
|
|
ImplIvar->getIdentifier()->getName());
|
|
|
|
Diag(ClsIvar->getLocation(), diag::err_previous_definition,
|
|
|
|
ClsIvar->getIdentifier()->getName());
|
|
|
|
}
|
|
|
|
// TODO: Two mismatched (unequal width) Ivar bitfields should be diagnosed
|
|
|
|
// as error.
|
|
|
|
else if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) {
|
|
|
|
Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name,
|
|
|
|
ImplIvar->getIdentifier()->getName());
|
|
|
|
Diag(ClsIvar->getLocation(), diag::err_previous_definition,
|
|
|
|
ClsIvar->getIdentifier()->getName());
|
|
|
|
err = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
--numIvars;
|
|
|
|
--IntfNumIvars;
|
|
|
|
}
|
|
|
|
if (!err && (numIvars > 0 || IntfNumIvars > 0))
|
|
|
|
Diag(numIvars > 0 ? ivars[j]->getLocation() : IntfIvars[j]->getLocation(),
|
|
|
|
diag::err_inconsistant_ivar);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-09-29 01:40:07 +08:00
|
|
|
/// CheckProtocolMethodDefs - This routine checks unimpletented methods
|
|
|
|
/// Declared in protocol, and those referenced by it.
|
2007-09-30 01:14:55 +08:00
|
|
|
void Sema::CheckProtocolMethodDefs(ObjcProtocolDecl *PDecl,
|
2007-10-03 04:06:01 +08:00
|
|
|
bool& IncompleteImpl,
|
2007-10-09 05:05:34 +08:00
|
|
|
const llvm::DenseSet<Selector> &InsMap,
|
2007-10-06 04:15:24 +08:00
|
|
|
const llvm::DenseSet<Selector> &ClsMap) {
|
2007-09-29 01:40:07 +08:00
|
|
|
// check unimplemented instance methods.
|
2007-10-03 06:05:16 +08:00
|
|
|
ObjcMethodDecl** methods = PDecl->getInstanceMethods();
|
2007-10-06 02:00:57 +08:00
|
|
|
for (int j = 0; j < PDecl->getNumInstanceMethods(); j++) {
|
2007-10-09 05:05:34 +08:00
|
|
|
if (!InsMap.count(methods[j]->getSelector())) {
|
2007-09-30 01:14:55 +08:00
|
|
|
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
|
2007-10-07 09:33:16 +08:00
|
|
|
methods[j]->getSelector().getName());
|
2007-10-03 04:06:01 +08:00
|
|
|
IncompleteImpl = true;
|
2007-09-29 01:40:07 +08:00
|
|
|
}
|
2007-10-06 02:00:57 +08:00
|
|
|
}
|
2007-09-29 01:40:07 +08:00
|
|
|
// check unimplemented class methods
|
2007-10-03 06:05:16 +08:00
|
|
|
methods = PDecl->getClassMethods();
|
|
|
|
for (int j = 0; j < PDecl->getNumClassMethods(); j++)
|
2007-10-06 04:15:24 +08:00
|
|
|
if (!ClsMap.count(methods[j]->getSelector())) {
|
2007-09-30 01:14:55 +08:00
|
|
|
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
|
2007-10-07 09:33:16 +08:00
|
|
|
methods[j]->getSelector().getName());
|
2007-10-03 04:06:01 +08:00
|
|
|
IncompleteImpl = true;
|
2007-09-29 01:40:07 +08:00
|
|
|
}
|
2007-09-28 02:57:03 +08:00
|
|
|
|
2007-09-29 01:40:07 +08:00
|
|
|
// Check on this protocols's referenced protocols, recursively
|
|
|
|
ObjcProtocolDecl** RefPDecl = PDecl->getReferencedProtocols();
|
|
|
|
for (int i = 0; i < PDecl->getNumReferencedProtocols(); i++)
|
2007-10-03 04:06:01 +08:00
|
|
|
CheckProtocolMethodDefs(RefPDecl[i], IncompleteImpl, InsMap, ClsMap);
|
2007-09-29 01:40:07 +08:00
|
|
|
}
|
|
|
|
|
2007-09-30 01:14:55 +08:00
|
|
|
void Sema::ImplMethodsVsClassMethods(ObjcImplementationDecl* IMPDecl,
|
|
|
|
ObjcInterfaceDecl* IDecl) {
|
2007-10-09 05:05:34 +08:00
|
|
|
llvm::DenseSet<Selector> InsMap;
|
2007-09-28 02:57:03 +08:00
|
|
|
// Check and see if instance methods in class interface have been
|
|
|
|
// implemented in the implementation class.
|
2007-10-03 06:05:16 +08:00
|
|
|
ObjcMethodDecl **methods = IMPDecl->getInstanceMethods();
|
2007-10-06 02:00:57 +08:00
|
|
|
for (int i=0; i < IMPDecl->getNumInstanceMethods(); i++)
|
2007-10-09 05:05:34 +08:00
|
|
|
InsMap.insert(methods[i]->getSelector());
|
2007-09-28 02:57:03 +08:00
|
|
|
|
2007-10-03 04:06:01 +08:00
|
|
|
bool IncompleteImpl = false;
|
2007-10-03 06:05:16 +08:00
|
|
|
methods = IDecl->getInstanceMethods();
|
|
|
|
for (int j = 0; j < IDecl->getNumInstanceMethods(); j++)
|
2007-10-09 05:05:34 +08:00
|
|
|
if (!InsMap.count(methods[j]->getSelector())) {
|
2007-09-30 01:14:55 +08:00
|
|
|
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
|
2007-10-07 09:33:16 +08:00
|
|
|
methods[j]->getSelector().getName());
|
2007-10-03 04:06:01 +08:00
|
|
|
IncompleteImpl = true;
|
2007-09-28 02:57:03 +08:00
|
|
|
}
|
2007-10-06 04:15:24 +08:00
|
|
|
llvm::DenseSet<Selector> ClsMap;
|
2007-09-28 02:57:03 +08:00
|
|
|
// Check and see if class methods in class interface have been
|
|
|
|
// implemented in the implementation class.
|
2007-10-03 06:05:16 +08:00
|
|
|
methods = IMPDecl->getClassMethods();
|
2007-10-06 02:00:57 +08:00
|
|
|
for (int i=0; i < IMPDecl->getNumClassMethods(); i++)
|
2007-10-06 04:15:24 +08:00
|
|
|
ClsMap.insert(methods[i]->getSelector());
|
2007-09-28 02:57:03 +08:00
|
|
|
|
2007-10-03 06:05:16 +08:00
|
|
|
methods = IDecl->getClassMethods();
|
|
|
|
for (int j = 0; j < IDecl->getNumClassMethods(); j++)
|
2007-10-06 04:15:24 +08:00
|
|
|
if (!ClsMap.count(methods[j]->getSelector())) {
|
2007-09-30 01:14:55 +08:00
|
|
|
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
|
2007-10-07 09:33:16 +08:00
|
|
|
methods[j]->getSelector().getName());
|
2007-10-03 04:06:01 +08:00
|
|
|
IncompleteImpl = true;
|
2007-09-28 02:57:03 +08:00
|
|
|
}
|
2007-09-29 01:40:07 +08:00
|
|
|
|
|
|
|
// Check the protocol list for unimplemented methods in the @implementation
|
|
|
|
// class.
|
2007-10-03 06:05:16 +08:00
|
|
|
ObjcProtocolDecl** protocols = IDecl->getReferencedProtocols();
|
2007-10-06 04:15:24 +08:00
|
|
|
for (int i = 0; i < IDecl->getNumIntfRefProtocols(); i++)
|
|
|
|
CheckProtocolMethodDefs(protocols[i], IncompleteImpl, InsMap, ClsMap);
|
|
|
|
|
2007-10-03 04:06:01 +08:00
|
|
|
if (IncompleteImpl)
|
2007-10-04 08:22:33 +08:00
|
|
|
Diag(IMPDecl->getLocation(), diag::warn_incomplete_impl_class,
|
|
|
|
IMPDecl->getName());
|
2007-10-03 00:38:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
|
|
|
|
/// category interface is implemented in the category @implementation.
|
|
|
|
void Sema::ImplCategoryMethodsVsIntfMethods(ObjcCategoryImplDecl *CatImplDecl,
|
|
|
|
ObjcCategoryDecl *CatClassDecl) {
|
2007-10-09 05:05:34 +08:00
|
|
|
llvm::DenseSet<Selector> InsMap;
|
2007-10-03 00:38:50 +08:00
|
|
|
// Check and see if instance methods in category interface have been
|
|
|
|
// implemented in its implementation class.
|
2007-10-03 06:05:16 +08:00
|
|
|
ObjcMethodDecl **methods = CatImplDecl->getInstanceMethods();
|
2007-10-06 02:00:57 +08:00
|
|
|
for (int i=0; i < CatImplDecl->getNumInstanceMethods(); i++)
|
2007-10-09 05:05:34 +08:00
|
|
|
InsMap.insert(methods[i]->getSelector());
|
2007-10-03 00:38:50 +08:00
|
|
|
|
2007-10-03 04:06:01 +08:00
|
|
|
bool IncompleteImpl = false;
|
2007-10-03 06:05:16 +08:00
|
|
|
methods = CatClassDecl->getInstanceMethods();
|
|
|
|
for (int j = 0; j < CatClassDecl->getNumInstanceMethods(); j++)
|
2007-10-09 05:05:34 +08:00
|
|
|
if (!InsMap.count(methods[j]->getSelector())) {
|
2007-10-03 00:38:50 +08:00
|
|
|
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
|
2007-10-07 09:33:16 +08:00
|
|
|
methods[j]->getSelector().getName());
|
2007-10-03 04:06:01 +08:00
|
|
|
IncompleteImpl = true;
|
2007-10-03 00:38:50 +08:00
|
|
|
}
|
2007-10-06 04:15:24 +08:00
|
|
|
llvm::DenseSet<Selector> ClsMap;
|
2007-10-03 00:38:50 +08:00
|
|
|
// Check and see if class methods in category interface have been
|
|
|
|
// implemented in its implementation class.
|
2007-10-03 06:05:16 +08:00
|
|
|
methods = CatImplDecl->getClassMethods();
|
2007-10-06 02:00:57 +08:00
|
|
|
for (int i=0; i < CatImplDecl->getNumClassMethods(); i++)
|
2007-10-06 04:15:24 +08:00
|
|
|
ClsMap.insert(methods[i]->getSelector());
|
2007-10-03 00:38:50 +08:00
|
|
|
|
2007-10-03 06:05:16 +08:00
|
|
|
methods = CatClassDecl->getClassMethods();
|
|
|
|
for (int j = 0; j < CatClassDecl->getNumClassMethods(); j++)
|
2007-10-06 04:15:24 +08:00
|
|
|
if (!ClsMap.count(methods[j]->getSelector())) {
|
2007-10-03 00:38:50 +08:00
|
|
|
Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
|
2007-10-07 09:33:16 +08:00
|
|
|
methods[j]->getSelector().getName());
|
2007-10-03 04:06:01 +08:00
|
|
|
IncompleteImpl = true;
|
2007-10-03 00:38:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check the protocol list for unimplemented methods in the @implementation
|
|
|
|
// class.
|
2007-10-03 06:05:16 +08:00
|
|
|
ObjcProtocolDecl** protocols = CatClassDecl->getReferencedProtocols();
|
|
|
|
for (int i = 0; i < CatClassDecl->getNumReferencedProtocols(); i++) {
|
2007-10-03 00:38:50 +08:00
|
|
|
ObjcProtocolDecl* PDecl = protocols[i];
|
2007-10-03 04:06:01 +08:00
|
|
|
CheckProtocolMethodDefs(PDecl, IncompleteImpl, InsMap, ClsMap);
|
2007-10-03 00:38:50 +08:00
|
|
|
}
|
2007-10-03 04:06:01 +08:00
|
|
|
if (IncompleteImpl)
|
2007-10-04 08:22:33 +08:00
|
|
|
Diag(CatImplDecl->getLocation(), diag::warn_incomplete_impl_category,
|
2007-10-07 06:53:46 +08:00
|
|
|
CatClassDecl->getName());
|
2007-09-28 02:57:03 +08:00
|
|
|
}
|
|
|
|
|
2007-10-03 06:39:18 +08:00
|
|
|
/// ActOnForwardClassDeclaration -
|
2007-09-07 05:24:23 +08:00
|
|
|
Action::DeclTy *
|
2007-10-11 01:32:04 +08:00
|
|
|
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
2007-10-03 06:39:18 +08:00
|
|
|
IdentifierInfo **IdentList, unsigned NumElts)
|
|
|
|
{
|
2007-10-07 04:08:36 +08:00
|
|
|
llvm::SmallVector<ObjcInterfaceDecl*, 32> Interfaces;
|
|
|
|
|
2007-09-07 05:24:23 +08:00
|
|
|
for (unsigned i = 0; i != NumElts; ++i) {
|
2007-10-16 03:16:57 +08:00
|
|
|
// Check for another declaration kind with the same name.
|
|
|
|
ScopedDecl *PrevDecl = LookupInterfaceDecl(IdentList[i]);
|
|
|
|
if (PrevDecl && !isa<ObjcInterfaceDecl>(PrevDecl)) {
|
|
|
|
Diag(AtClassLoc, diag::err_redefinition_different_kind,
|
|
|
|
IdentList[i]->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
ObjcInterfaceDecl *IDecl = dyn_cast_or_null<ObjcInterfaceDecl>(PrevDecl);
|
2007-10-07 04:08:36 +08:00
|
|
|
if (!IDecl) { // Not already seen? Make a forward decl.
|
2007-10-16 03:16:57 +08:00
|
|
|
IDecl = new ObjcInterfaceDecl(AtClassLoc, 0, IdentList[i], true);
|
2007-09-21 04:26:44 +08:00
|
|
|
// Chain & install the interface decl into the identifier.
|
|
|
|
IDecl->setNext(IdentList[i]->getFETokenInfo<ScopedDecl>());
|
|
|
|
IdentList[i]->setFETokenInfo(IDecl);
|
2007-10-07 15:05:08 +08:00
|
|
|
|
|
|
|
// Remember that this needs to be removed when the scope is popped.
|
2007-10-11 01:32:04 +08:00
|
|
|
TUScope->AddDecl(IDecl);
|
2007-09-21 04:26:44 +08:00
|
|
|
}
|
2007-10-07 04:08:36 +08:00
|
|
|
|
|
|
|
Interfaces.push_back(IDecl);
|
2007-09-07 05:24:23 +08:00
|
|
|
}
|
2007-10-07 04:08:36 +08:00
|
|
|
|
|
|
|
return new ObjcClassDecl(AtClassLoc, &Interfaces[0], Interfaces.size());
|
2007-09-07 05:24:23 +08:00
|
|
|
}
|
|
|
|
|
2007-01-22 15:39:13 +08:00
|
|
|
|
2007-09-16 02:49:24 +08:00
|
|
|
/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the
|
2007-01-24 07:42:53 +08:00
|
|
|
/// former case, Name will be non-null. In the later case, Name will be null.
|
|
|
|
/// TagType indicates what kind of tag this is. TK indicates whether this is a
|
|
|
|
/// reference/declaration/definition of a tag.
|
2007-09-16 02:49:24 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
|
2007-01-23 12:08:05 +08:00
|
|
|
SourceLocation KWLoc, IdentifierInfo *Name,
|
2007-06-09 11:47:53 +08:00
|
|
|
SourceLocation NameLoc, AttributeList *Attr) {
|
2007-01-23 09:57:16 +08:00
|
|
|
// If this is a use of an existing tag, it must have a name.
|
2007-01-24 04:11:08 +08:00
|
|
|
assert((Name != 0 || TK == TK_Definition) &&
|
|
|
|
"Nameless record must be a definition!");
|
2007-01-23 09:57:16 +08:00
|
|
|
|
2007-01-23 12:08:05 +08:00
|
|
|
Decl::Kind Kind;
|
2007-01-23 12:27:41 +08:00
|
|
|
switch (TagType) {
|
2007-01-23 12:08:05 +08:00
|
|
|
default: assert(0 && "Unknown tag type!");
|
2007-01-23 12:27:41 +08:00
|
|
|
case DeclSpec::TST_struct: Kind = Decl::Struct; break;
|
|
|
|
case DeclSpec::TST_union: Kind = Decl::Union; break;
|
|
|
|
//case DeclSpec::TST_class: Kind = Decl::Class; break;
|
|
|
|
case DeclSpec::TST_enum: Kind = Decl::Enum; break;
|
2007-01-23 12:08:05 +08:00
|
|
|
}
|
2007-01-23 10:05:42 +08:00
|
|
|
|
2007-01-22 15:39:13 +08:00
|
|
|
// If this is a named struct, check to see if there was a previous forward
|
|
|
|
// declaration or definition.
|
2007-01-24 04:11:08 +08:00
|
|
|
if (TagDecl *PrevDecl =
|
2007-01-28 16:20:04 +08:00
|
|
|
dyn_cast_or_null<TagDecl>(LookupScopedDecl(Name, Decl::IDNS_Tag,
|
|
|
|
NameLoc, S))) {
|
2007-01-23 09:57:16 +08:00
|
|
|
|
|
|
|
// If this is a use of a previous tag, or if the tag is already declared in
|
|
|
|
// the same scope (so that the definition/declaration completes or
|
|
|
|
// rementions the tag), reuse the decl.
|
2007-01-24 04:11:08 +08:00
|
|
|
if (TK == TK_Reference || S->isDeclScope(PrevDecl)) {
|
2007-01-23 10:05:42 +08:00
|
|
|
// Make sure that this wasn't declared as an enum and now used as a struct
|
|
|
|
// or something similar.
|
|
|
|
if (PrevDecl->getKind() != Kind) {
|
2007-01-23 12:08:05 +08:00
|
|
|
Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
|
2007-01-23 10:05:42 +08:00
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_use);
|
|
|
|
}
|
2007-01-24 04:11:08 +08:00
|
|
|
|
|
|
|
// If this is a use or a forward declaration, we're good.
|
|
|
|
if (TK != TK_Definition)
|
|
|
|
return PrevDecl;
|
2007-01-23 12:08:05 +08:00
|
|
|
|
2007-01-24 04:11:08 +08:00
|
|
|
// Diagnose attempts to redefine a tag.
|
|
|
|
if (PrevDecl->isDefinition()) {
|
|
|
|
Diag(NameLoc, diag::err_redefinition, Name->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
// If this is a redefinition, recover by making this struct be
|
|
|
|
// anonymous, which will make any later references get the previous
|
|
|
|
// definition.
|
|
|
|
Name = 0;
|
|
|
|
} else {
|
|
|
|
// Okay, this is definition of a previously declared or referenced tag.
|
|
|
|
// Move the location of the decl to be the definition site.
|
|
|
|
PrevDecl->setLocation(NameLoc);
|
|
|
|
return PrevDecl;
|
|
|
|
}
|
2007-01-23 09:57:16 +08:00
|
|
|
}
|
2007-01-23 12:08:05 +08:00
|
|
|
// If we get here, this is a definition of a new struct type in a nested
|
|
|
|
// scope, e.g. "struct foo; void bar() { struct foo; }", just create a new
|
|
|
|
// type.
|
2007-01-22 15:39:13 +08:00
|
|
|
}
|
|
|
|
|
2007-01-23 12:27:41 +08:00
|
|
|
// If there is an identifier, use the location of the identifier as the
|
|
|
|
// location of the decl, otherwise use the location of the struct/union
|
|
|
|
// keyword.
|
|
|
|
SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
|
|
|
|
|
2007-01-22 15:39:13 +08:00
|
|
|
// Otherwise, if this is the first time we've seen this tag, create the decl.
|
2007-01-24 04:11:08 +08:00
|
|
|
TagDecl *New;
|
2007-01-25 08:44:24 +08:00
|
|
|
switch (Kind) {
|
|
|
|
default: assert(0 && "Unknown tag kind!");
|
2007-01-25 14:27:24 +08:00
|
|
|
case Decl::Enum:
|
2007-06-09 08:53:06 +08:00
|
|
|
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
|
|
|
|
// enum X { A, B, C } D; D should chain to X.
|
|
|
|
New = new EnumDecl(Loc, Name, 0);
|
2007-01-25 14:27:24 +08:00
|
|
|
// If this is an undefined enum, warn.
|
2007-01-25 15:29:02 +08:00
|
|
|
if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum);
|
2007-01-25 14:27:24 +08:00
|
|
|
break;
|
2007-01-25 08:44:24 +08:00
|
|
|
case Decl::Union:
|
|
|
|
case Decl::Struct:
|
|
|
|
case Decl::Class:
|
2007-06-09 08:53:06 +08:00
|
|
|
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
|
|
|
|
// struct X { int A; } D; D should chain to X.
|
|
|
|
New = new RecordDecl(Kind, Loc, Name, 0);
|
2007-01-25 08:44:24 +08:00
|
|
|
break;
|
|
|
|
}
|
2007-01-22 15:39:13 +08:00
|
|
|
|
|
|
|
// If this has an identifier, add it to the scope stack.
|
|
|
|
if (Name) {
|
2007-08-26 14:24:45 +08:00
|
|
|
// The scope passed in may not be a decl scope. Zip up the scope tree until
|
|
|
|
// we find one that is.
|
|
|
|
while ((S->getFlags() & Scope::DeclScope) == 0)
|
|
|
|
S = S->getParent();
|
|
|
|
|
|
|
|
// Add it to the decl chain.
|
2007-09-14 02:10:37 +08:00
|
|
|
New->setNext(Name->getFETokenInfo<ScopedDecl>());
|
2007-01-22 15:39:13 +08:00
|
|
|
Name->setFETokenInfo(New);
|
|
|
|
S->AddDecl(New);
|
|
|
|
}
|
|
|
|
|
|
|
|
return New;
|
|
|
|
}
|
2007-01-24 07:42:53 +08:00
|
|
|
|
2007-09-16 02:49:24 +08:00
|
|
|
/// ActOnField - Each field of a struct/union/class is passed into this in order
|
2007-01-24 07:42:53 +08:00
|
|
|
/// to create a FieldDecl object for it.
|
2007-09-16 02:49:24 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagDecl,
|
2007-01-24 07:42:53 +08:00
|
|
|
SourceLocation DeclStart,
|
|
|
|
Declarator &D, ExprTy *BitfieldWidth) {
|
|
|
|
IdentifierInfo *II = D.getIdentifier();
|
|
|
|
Expr *BitWidth = (Expr*)BitfieldWidth;
|
|
|
|
SourceLocation Loc = DeclStart;
|
|
|
|
if (II) Loc = D.getIdentifierLoc();
|
|
|
|
|
2007-01-28 08:21:37 +08:00
|
|
|
// FIXME: Unnamed fields can be handled in various different ways, for
|
|
|
|
// example, unnamed unions inject all members into the struct namespace!
|
|
|
|
|
|
|
|
|
2007-01-24 07:42:53 +08:00
|
|
|
if (BitWidth) {
|
|
|
|
// TODO: Validate.
|
2007-05-24 05:48:04 +08:00
|
|
|
//printf("WARNING: BITFIELDS IGNORED!\n");
|
2007-01-24 07:42:53 +08:00
|
|
|
|
|
|
|
// 6.7.2.1p3
|
|
|
|
// 6.7.2.1p4
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Not a bitfield.
|
|
|
|
|
|
|
|
// validate II.
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType T = GetTypeForDeclarator(D, S);
|
2007-08-29 04:14:24 +08:00
|
|
|
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
|
|
|
bool InvalidDecl = false;
|
2007-09-01 01:20:07 +08:00
|
|
|
|
2007-05-09 05:09:37 +08:00
|
|
|
// C99 6.7.2.1p8: A member of a structure or union may have any type other
|
|
|
|
// than a variably modified type.
|
2007-09-01 01:20:07 +08:00
|
|
|
if (const VariableArrayType *VAT = T->getAsVariablyModifiedType()) {
|
|
|
|
Diag(Loc, diag::err_typecheck_illegal_vla,
|
|
|
|
VAT->getSizeExpr()->getSourceRange());
|
|
|
|
InvalidDecl = true;
|
2007-05-09 05:09:37 +08:00
|
|
|
}
|
2007-06-09 08:53:06 +08:00
|
|
|
// FIXME: Chain fielddecls together.
|
2007-09-12 05:17:26 +08:00
|
|
|
FieldDecl *NewFD;
|
|
|
|
|
|
|
|
if (isa<RecordDecl>(static_cast<Decl *>(TagDecl)))
|
2007-09-14 10:20:46 +08:00
|
|
|
NewFD = new FieldDecl(Loc, II, T);
|
2007-09-26 02:38:09 +08:00
|
|
|
else if (isa<ObjcInterfaceDecl>(static_cast<Decl *>(TagDecl))
|
2007-10-04 08:45:27 +08:00
|
|
|
|| isa<ObjcImplementationDecl>(static_cast<Decl *>(TagDecl)))
|
2007-09-14 10:20:46 +08:00
|
|
|
NewFD = new ObjcIvarDecl(Loc, II, T);
|
2007-09-12 05:17:26 +08:00
|
|
|
else
|
2007-09-16 02:49:24 +08:00
|
|
|
assert(0 && "Sema::ActOnField(): Unknown TagDecl");
|
2007-09-12 05:17:26 +08:00
|
|
|
|
2007-08-29 04:14:24 +08:00
|
|
|
if (D.getInvalidType() || InvalidDecl)
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
return NewFD;
|
2007-01-24 07:42:53 +08:00
|
|
|
}
|
|
|
|
|
2007-10-02 00:53:59 +08:00
|
|
|
/// TranslateIvarVisibility - Translate visibility from a token ID to an
|
|
|
|
/// AST enum value.
|
|
|
|
static ObjcIvarDecl::AccessControl
|
|
|
|
TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
|
2007-09-15 07:09:53 +08:00
|
|
|
switch (ivarVisibility) {
|
2007-10-02 00:53:59 +08:00
|
|
|
case tok::objc_private: return ObjcIvarDecl::Private;
|
|
|
|
case tok::objc_public: return ObjcIvarDecl::Public;
|
|
|
|
case tok::objc_protected: return ObjcIvarDecl::Protected;
|
|
|
|
case tok::objc_package: return ObjcIvarDecl::Package;
|
|
|
|
default: assert(false && "Unknown visitibility kind");
|
2007-09-15 07:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-29 08:54:24 +08:00
|
|
|
void Sema::ActOnFields(Scope* S,
|
2007-10-04 08:45:27 +08:00
|
|
|
SourceLocation RecLoc, DeclTy *RecDecl,
|
2007-09-16 02:49:24 +08:00
|
|
|
DeclTy **Fields, unsigned NumFields,
|
2007-10-30 05:38:07 +08:00
|
|
|
SourceLocation LBrac, SourceLocation RBrac,
|
2007-09-16 02:49:24 +08:00
|
|
|
tok::ObjCKeywordKind *visibility) {
|
2007-09-15 06:20:54 +08:00
|
|
|
Decl *EnclosingDecl = static_cast<Decl*>(RecDecl);
|
|
|
|
assert(EnclosingDecl && "missing record or interface decl");
|
|
|
|
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
|
|
|
|
|
2007-09-15 00:27:55 +08:00
|
|
|
if (Record && Record->isDefinition()) {
|
2007-01-24 07:42:53 +08:00
|
|
|
// Diagnose code like:
|
2007-01-24 10:11:17 +08:00
|
|
|
// struct S { struct S {} X; };
|
2007-01-24 07:42:53 +08:00
|
|
|
// We discover this when we complete the outer S. Reject and ignore the
|
|
|
|
// outer S.
|
|
|
|
Diag(Record->getLocation(), diag::err_nested_redefinition,
|
|
|
|
Record->getKindName());
|
|
|
|
Diag(RecLoc, diag::err_previous_definition);
|
2007-09-15 06:20:54 +08:00
|
|
|
Record->setInvalidDecl();
|
2007-01-24 07:42:53 +08:00
|
|
|
return;
|
|
|
|
}
|
2007-01-24 10:11:17 +08:00
|
|
|
// Verify that all the fields are okay.
|
2007-01-24 10:26:21 +08:00
|
|
|
unsigned NumNamedMembers = 0;
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<FieldDecl*, 32> RecFields;
|
|
|
|
llvm::SmallSet<const IdentifierInfo*, 32> FieldIDs;
|
2007-09-15 06:20:54 +08:00
|
|
|
|
2007-01-24 10:11:17 +08:00
|
|
|
for (unsigned i = 0; i != NumFields; ++i) {
|
2007-09-15 00:27:55 +08:00
|
|
|
|
2007-09-15 06:20:54 +08:00
|
|
|
FieldDecl *FD = cast_or_null<FieldDecl>(static_cast<Decl*>(Fields[i]));
|
|
|
|
assert(FD && "missing field decl");
|
|
|
|
|
|
|
|
// Remember all fields.
|
|
|
|
RecFields.push_back(FD);
|
2007-01-25 08:44:24 +08:00
|
|
|
|
|
|
|
// Get the type for the field.
|
2007-08-01 05:33:24 +08:00
|
|
|
Type *FDTy = FD->getType().getTypePtr();
|
2007-01-25 08:44:24 +08:00
|
|
|
|
2007-09-15 07:09:53 +08:00
|
|
|
// If we have visibility info, make sure the AST is set accordingly.
|
|
|
|
if (visibility)
|
2007-10-02 00:53:59 +08:00
|
|
|
cast<ObjcIvarDecl>(FD)->setAccessControl(
|
|
|
|
TranslateIvarVisibility(visibility[i]));
|
2007-09-15 07:09:53 +08:00
|
|
|
|
2007-01-24 10:11:17 +08:00
|
|
|
// C99 6.7.2.1p2 - A field may not be a function type.
|
2007-08-01 05:33:24 +08:00
|
|
|
if (FDTy->isFunctionType()) {
|
2007-09-15 06:20:54 +08:00
|
|
|
Diag(FD->getLocation(), diag::err_field_declared_as_function,
|
2007-01-24 10:11:17 +08:00
|
|
|
FD->getName());
|
2007-09-15 06:20:54 +08:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-01-24 10:11:17 +08:00
|
|
|
continue;
|
|
|
|
}
|
2007-01-24 10:26:21 +08:00
|
|
|
// C99 6.7.2.1p2 - A field may not be an incomplete type except...
|
2007-01-25 08:44:24 +08:00
|
|
|
if (FDTy->isIncompleteType()) {
|
2007-09-15 00:27:55 +08:00
|
|
|
if (!Record) { // Incomplete ivar type is always an error.
|
2007-10-04 08:45:27 +08:00
|
|
|
Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName());
|
2007-09-15 06:20:54 +08:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-10-04 08:45:27 +08:00
|
|
|
continue;
|
2007-09-15 00:27:55 +08:00
|
|
|
}
|
2007-01-24 10:26:21 +08:00
|
|
|
if (i != NumFields-1 || // ... that the last member ...
|
|
|
|
Record->getKind() != Decl::Struct || // ... of a structure ...
|
2007-08-01 05:33:24 +08:00
|
|
|
!FDTy->isArrayType()) { //... may have incomplete array type.
|
2007-01-24 10:26:21 +08:00
|
|
|
Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName());
|
2007-09-15 06:20:54 +08:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-01-24 10:26:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
2007-09-15 00:27:55 +08:00
|
|
|
if (NumNamedMembers < 1) { //... must have more than named member ...
|
2007-01-24 10:26:21 +08:00
|
|
|
Diag(FD->getLocation(), diag::err_flexible_array_empty_struct,
|
|
|
|
FD->getName());
|
2007-09-15 06:20:54 +08:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-01-24 10:26:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
2007-01-25 08:44:24 +08:00
|
|
|
// Okay, we have a legal flexible array member at the end of the struct.
|
2007-09-15 00:27:55 +08:00
|
|
|
if (Record)
|
|
|
|
Record->setHasFlexibleArrayMember(true);
|
2007-01-25 08:44:24 +08:00
|
|
|
}
|
|
|
|
/// C99 6.7.2.1p2 - a struct ending in a flexible array member cannot be the
|
|
|
|
/// field of another structure or the element of an array.
|
2007-08-01 05:33:24 +08:00
|
|
|
if (const RecordType *FDTTy = FDTy->getAsRecordType()) {
|
2007-01-25 08:44:24 +08:00
|
|
|
if (FDTTy->getDecl()->hasFlexibleArrayMember()) {
|
|
|
|
// If this is a member of a union, then entire union becomes "flexible".
|
2007-09-15 00:27:55 +08:00
|
|
|
if (Record && Record->getKind() == Decl::Union) {
|
2007-01-25 12:52:46 +08:00
|
|
|
Record->setHasFlexibleArrayMember(true);
|
2007-01-25 08:44:24 +08:00
|
|
|
} else {
|
|
|
|
// If this is a struct/class and this is not the last element, reject
|
|
|
|
// it. Note that GCC supports variable sized arrays in the middle of
|
|
|
|
// structures.
|
|
|
|
if (i != NumFields-1) {
|
|
|
|
Diag(FD->getLocation(), diag::err_variable_sized_type_in_struct,
|
|
|
|
FD->getName());
|
2007-09-15 06:20:54 +08:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-01-25 08:44:24 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// We support flexible arrays at the end of structs in other structs
|
|
|
|
// as an extension.
|
|
|
|
Diag(FD->getLocation(), diag::ext_flexible_array_in_struct,
|
|
|
|
FD->getName());
|
2007-10-04 08:45:27 +08:00
|
|
|
if (Record)
|
2007-09-15 00:27:55 +08:00
|
|
|
Record->setHasFlexibleArrayMember(true);
|
2007-01-25 08:44:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-10-13 06:10:42 +08:00
|
|
|
/// A field cannot be an Objective-c object
|
|
|
|
if (FDTy->isObjcInterfaceType()) {
|
|
|
|
Diag(FD->getLocation(), diag::err_statically_allocated_object,
|
|
|
|
FD->getName());
|
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
|
|
|
continue;
|
|
|
|
}
|
2007-01-24 10:26:21 +08:00
|
|
|
// Keep track of the number of named members.
|
2007-01-26 06:48:42 +08:00
|
|
|
if (IdentifierInfo *II = FD->getIdentifier()) {
|
|
|
|
// Detect duplicate member names.
|
2007-01-27 10:14:08 +08:00
|
|
|
if (!FieldIDs.insert(II)) {
|
2007-01-26 06:48:42 +08:00
|
|
|
Diag(FD->getLocation(), diag::err_duplicate_member, II->getName());
|
|
|
|
// Find the previous decl.
|
|
|
|
SourceLocation PrevLoc;
|
|
|
|
for (unsigned i = 0, e = RecFields.size(); ; ++i) {
|
|
|
|
assert(i != e && "Didn't find previous def!");
|
|
|
|
if (RecFields[i]->getIdentifier() == II) {
|
|
|
|
PrevLoc = RecFields[i]->getLocation();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Diag(PrevLoc, diag::err_previous_definition);
|
2007-09-15 06:20:54 +08:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-01-26 06:48:42 +08:00
|
|
|
continue;
|
|
|
|
}
|
2007-01-24 10:26:21 +08:00
|
|
|
++NumNamedMembers;
|
2007-01-26 06:48:42 +08:00
|
|
|
}
|
2007-01-24 10:11:17 +08:00
|
|
|
}
|
2007-01-24 10:26:21 +08:00
|
|
|
|
|
|
|
// Okay, we successfully defined 'Record'.
|
2007-09-15 00:27:55 +08:00
|
|
|
if (Record)
|
|
|
|
Record->defineBody(&RecFields[0], RecFields.size());
|
2007-09-15 05:08:27 +08:00
|
|
|
else {
|
|
|
|
ObjcIvarDecl **ClsFields =
|
|
|
|
reinterpret_cast<ObjcIvarDecl**>(&RecFields[0]);
|
2007-09-27 02:27:25 +08:00
|
|
|
if (isa<ObjcInterfaceDecl>(static_cast<Decl*>(RecDecl)))
|
|
|
|
cast<ObjcInterfaceDecl>(static_cast<Decl*>(RecDecl))->
|
2007-10-30 05:38:07 +08:00
|
|
|
addInstanceVariablesToClass(ClsFields, RecFields.size(), RBrac);
|
2007-09-27 02:27:25 +08:00
|
|
|
else if (isa<ObjcImplementationDecl>(static_cast<Decl*>(RecDecl))) {
|
|
|
|
ObjcImplementationDecl* IMPDecl =
|
2007-10-04 08:45:27 +08:00
|
|
|
cast<ObjcImplementationDecl>(static_cast<Decl*>(RecDecl));
|
2007-09-27 02:27:25 +08:00
|
|
|
assert(IMPDecl && "ActOnFields - missing ObjcImplementationDecl");
|
|
|
|
IMPDecl->ObjcAddInstanceVariablesToClassImpl(ClsFields, RecFields.size());
|
2007-10-03 05:43:37 +08:00
|
|
|
CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size());
|
2007-09-27 02:27:25 +08:00
|
|
|
}
|
2007-09-15 05:08:27 +08:00
|
|
|
}
|
2007-01-24 07:42:53 +08:00
|
|
|
}
|
|
|
|
|
2007-10-06 02:00:57 +08:00
|
|
|
/// MatchTwoMethodDeclarations - Checks that two methods have matching type and
|
|
|
|
/// returns true, or false, accordingly.
|
|
|
|
/// TODO: Handle protocol list; such as id<p1,p2> in type comparisons
|
|
|
|
bool Sema:: MatchTwoMethodDeclarations(const ObjcMethodDecl *Method,
|
|
|
|
const ObjcMethodDecl *PrevMethod) {
|
2007-10-17 05:36:54 +08:00
|
|
|
if (Method->getResultType().getCanonicalType() !=
|
|
|
|
PrevMethod->getResultType().getCanonicalType())
|
2007-10-06 02:00:57 +08:00
|
|
|
return false;
|
|
|
|
for (int i = 0; i < Method->getNumParams(); i++) {
|
|
|
|
ParmVarDecl *ParamDecl = Method->getParamDecl(i);
|
|
|
|
ParmVarDecl *PrevParamDecl = PrevMethod->getParamDecl(i);
|
|
|
|
if (ParamDecl->getCanonicalType() != PrevParamDecl->getCanonicalType())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-10-14 08:58:41 +08:00
|
|
|
void Sema::AddInstanceMethodToGlobalPool(ObjcMethodDecl *Method) {
|
|
|
|
ObjcMethodList &FirstMethod = InstanceMethodPool[Method->getSelector()];
|
|
|
|
if (!FirstMethod.Method) {
|
|
|
|
// Haven't seen a method with this selector name yet - add it.
|
|
|
|
FirstMethod.Method = Method;
|
|
|
|
FirstMethod.Next = 0;
|
|
|
|
} else {
|
|
|
|
// We've seen a method with this name, now check the type signature(s).
|
|
|
|
bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method);
|
|
|
|
|
|
|
|
for (ObjcMethodList *Next = FirstMethod.Next; !match && Next;
|
|
|
|
Next = Next->Next)
|
|
|
|
match = MatchTwoMethodDeclarations(Method, Next->Method);
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
// We have a new signature for an existing method - add it.
|
|
|
|
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
|
|
|
|
struct ObjcMethodList *OMI = new ObjcMethodList(Method, FirstMethod.Next);
|
|
|
|
FirstMethod.Next = OMI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::AddFactoryMethodToGlobalPool(ObjcMethodDecl *Method) {
|
|
|
|
ObjcMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()];
|
|
|
|
if (!FirstMethod.Method) {
|
|
|
|
// Haven't seen a method with this selector name yet - add it.
|
|
|
|
FirstMethod.Method = Method;
|
|
|
|
FirstMethod.Next = 0;
|
|
|
|
} else {
|
|
|
|
// We've seen a method with this name, now check the type signature(s).
|
|
|
|
bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method);
|
|
|
|
|
|
|
|
for (ObjcMethodList *Next = FirstMethod.Next; !match && Next;
|
|
|
|
Next = Next->Next)
|
|
|
|
match = MatchTwoMethodDeclarations(Method, Next->Method);
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
// We have a new signature for an existing method - add it.
|
|
|
|
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
|
|
|
|
struct ObjcMethodList *OMI = new ObjcMethodList(Method, FirstMethod.Next);
|
|
|
|
FirstMethod.Next = OMI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-07 06:53:46 +08:00
|
|
|
void Sema::ActOnAddMethodsToObjcDecl(Scope* S, DeclTy *classDecl,
|
2007-10-30 05:38:07 +08:00
|
|
|
DeclTy **allMethods, unsigned allNum,
|
|
|
|
SourceLocation AtEndLoc) {
|
2007-10-07 06:53:46 +08:00
|
|
|
Decl *ClassDecl = static_cast<Decl *>(classDecl);
|
2007-10-13 02:49:25 +08:00
|
|
|
|
|
|
|
// FIXME: If we don't have a ClassDecl, we have an error. I (snaroff) would
|
|
|
|
// prefer we always pass in a decl. If the decl has an error, isInvalidDecl()
|
|
|
|
// should be true.
|
2007-09-13 02:23:47 +08:00
|
|
|
if (!ClassDecl)
|
|
|
|
return;
|
2007-10-30 11:43:13 +08:00
|
|
|
|
2007-09-11 04:33:04 +08:00
|
|
|
llvm::SmallVector<ObjcMethodDecl*, 32> insMethods;
|
|
|
|
llvm::SmallVector<ObjcMethodDecl*, 16> clsMethods;
|
2007-10-06 02:00:57 +08:00
|
|
|
|
2007-10-09 05:05:34 +08:00
|
|
|
llvm::DenseMap<Selector, const ObjcMethodDecl*> InsMap;
|
|
|
|
llvm::DenseMap<Selector, const ObjcMethodDecl*> ClsMap;
|
2007-10-06 02:00:57 +08:00
|
|
|
|
2007-10-13 07:43:31 +08:00
|
|
|
bool checkDuplicateMethods =
|
|
|
|
(isa<ObjcInterfaceDecl>(ClassDecl) || isa<ObjcCategoryDecl>(ClassDecl)
|
|
|
|
|| isa<ObjcProtocolDecl>(ClassDecl));
|
2007-10-17 05:52:23 +08:00
|
|
|
bool checkIdenticalMethods = isa<ObjcImplementationDecl>(ClassDecl);
|
2007-10-06 02:00:57 +08:00
|
|
|
|
2007-09-11 04:33:04 +08:00
|
|
|
for (unsigned i = 0; i < allNum; i++ ) {
|
2007-09-18 05:07:36 +08:00
|
|
|
ObjcMethodDecl *Method =
|
2007-09-11 04:33:04 +08:00
|
|
|
cast_or_null<ObjcMethodDecl>(static_cast<Decl*>(allMethods[i]));
|
2007-10-14 08:58:41 +08:00
|
|
|
|
2007-09-11 04:33:04 +08:00
|
|
|
if (!Method) continue; // Already issued a diagnostic.
|
2007-10-06 02:00:57 +08:00
|
|
|
if (Method->isInstance()) {
|
2007-10-17 05:52:23 +08:00
|
|
|
/// Check for instance method of the same name with incompatible types
|
|
|
|
const ObjcMethodDecl *&PrevMethod = InsMap[Method->getSelector()];
|
|
|
|
bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
|
|
|
|
: false;
|
|
|
|
if (checkDuplicateMethods && PrevMethod && !match
|
|
|
|
|| checkIdenticalMethods && match) {
|
2007-10-06 02:00:57 +08:00
|
|
|
Diag(Method->getLocation(), diag::error_duplicate_method_decl,
|
2007-10-07 09:33:16 +08:00
|
|
|
Method->getSelector().getName());
|
2007-10-06 02:00:57 +08:00
|
|
|
Diag(PrevMethod->getLocation(), diag::err_previous_declaration);
|
2007-10-17 05:52:23 +08:00
|
|
|
} else {
|
2007-10-06 02:00:57 +08:00
|
|
|
insMethods.push_back(Method);
|
2007-10-17 05:52:23 +08:00
|
|
|
InsMap[Method->getSelector()] = Method;
|
|
|
|
/// The following allows us to typecheck messages to "id".
|
|
|
|
AddInstanceMethodToGlobalPool(Method);
|
2007-10-06 02:00:57 +08:00
|
|
|
}
|
2007-10-17 05:52:23 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/// Check for class method of the same name with incompatible types
|
|
|
|
const ObjcMethodDecl *&PrevMethod = ClsMap[Method->getSelector()];
|
|
|
|
bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod)
|
|
|
|
: false;
|
|
|
|
if (checkDuplicateMethods && PrevMethod && !match
|
|
|
|
|| checkIdenticalMethods && match) {
|
|
|
|
Diag(Method->getLocation(), diag::error_duplicate_method_decl,
|
|
|
|
Method->getSelector().getName());
|
|
|
|
Diag(PrevMethod->getLocation(), diag::err_previous_declaration);
|
|
|
|
} else {
|
2007-10-06 02:00:57 +08:00
|
|
|
clsMethods.push_back(Method);
|
2007-10-17 05:52:23 +08:00
|
|
|
ClsMap[Method->getSelector()] = Method;
|
|
|
|
/// The following allows us to typecheck messages to "id".
|
|
|
|
AddInstanceMethodToGlobalPool(Method);
|
|
|
|
}
|
2007-10-06 02:00:57 +08:00
|
|
|
}
|
2007-09-11 04:33:04 +08:00
|
|
|
}
|
2007-10-07 06:53:46 +08:00
|
|
|
|
|
|
|
if (ObjcInterfaceDecl *I = dyn_cast<ObjcInterfaceDecl>(ClassDecl)) {
|
2007-10-30 05:38:07 +08:00
|
|
|
I->addMethods(&insMethods[0], insMethods.size(),
|
|
|
|
&clsMethods[0], clsMethods.size(), AtEndLoc);
|
2007-10-07 06:53:46 +08:00
|
|
|
} else if (ObjcProtocolDecl *P = dyn_cast<ObjcProtocolDecl>(ClassDecl)) {
|
2007-10-30 05:38:07 +08:00
|
|
|
P->addMethods(&insMethods[0], insMethods.size(),
|
|
|
|
&clsMethods[0], clsMethods.size(), AtEndLoc);
|
2007-09-28 02:57:03 +08:00
|
|
|
}
|
2007-10-07 06:53:46 +08:00
|
|
|
else if (ObjcCategoryDecl *C = dyn_cast<ObjcCategoryDecl>(ClassDecl)) {
|
2007-10-30 05:38:07 +08:00
|
|
|
C->addMethods(&insMethods[0], insMethods.size(),
|
|
|
|
&clsMethods[0], clsMethods.size(), AtEndLoc);
|
2007-09-28 02:57:03 +08:00
|
|
|
}
|
2007-10-07 06:53:46 +08:00
|
|
|
else if (ObjcImplementationDecl *IC =
|
|
|
|
dyn_cast<ObjcImplementationDecl>(ClassDecl)) {
|
2007-10-30 05:38:07 +08:00
|
|
|
IC->addMethods(&insMethods[0], insMethods.size(),
|
|
|
|
&clsMethods[0], clsMethods.size(), AtEndLoc);
|
2007-10-07 06:53:46 +08:00
|
|
|
if (ObjcInterfaceDecl* IDecl = getObjCInterfaceDecl(IC->getIdentifier()))
|
|
|
|
ImplMethodsVsClassMethods(IC, IDecl);
|
|
|
|
} else {
|
|
|
|
ObjcCategoryImplDecl* CatImplClass = cast<ObjcCategoryImplDecl>(ClassDecl);
|
2007-10-30 05:38:07 +08:00
|
|
|
CatImplClass->addMethods(&insMethods[0], insMethods.size(),
|
|
|
|
&clsMethods[0], clsMethods.size(), AtEndLoc);
|
2007-10-07 06:53:46 +08:00
|
|
|
ObjcInterfaceDecl* IDecl = CatImplClass->getClassInterface();
|
|
|
|
// Find category interface decl and then check that all methods declared
|
|
|
|
// in this interface is implemented in the category @implementation.
|
|
|
|
if (IDecl) {
|
2007-10-15 02:27:41 +08:00
|
|
|
for (ObjcCategoryDecl *Categories = IDecl->getCategoryList();
|
2007-10-07 06:53:46 +08:00
|
|
|
Categories; Categories = Categories->getNextClassCategory()) {
|
2007-10-07 07:12:31 +08:00
|
|
|
if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
|
2007-10-07 06:53:46 +08:00
|
|
|
ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories);
|
|
|
|
break;
|
2007-10-03 00:38:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-09-11 04:33:04 +08:00
|
|
|
}
|
|
|
|
|
2007-10-27 04:53:56 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnMethodDeclaration(
|
|
|
|
SourceLocation MethodLoc, SourceLocation EndLoc,
|
2007-09-29 06:22:11 +08:00
|
|
|
tok::TokenKind MethodType, TypeTy *ReturnType, Selector Sel,
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
// optional arguments. The number of types/arguments is obtained
|
|
|
|
// from the Sel.getNumArgs().
|
|
|
|
TypeTy **ArgTypes, IdentifierInfo **ArgNames,
|
|
|
|
AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind) {
|
2007-09-13 02:23:47 +08:00
|
|
|
llvm::SmallVector<ParmVarDecl*, 16> Params;
|
2007-10-31 01:06:23 +08:00
|
|
|
|
2007-09-29 06:22:11 +08:00
|
|
|
for (unsigned i = 0; i < Sel.getNumArgs(); i++) {
|
2007-09-13 02:23:47 +08:00
|
|
|
// FIXME: arg->AttrList must be stored too!
|
2007-10-11 05:53:07 +08:00
|
|
|
QualType argType;
|
|
|
|
|
|
|
|
if (ArgTypes[i])
|
|
|
|
argType = QualType::getFromOpaquePtr(ArgTypes[i]);
|
|
|
|
else
|
2007-11-01 02:42:27 +08:00
|
|
|
argType = Context.getObjcIdType();
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
ParmVarDecl* Param = new ParmVarDecl(SourceLocation(/*FIXME*/), ArgNames[i],
|
2007-10-11 05:53:07 +08:00
|
|
|
argType, VarDecl::None, 0);
|
2007-09-13 02:23:47 +08:00
|
|
|
Params.push_back(Param);
|
|
|
|
}
|
2007-10-10 06:01:59 +08:00
|
|
|
QualType resultDeclType;
|
|
|
|
|
|
|
|
if (ReturnType)
|
|
|
|
resultDeclType = QualType::getFromOpaquePtr(ReturnType);
|
2007-10-11 05:53:07 +08:00
|
|
|
else // get the type for "id".
|
2007-11-01 02:42:27 +08:00
|
|
|
resultDeclType = Context.getObjcIdType();
|
2007-10-11 05:53:07 +08:00
|
|
|
|
2007-10-27 04:53:56 +08:00
|
|
|
ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, EndLoc, Sel,
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
resultDeclType, 0, -1, AttrList,
|
2007-09-30 02:24:58 +08:00
|
|
|
MethodType == tok::minus,
|
2007-10-04 08:45:27 +08:00
|
|
|
MethodDeclKind == tok::objc_optional ?
|
|
|
|
ObjcMethodDecl::Optional :
|
|
|
|
ObjcMethodDecl::Required);
|
2007-09-29 06:22:11 +08:00
|
|
|
ObjcMethod->setMethodParams(&Params[0], Sel.getNumArgs());
|
2007-09-18 05:07:36 +08:00
|
|
|
return ObjcMethod;
|
2007-09-13 02:23:47 +08:00
|
|
|
}
|
|
|
|
|
2007-09-16 02:49:24 +08:00
|
|
|
Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl,
|
2007-06-11 09:28:17 +08:00
|
|
|
DeclTy *lastEnumConst,
|
2007-01-25 15:29:02 +08:00
|
|
|
SourceLocation IdLoc, IdentifierInfo *Id,
|
2007-06-11 09:28:17 +08:00
|
|
|
SourceLocation EqualLoc, ExprTy *val) {
|
|
|
|
theEnumDecl = theEnumDecl; // silence unused warning.
|
|
|
|
EnumConstantDecl *LastEnumConst =
|
|
|
|
cast_or_null<EnumConstantDecl>(static_cast<Decl*>(lastEnumConst));
|
|
|
|
Expr *Val = static_cast<Expr*>(val);
|
2007-01-26 06:38:29 +08:00
|
|
|
|
2007-08-26 14:24:45 +08:00
|
|
|
// The scope passed in may not be a decl scope. Zip up the scope tree until
|
|
|
|
// we find one that is.
|
|
|
|
while ((S->getFlags() & Scope::DeclScope) == 0)
|
|
|
|
S = S->getParent();
|
|
|
|
|
2007-01-26 06:38:29 +08:00
|
|
|
// Verify that there isn't already something declared with this name in this
|
|
|
|
// scope.
|
2007-09-14 05:41:19 +08:00
|
|
|
if (ScopedDecl *PrevDecl = LookupScopedDecl(Id, Decl::IDNS_Ordinary,
|
|
|
|
IdLoc, S)) {
|
2007-01-26 06:38:29 +08:00
|
|
|
if (S->isDeclScope(PrevDecl)) {
|
|
|
|
if (isa<EnumConstantDecl>(PrevDecl))
|
|
|
|
Diag(IdLoc, diag::err_redefinition_of_enumerator, Id->getName());
|
|
|
|
else
|
|
|
|
Diag(IdLoc, diag::err_redefinition, Id->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
2007-06-11 09:28:17 +08:00
|
|
|
// FIXME: Don't leak memory: delete Val;
|
2007-01-26 06:38:29 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2007-06-11 09:28:17 +08:00
|
|
|
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::APSInt EnumVal(32);
|
2007-06-11 09:28:17 +08:00
|
|
|
QualType EltTy;
|
|
|
|
if (Val) {
|
2007-08-28 05:16:18 +08:00
|
|
|
// Make sure to promote the operand type to int.
|
|
|
|
UsualUnaryConversions(Val);
|
|
|
|
|
2007-06-11 09:28:17 +08:00
|
|
|
// C99 6.7.2.2p2: Make sure we have an integer constant expression.
|
|
|
|
SourceLocation ExpLoc;
|
2007-07-16 07:26:56 +08:00
|
|
|
if (!Val->isIntegerConstantExpr(EnumVal, Context, &ExpLoc)) {
|
2007-06-11 09:28:17 +08:00
|
|
|
Diag(ExpLoc, diag::err_enum_value_not_integer_constant_expr,
|
|
|
|
Id->getName());
|
|
|
|
// FIXME: Don't leak memory: delete Val;
|
2007-08-28 01:37:24 +08:00
|
|
|
Val = 0; // Just forget about it.
|
2007-08-30 00:03:41 +08:00
|
|
|
} else {
|
|
|
|
EltTy = Val->getType();
|
2007-06-11 09:28:17 +08:00
|
|
|
}
|
2007-08-28 01:37:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Val) {
|
|
|
|
if (LastEnumConst) {
|
|
|
|
// Assign the last value + 1.
|
|
|
|
EnumVal = LastEnumConst->getInitVal();
|
|
|
|
++EnumVal;
|
2007-08-28 05:16:18 +08:00
|
|
|
|
|
|
|
// Check for overflow on increment.
|
|
|
|
if (EnumVal < LastEnumConst->getInitVal())
|
|
|
|
Diag(IdLoc, diag::warn_enum_value_overflow);
|
|
|
|
|
2007-08-28 01:37:24 +08:00
|
|
|
EltTy = LastEnumConst->getType();
|
|
|
|
} else {
|
|
|
|
// First value, set to zero.
|
|
|
|
EltTy = Context.IntTy;
|
2007-09-04 10:45:27 +08:00
|
|
|
EnumVal.zextOrTrunc(
|
|
|
|
static_cast<uint32_t>(Context.getTypeSize(EltTy, IdLoc)));
|
2007-08-28 01:37:24 +08:00
|
|
|
}
|
2007-05-08 05:22:42 +08:00
|
|
|
}
|
2007-06-11 09:28:17 +08:00
|
|
|
|
|
|
|
EnumConstantDecl *New = new EnumConstantDecl(IdLoc, Id, EltTy, Val, EnumVal,
|
|
|
|
LastEnumConst);
|
2007-01-26 06:38:29 +08:00
|
|
|
|
|
|
|
// Register this decl in the current scope stack.
|
2007-09-14 02:10:37 +08:00
|
|
|
New->setNext(Id->getFETokenInfo<ScopedDecl>());
|
2007-01-26 06:38:29 +08:00
|
|
|
Id->setFETokenInfo(New);
|
|
|
|
S->AddDecl(New);
|
|
|
|
return New;
|
2007-01-25 15:29:02 +08:00
|
|
|
}
|
|
|
|
|
2007-09-16 02:49:24 +08:00
|
|
|
void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
|
2007-01-25 15:29:02 +08:00
|
|
|
DeclTy **Elements, unsigned NumElements) {
|
|
|
|
EnumDecl *Enum = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX));
|
|
|
|
assert(!Enum->isDefinition() && "Enum redefinitions can't reach here");
|
|
|
|
|
2007-08-28 13:10:31 +08:00
|
|
|
// TODO: If the result value doesn't fit in an int, it must be a long or long
|
|
|
|
// long value. ISO C does not support this, but GCC does as an extension,
|
|
|
|
// emit a warning.
|
2007-08-28 14:15:15 +08:00
|
|
|
unsigned IntWidth = Context.Target.getIntWidth(Enum->getLocation());
|
2007-08-28 13:10:31 +08:00
|
|
|
|
|
|
|
|
2007-08-28 14:15:15 +08:00
|
|
|
// Verify that all the values are okay, compute the size of the values, and
|
|
|
|
// reverse the list.
|
|
|
|
unsigned NumNegativeBits = 0;
|
|
|
|
unsigned NumPositiveBits = 0;
|
|
|
|
|
|
|
|
// Keep track of whether all elements have type int.
|
|
|
|
bool AllElementsInt = true;
|
|
|
|
|
2007-06-11 09:28:17 +08:00
|
|
|
EnumConstantDecl *EltList = 0;
|
2007-01-25 15:29:02 +08:00
|
|
|
for (unsigned i = 0; i != NumElements; ++i) {
|
|
|
|
EnumConstantDecl *ECD =
|
|
|
|
cast_or_null<EnumConstantDecl>(static_cast<Decl*>(Elements[i]));
|
|
|
|
if (!ECD) continue; // Already issued a diagnostic.
|
2007-08-28 13:27:00 +08:00
|
|
|
|
|
|
|
// If the enum value doesn't fit in an int, emit an extension warning.
|
|
|
|
assert(ECD->getInitVal().getBitWidth() >= IntWidth &&
|
|
|
|
"Should have promoted value to int");
|
|
|
|
const llvm::APSInt &InitVal = ECD->getInitVal();
|
|
|
|
if (InitVal.getBitWidth() > IntWidth) {
|
|
|
|
llvm::APSInt V(InitVal);
|
|
|
|
V.trunc(IntWidth);
|
|
|
|
V.extend(InitVal.getBitWidth());
|
|
|
|
if (V != InitVal)
|
|
|
|
Diag(ECD->getLocation(), diag::ext_enum_value_not_int,
|
|
|
|
InitVal.toString());
|
|
|
|
}
|
2007-08-28 14:15:15 +08:00
|
|
|
|
|
|
|
// Keep track of the size of positive and negative values.
|
|
|
|
if (InitVal.isUnsigned() || !InitVal.isNegative())
|
|
|
|
NumPositiveBits = std::max(NumPositiveBits, InitVal.getActiveBits());
|
|
|
|
else
|
|
|
|
NumNegativeBits = std::max(NumNegativeBits, InitVal.getMinSignedBits());
|
2007-06-11 09:28:17 +08:00
|
|
|
|
2007-08-28 14:15:15 +08:00
|
|
|
// Keep track of whether every enum element has type int (very commmon).
|
|
|
|
if (AllElementsInt)
|
|
|
|
AllElementsInt = ECD->getType() == Context.IntTy;
|
|
|
|
|
2007-06-11 09:28:17 +08:00
|
|
|
ECD->setNextDeclarator(EltList);
|
|
|
|
EltList = ECD;
|
2007-01-25 15:29:02 +08:00
|
|
|
}
|
|
|
|
|
2007-08-28 14:15:15 +08:00
|
|
|
// Figure out the type that should be used for this enum.
|
|
|
|
// FIXME: Support attribute(packed) on enums and -fshort-enums.
|
|
|
|
QualType BestType;
|
2007-08-30 01:31:48 +08:00
|
|
|
unsigned BestWidth;
|
2007-08-28 14:15:15 +08:00
|
|
|
|
|
|
|
if (NumNegativeBits) {
|
|
|
|
// If there is a negative value, figure out the smallest integer type (of
|
|
|
|
// int/long/longlong) that fits.
|
2007-08-30 01:31:48 +08:00
|
|
|
if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
|
2007-08-28 14:15:15 +08:00
|
|
|
BestType = Context.IntTy;
|
2007-08-30 01:31:48 +08:00
|
|
|
BestWidth = IntWidth;
|
|
|
|
} else {
|
|
|
|
BestWidth = Context.Target.getLongWidth(Enum->getLocation());
|
|
|
|
if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth)
|
2007-08-28 14:15:15 +08:00
|
|
|
BestType = Context.LongTy;
|
|
|
|
else {
|
2007-08-30 01:31:48 +08:00
|
|
|
BestWidth = Context.Target.getLongLongWidth(Enum->getLocation());
|
|
|
|
if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
|
2007-08-28 14:15:15 +08:00
|
|
|
Diag(Enum->getLocation(), diag::warn_enum_too_large);
|
|
|
|
BestType = Context.LongLongTy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If there is no negative value, figure out which of uint, ulong, ulonglong
|
|
|
|
// fits.
|
2007-08-30 01:31:48 +08:00
|
|
|
if (NumPositiveBits <= IntWidth) {
|
2007-08-28 14:15:15 +08:00
|
|
|
BestType = Context.UnsignedIntTy;
|
2007-08-30 01:31:48 +08:00
|
|
|
BestWidth = IntWidth;
|
|
|
|
} else if (NumPositiveBits <=
|
|
|
|
(BestWidth = Context.Target.getLongWidth(Enum->getLocation())))
|
2007-08-28 14:15:15 +08:00
|
|
|
BestType = Context.UnsignedLongTy;
|
|
|
|
else {
|
2007-08-30 01:31:48 +08:00
|
|
|
BestWidth = Context.Target.getLongLongWidth(Enum->getLocation());
|
|
|
|
assert(NumPositiveBits <= BestWidth &&
|
2007-08-28 14:15:15 +08:00
|
|
|
"How could an initializer get larger than ULL?");
|
|
|
|
BestType = Context.UnsignedLongLongTy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-30 01:31:48 +08:00
|
|
|
// Loop over all of the enumerator constants, changing their types to match
|
|
|
|
// the type of the enum if needed.
|
|
|
|
for (unsigned i = 0; i != NumElements; ++i) {
|
|
|
|
EnumConstantDecl *ECD =
|
|
|
|
cast_or_null<EnumConstantDecl>(static_cast<Decl*>(Elements[i]));
|
|
|
|
if (!ECD) continue; // Already issued a diagnostic.
|
|
|
|
|
|
|
|
// Standard C says the enumerators have int type, but we allow, as an
|
|
|
|
// extension, the enumerators to be larger than int size. If each
|
|
|
|
// enumerator value fits in an int, type it as an int, otherwise type it the
|
|
|
|
// same as the enumerator decl itself. This means that in "enum { X = 1U }"
|
|
|
|
// that X has type 'int', not 'unsigned'.
|
|
|
|
if (ECD->getType() == Context.IntTy)
|
|
|
|
continue; // Already int type.
|
|
|
|
|
|
|
|
// Determine whether the value fits into an int.
|
|
|
|
llvm::APSInt InitVal = ECD->getInitVal();
|
|
|
|
bool FitsInInt;
|
|
|
|
if (InitVal.isUnsigned() || !InitVal.isNegative())
|
|
|
|
FitsInInt = InitVal.getActiveBits() < IntWidth;
|
|
|
|
else
|
|
|
|
FitsInInt = InitVal.getMinSignedBits() <= IntWidth;
|
|
|
|
|
|
|
|
// If it fits into an integer type, force it. Otherwise force it to match
|
|
|
|
// the enum decl type.
|
|
|
|
QualType NewTy;
|
|
|
|
unsigned NewWidth;
|
|
|
|
bool NewSign;
|
|
|
|
if (FitsInInt) {
|
|
|
|
NewTy = Context.IntTy;
|
|
|
|
NewWidth = IntWidth;
|
|
|
|
NewSign = true;
|
|
|
|
} else if (ECD->getType() == BestType) {
|
|
|
|
// Already the right type!
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
NewTy = BestType;
|
|
|
|
NewWidth = BestWidth;
|
|
|
|
NewSign = BestType->isSignedIntegerType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust the APSInt value.
|
|
|
|
InitVal.extOrTrunc(NewWidth);
|
|
|
|
InitVal.setIsSigned(NewSign);
|
|
|
|
ECD->setInitVal(InitVal);
|
|
|
|
|
|
|
|
// Adjust the Expr initializer and type.
|
|
|
|
ECD->setInitExpr(new ImplicitCastExpr(NewTy, ECD->getInitExpr()));
|
|
|
|
ECD->setType(NewTy);
|
|
|
|
}
|
2007-08-28 14:15:15 +08:00
|
|
|
|
2007-08-29 02:24:31 +08:00
|
|
|
Enum->defineElements(EltList, BestType);
|
2007-01-25 15:29:02 +08:00
|
|
|
}
|
2007-01-24 07:42:53 +08:00
|
|
|
|
2007-03-22 05:08:52 +08:00
|
|
|
void Sema::AddTopLevelDecl(Decl *current, Decl *last) {
|
|
|
|
if (!current) return;
|
|
|
|
|
|
|
|
// If this is a top-level decl that is chained to some other (e.g. int A,B,C;)
|
|
|
|
// remember this in the LastInGroupList list.
|
2007-06-09 08:53:06 +08:00
|
|
|
if (last)
|
2007-03-22 05:08:52 +08:00
|
|
|
LastInGroupList.push_back((Decl*)last);
|
|
|
|
}
|
2007-06-11 08:35:03 +08:00
|
|
|
|
|
|
|
void Sema::HandleDeclAttribute(Decl *New, AttributeList *rawAttr) {
|
|
|
|
if (strcmp(rawAttr->getAttributeName()->getName(), "vector_size") == 0) {
|
|
|
|
if (ValueDecl *vDecl = dyn_cast<ValueDecl>(New)) {
|
2007-07-07 07:09:18 +08:00
|
|
|
QualType newType = HandleVectorTypeAttribute(vDecl->getType(), rawAttr);
|
2007-07-10 02:55:26 +08:00
|
|
|
if (!newType.isNull()) // install the new vector type into the decl
|
|
|
|
vDecl->setType(newType);
|
2007-06-11 08:35:03 +08:00
|
|
|
}
|
|
|
|
if (TypedefDecl *tDecl = dyn_cast<TypedefDecl>(New)) {
|
2007-07-07 07:09:18 +08:00
|
|
|
QualType newType = HandleVectorTypeAttribute(tDecl->getUnderlyingType(),
|
|
|
|
rawAttr);
|
2007-07-10 02:55:26 +08:00
|
|
|
if (!newType.isNull()) // install the new vector type into the decl
|
|
|
|
tDecl->setUnderlyingType(newType);
|
2007-06-11 08:35:03 +08:00
|
|
|
}
|
|
|
|
}
|
2007-07-19 02:00:27 +08:00
|
|
|
if (strcmp(rawAttr->getAttributeName()->getName(), "ocu_vector_type") == 0) {
|
2007-07-30 00:33:31 +08:00
|
|
|
if (TypedefDecl *tDecl = dyn_cast<TypedefDecl>(New))
|
|
|
|
HandleOCUVectorTypeAttribute(tDecl, rawAttr);
|
|
|
|
else
|
2007-07-19 02:00:27 +08:00
|
|
|
Diag(rawAttr->getAttributeLoc(),
|
|
|
|
diag::err_typecheck_ocu_vector_not_typedef);
|
|
|
|
}
|
2007-06-11 08:35:03 +08:00
|
|
|
// FIXME: add other attributes...
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix,
|
|
|
|
AttributeList *declarator_postfix) {
|
|
|
|
while (declspec_prefix) {
|
|
|
|
HandleDeclAttribute(New, declspec_prefix);
|
|
|
|
declspec_prefix = declspec_prefix->getNext();
|
|
|
|
}
|
|
|
|
while (declarator_postfix) {
|
|
|
|
HandleDeclAttribute(New, declarator_postfix);
|
|
|
|
declarator_postfix = declarator_postfix->getNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-30 00:33:31 +08:00
|
|
|
void Sema::HandleOCUVectorTypeAttribute(TypedefDecl *tDecl,
|
|
|
|
AttributeList *rawAttr) {
|
|
|
|
QualType curType = tDecl->getUnderlyingType();
|
2007-07-19 02:00:27 +08:00
|
|
|
// check the attribute arugments.
|
|
|
|
if (rawAttr->getNumArgs() != 1) {
|
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_wrong_number_arguments,
|
|
|
|
std::string("1"));
|
2007-07-30 00:33:31 +08:00
|
|
|
return;
|
2007-07-19 02:00:27 +08:00
|
|
|
}
|
|
|
|
Expr *sizeExpr = static_cast<Expr *>(rawAttr->getArg(0));
|
|
|
|
llvm::APSInt vecSize(32);
|
|
|
|
if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) {
|
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_vector_size_not_int,
|
|
|
|
sizeExpr->getSourceRange());
|
2007-07-30 00:33:31 +08:00
|
|
|
return;
|
2007-07-19 02:00:27 +08:00
|
|
|
}
|
|
|
|
// unlike gcc's vector_size attribute, we do not allow vectors to be defined
|
|
|
|
// in conjunction with complex types (pointers, arrays, functions, etc.).
|
|
|
|
Type *canonType = curType.getCanonicalType().getTypePtr();
|
|
|
|
if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) {
|
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_invalid_vector_type,
|
|
|
|
curType.getCanonicalType().getAsString());
|
2007-07-30 00:33:31 +08:00
|
|
|
return;
|
2007-07-19 02:00:27 +08:00
|
|
|
}
|
|
|
|
// unlike gcc's vector_size attribute, the size is specified as the
|
|
|
|
// number of elements, not the number of bytes.
|
2007-09-04 10:45:27 +08:00
|
|
|
unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
|
2007-07-19 02:00:27 +08:00
|
|
|
|
|
|
|
if (vectorSize == 0) {
|
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_zero_size,
|
|
|
|
sizeExpr->getSourceRange());
|
2007-07-30 00:33:31 +08:00
|
|
|
return;
|
2007-07-19 02:00:27 +08:00
|
|
|
}
|
2007-07-30 00:33:31 +08:00
|
|
|
// Instantiate/Install the vector type, the number of elements is > 0.
|
|
|
|
tDecl->setUnderlyingType(Context.getOCUVectorType(curType, vectorSize));
|
|
|
|
// Remember this typedef decl, we will need it later for diagnostics.
|
|
|
|
OCUVectorDecls.push_back(tDecl);
|
2007-07-19 02:00:27 +08:00
|
|
|
}
|
|
|
|
|
2007-07-07 07:09:18 +08:00
|
|
|
QualType Sema::HandleVectorTypeAttribute(QualType curType,
|
2007-07-14 06:13:22 +08:00
|
|
|
AttributeList *rawAttr) {
|
2007-07-07 07:09:18 +08:00
|
|
|
// check the attribute arugments.
|
2007-06-11 08:35:03 +08:00
|
|
|
if (rawAttr->getNumArgs() != 1) {
|
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_wrong_number_arguments,
|
|
|
|
std::string("1"));
|
2007-07-07 07:09:18 +08:00
|
|
|
return QualType();
|
2007-06-11 08:35:03 +08:00
|
|
|
}
|
|
|
|
Expr *sizeExpr = static_cast<Expr *>(rawAttr->getArg(0));
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::APSInt vecSize(32);
|
2007-07-16 07:26:56 +08:00
|
|
|
if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) {
|
2007-06-11 08:35:03 +08:00
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_vector_size_not_int,
|
|
|
|
sizeExpr->getSourceRange());
|
2007-07-07 07:09:18 +08:00
|
|
|
return QualType();
|
2007-06-11 08:35:03 +08:00
|
|
|
}
|
|
|
|
// navigate to the base type - we need to provide for vector pointers,
|
|
|
|
// vector arrays, and functions returning vectors.
|
|
|
|
Type *canonType = curType.getCanonicalType().getTypePtr();
|
|
|
|
|
2007-07-19 02:00:27 +08:00
|
|
|
if (canonType->isPointerType() || canonType->isArrayType() ||
|
|
|
|
canonType->isFunctionType()) {
|
|
|
|
assert(1 && "HandleVector(): Complex type construction unimplemented");
|
|
|
|
/* FIXME: rebuild the type from the inside out, vectorizing the inner type.
|
|
|
|
do {
|
|
|
|
if (PointerType *PT = dyn_cast<PointerType>(canonType))
|
|
|
|
canonType = PT->getPointeeType().getTypePtr();
|
|
|
|
else if (ArrayType *AT = dyn_cast<ArrayType>(canonType))
|
|
|
|
canonType = AT->getElementType().getTypePtr();
|
|
|
|
else if (FunctionType *FT = dyn_cast<FunctionType>(canonType))
|
|
|
|
canonType = FT->getResultType().getTypePtr();
|
|
|
|
} while (canonType->isPointerType() || canonType->isArrayType() ||
|
|
|
|
canonType->isFunctionType());
|
|
|
|
*/
|
2007-06-11 08:35:03 +08:00
|
|
|
}
|
|
|
|
// the base type must be integer or float.
|
|
|
|
if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) {
|
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_invalid_vector_type,
|
|
|
|
curType.getCanonicalType().getAsString());
|
2007-07-07 07:09:18 +08:00
|
|
|
return QualType();
|
2007-06-11 08:35:03 +08:00
|
|
|
}
|
2007-09-04 10:45:27 +08:00
|
|
|
unsigned typeSize = static_cast<unsigned>(
|
|
|
|
Context.getTypeSize(curType, rawAttr->getAttributeLoc()));
|
2007-07-07 07:09:18 +08:00
|
|
|
// vecSize is specified in bytes - convert to bits.
|
2007-09-04 10:45:27 +08:00
|
|
|
unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8);
|
2007-07-07 07:09:18 +08:00
|
|
|
|
|
|
|
// the vector size needs to be an integral multiple of the type size.
|
|
|
|
if (vectorSize % typeSize) {
|
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_invalid_size,
|
|
|
|
sizeExpr->getSourceRange());
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
if (vectorSize == 0) {
|
|
|
|
Diag(rawAttr->getAttributeLoc(), diag::err_attribute_zero_size,
|
|
|
|
sizeExpr->getSourceRange());
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
// Since OpenCU requires 3 element vectors (OpenCU 5.1.2), we don't restrict
|
|
|
|
// the number of elements to be a power of two (unlike GCC).
|
|
|
|
// Instantiate the vector type, the number of elements is > 0.
|
2007-07-19 02:00:27 +08:00
|
|
|
return Context.getVectorType(curType, vectorSize/typeSize);
|
2007-06-11 08:35:03 +08:00
|
|
|
}
|
|
|
|
|