2007-07-11 21:01:13 +04:00
|
|
|
//===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 22:59:25 +03:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-07-11 21:01:13 +04:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements semantic analysis for declarations.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Sema.h"
|
2008-07-03 08:20:39 +04:00
|
|
|
#include "clang/AST/APValue.h"
|
2008-02-06 03:51:33 +03:00
|
|
|
#include "clang/AST/ASTConsumer.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 09:35:13 +04:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2008-06-26 22:38:35 +04:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
2008-08-11 07:45:03 +04:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2008-01-31 02:46:05 +03:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
|
2008-02-06 03:51:33 +03:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2008-01-31 02:46:05 +03:00
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
#include "llvm/ADT/SmallSet.h"
|
|
|
|
using namespace clang;
|
|
|
|
|
2008-08-01 14:35:27 +04:00
|
|
|
Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) {
|
2008-04-02 18:35:35 +04:00
|
|
|
Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, false);
|
|
|
|
|
2008-04-14 01:07:44 +04:00
|
|
|
if (IIDecl && (isa<TypedefDecl>(IIDecl) ||
|
|
|
|
isa<ObjCInterfaceDecl>(IIDecl) ||
|
|
|
|
isa<TagDecl>(IIDecl)))
|
2007-10-12 20:34:10 +04:00
|
|
|
return IIDecl;
|
2007-09-07 01:24:23 +04:00
|
|
|
return 0;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-07-01 14:37:29 +04:00
|
|
|
DeclContext *Sema::getDCParent(DeclContext *DC) {
|
|
|
|
// If CurContext is a ObjC method, getParent() will return NULL.
|
|
|
|
if (isa<ObjCMethodDecl>(DC))
|
|
|
|
return Context.getTranslationUnitDecl();
|
|
|
|
|
|
|
|
// A C++ inline method is parsed *after* the topmost class it was declared in
|
|
|
|
// is fully parsed (it's "complete").
|
|
|
|
// The parsing of a C++ inline method happens at the declaration context of
|
|
|
|
// the topmost (non-nested) class it is declared in.
|
|
|
|
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
|
|
|
|
assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record.");
|
|
|
|
DC = MD->getParent();
|
|
|
|
while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getParent()))
|
|
|
|
DC = RD;
|
|
|
|
|
|
|
|
// Return the declaration context of the topmost class the inline method is
|
|
|
|
// declared in.
|
|
|
|
return DC;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DC->getParent();
|
|
|
|
}
|
|
|
|
|
2008-04-22 22:39:57 +04:00
|
|
|
void Sema::PushDeclContext(DeclContext *DC) {
|
2008-07-01 14:37:29 +04:00
|
|
|
assert(getDCParent(DC) == CurContext &&
|
|
|
|
"The next DeclContext should be directly contained in the current one.");
|
2008-04-22 22:39:57 +04:00
|
|
|
CurContext = DC;
|
2008-04-04 10:12:32 +04:00
|
|
|
}
|
|
|
|
|
2008-04-06 08:47:34 +04:00
|
|
|
void Sema::PopDeclContext() {
|
|
|
|
assert(CurContext && "DeclContext imbalance!");
|
2008-07-01 14:37:29 +04:00
|
|
|
CurContext = getDCParent(CurContext);
|
2008-04-04 10:12:32 +04:00
|
|
|
}
|
|
|
|
|
2008-04-12 04:47:19 +04:00
|
|
|
/// Add this decl to the scope shadowed decl chains.
|
|
|
|
void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
|
|
|
|
S->AddDecl(D);
|
2008-05-10 03:39:43 +04:00
|
|
|
|
|
|
|
// C++ [basic.scope]p4:
|
|
|
|
// -- exactly one declaration shall declare a class name or
|
|
|
|
// enumeration name that is not a typedef name and the other
|
|
|
|
// declarations shall all refer to the same object or
|
|
|
|
// enumerator, or all refer to functions and function templates;
|
|
|
|
// in this case the class name or enumeration name is hidden.
|
|
|
|
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
|
|
|
// We are pushing the name of a tag (enum or class).
|
2008-07-17 21:49:50 +04:00
|
|
|
IdentifierResolver::iterator
|
|
|
|
I = IdResolver.begin(TD->getIdentifier(),
|
|
|
|
TD->getDeclContext(), false/*LookInParentCtx*/);
|
|
|
|
if (I != IdResolver.end() &&
|
|
|
|
IdResolver.isDeclInScope(*I, TD->getDeclContext(), S)) {
|
2008-05-10 03:39:43 +04:00
|
|
|
// There is already a declaration with the same name in the same
|
|
|
|
// scope. It must be found before we find the new declaration,
|
|
|
|
// so swap the order on the shadowed declaration chain.
|
|
|
|
|
2008-07-17 21:49:50 +04:00
|
|
|
IdResolver.AddShadowedDecl(TD, *I);
|
2008-05-10 03:39:43 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IdResolver.AddDecl(D);
|
2008-04-12 04:47:19 +04:00
|
|
|
}
|
|
|
|
|
2007-10-10 02:01:59 +04:00
|
|
|
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
|
2007-08-26 10:24:45 +04:00
|
|
|
if (S->decl_empty()) return;
|
|
|
|
assert((S->getFlags() & Scope::DeclScope) &&"Scope shouldn't contain decls!");
|
2008-05-10 03:39:43 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
|
|
|
|
I != E; ++I) {
|
2007-09-13 22:10:37 +04:00
|
|
|
Decl *TmpD = static_cast<Decl*>(*I);
|
|
|
|
assert(TmpD && "This decl didn't get pushed??");
|
2008-06-10 05:32:09 +04:00
|
|
|
|
|
|
|
if (isa<CXXFieldDecl>(TmpD)) continue;
|
|
|
|
|
|
|
|
assert(isa<ScopedDecl>(TmpD) && "Decl isn't ScopedDecl?");
|
|
|
|
ScopedDecl *D = cast<ScopedDecl>(TmpD);
|
2007-09-13 22:10:37 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
IdentifierInfo *II = D->getIdentifier();
|
|
|
|
if (!II) continue;
|
|
|
|
|
2008-09-03 22:03:35 +04:00
|
|
|
// We only want to remove the decls from the identifier decl chains for
|
|
|
|
// local scopes, when inside a function/method.
|
2008-06-10 05:32:09 +04:00
|
|
|
if (S->getFnParent() != 0)
|
|
|
|
IdResolver.RemoveDecl(D);
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2008-06-10 05:32:09 +04:00
|
|
|
// Chain this decl to the containing DeclContext.
|
|
|
|
D->setNext(CurContext->getDeclChain());
|
|
|
|
CurContext->setDeclChain(D);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-02 03:04:06 +04:00
|
|
|
/// getObjCInterfaceDecl - Look up a for a class declaration in the scope.
|
|
|
|
/// return 0 if one not found.
|
|
|
|
ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
|
2008-04-02 22:30:49 +04:00
|
|
|
// The third "scope" argument is 0 since we aren't enabling lazy built-in
|
|
|
|
// creation from this context.
|
|
|
|
Decl *IDecl = LookupDecl(Id, Decl::IDNS_Ordinary, 0, false);
|
2007-10-12 23:38:20 +04:00
|
|
|
|
2008-04-02 18:35:35 +04:00
|
|
|
return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
|
2007-10-12 23:38:20 +04:00
|
|
|
}
|
|
|
|
|
2008-04-02 03:04:06 +04:00
|
|
|
/// LookupDecl - Look up the inner-most declaration in the specified
|
2007-07-11 21:01:13 +04:00
|
|
|
/// namespace.
|
2008-04-02 18:35:35 +04:00
|
|
|
Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI,
|
|
|
|
Scope *S, bool enableLazyBuiltinCreation) {
|
2007-07-11 21:01:13 +04:00
|
|
|
if (II == 0) return 0;
|
2008-04-14 01:07:44 +04:00
|
|
|
unsigned NS = NSI;
|
|
|
|
if (getLangOptions().CPlusPlus && (NS & Decl::IDNS_Ordinary))
|
|
|
|
NS |= Decl::IDNS_Tag;
|
2008-04-11 11:00:53 +04:00
|
|
|
|
2007-07-11 21:01:13 +04: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.
|
2008-05-10 03:39:43 +04:00
|
|
|
for (IdentifierResolver::iterator
|
2008-07-17 21:49:50 +04:00
|
|
|
I = IdResolver.begin(II, CurContext), E = IdResolver.end(); I != E; ++I)
|
2008-05-10 03:39:43 +04:00
|
|
|
if ((*I)->getIdentifierNamespace() & NS)
|
|
|
|
return *I;
|
2008-04-11 11:00:53 +04:00
|
|
|
|
2007-07-11 21:01:13 +04: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.
|
2008-04-14 01:07:44 +04:00
|
|
|
if (NS & Decl::IDNS_Ordinary) {
|
2008-04-02 18:35:35 +04:00
|
|
|
if (enableLazyBuiltinCreation) {
|
|
|
|
// If this is a builtin on this (or all) targets, create the decl.
|
|
|
|
if (unsigned BuiltinID = II->getBuiltinID())
|
|
|
|
return LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, S);
|
|
|
|
}
|
2008-04-02 03:04:06 +04:00
|
|
|
if (getLangOptions().ObjC1) {
|
|
|
|
// @interface and @compatibility_alias introduce typedef-like names.
|
|
|
|
// Unlike typedef's, they can only be introduced at file-scope (and are
|
2008-04-02 04:39:51 +04:00
|
|
|
// therefore not scoped decls). They can, however, be shadowed by
|
2008-04-02 03:04:06 +04:00
|
|
|
// other names in IDNS_Ordinary.
|
2008-04-02 22:30:49 +04:00
|
|
|
ObjCInterfaceDeclsTy::iterator IDI = ObjCInterfaceDecls.find(II);
|
|
|
|
if (IDI != ObjCInterfaceDecls.end())
|
|
|
|
return IDI->second;
|
2008-04-02 03:04:06 +04:00
|
|
|
ObjCAliasTy::iterator I = ObjCAliasDecls.find(II);
|
|
|
|
if (I != ObjCAliasDecls.end())
|
|
|
|
return I->second->getClassInterface();
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-05-06 02:18:14 +04:00
|
|
|
void Sema::InitBuiltinVaListType() {
|
2007-10-16 00:28:48 +04:00
|
|
|
if (!Context.getBuiltinVaListType().isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
|
2008-04-02 18:35:35 +04:00
|
|
|
Decl *VaDecl = LookupDecl(VaIdent, Decl::IDNS_Ordinary, TUScope);
|
2007-10-19 02:17:45 +04:00
|
|
|
TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
|
2007-10-16 00:28:48 +04:00
|
|
|
Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
/// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope.
|
|
|
|
/// lazily create a decl for it.
|
2007-10-11 03:42:28 +04:00
|
|
|
ScopedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
|
|
|
|
Scope *S) {
|
2007-07-11 21:01:13 +04:00
|
|
|
Builtin::ID BID = (Builtin::ID)bid;
|
|
|
|
|
2007-10-16 00:28:48 +04:00
|
|
|
if (BID == Builtin::BI__builtin_va_start ||
|
2008-05-06 02:18:14 +04:00
|
|
|
BID == Builtin::BI__builtin_va_copy ||
|
2008-07-09 21:26:36 +04:00
|
|
|
BID == Builtin::BI__builtin_va_end ||
|
|
|
|
BID == Builtin::BI__builtin_stdarg_start)
|
2007-10-16 00:28:48 +04:00
|
|
|
InitBuiltinVaListType();
|
|
|
|
|
2007-10-11 05:00:40 +04:00
|
|
|
QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context);
|
2008-04-17 18:47:13 +04:00
|
|
|
FunctionDecl *New = FunctionDecl::Create(Context,
|
|
|
|
Context.getTranslationUnitDecl(),
|
2008-04-04 10:12:32 +04:00
|
|
|
SourceLocation(), II, R,
|
2008-03-16 00:24:04 +03:00
|
|
|
FunctionDecl::Extern, false, 0);
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2008-05-06 02:18:14 +04:00
|
|
|
// Create Decl objects for each parameter, adding them to the
|
|
|
|
// FunctionDecl.
|
|
|
|
if (FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(R)) {
|
|
|
|
llvm::SmallVector<ParmVarDecl*, 16> Params;
|
|
|
|
for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i)
|
|
|
|
Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
|
|
|
|
FT->getArgType(i), VarDecl::None, 0,
|
|
|
|
0));
|
|
|
|
New->setParams(&Params[0], Params.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-04-11 11:00:53 +04:00
|
|
|
// TUScope is the translation-unit scope to insert this function into.
|
2008-05-10 03:39:43 +04:00
|
|
|
PushOnScopeChains(New, TUScope);
|
2007-07-11 21:01:13 +04:00
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
|
|
|
///
|
2008-04-02 03:04:06 +04:00
|
|
|
TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
|
2007-07-11 21:01:13 +04: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;
|
|
|
|
}
|
|
|
|
|
2008-07-25 22:44:27 +04:00
|
|
|
// If the typedef types are not identical, reject them in all languages and
|
|
|
|
// with any extensions enabled.
|
|
|
|
if (Old->getUnderlyingType() != New->getUnderlyingType() &&
|
|
|
|
Context.getCanonicalType(Old->getUnderlyingType()) !=
|
|
|
|
Context.getCanonicalType(New->getUnderlyingType())) {
|
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_typedef,
|
|
|
|
New->getUnderlyingType().getAsString(),
|
|
|
|
Old->getUnderlyingType().getAsString());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
return Old;
|
|
|
|
}
|
|
|
|
|
2007-10-31 21:42:27 +03:00
|
|
|
// Allow multiple definitions for ObjC built-in typedefs.
|
|
|
|
// FIXME: Verify the underlying types are equivalent!
|
2008-01-07 22:49:32 +03:00
|
|
|
if (getLangOptions().ObjC1 && isBuiltinObjCType(New))
|
2007-10-31 21:42:27 +03:00
|
|
|
return Old;
|
2008-06-11 10:20:39 +04:00
|
|
|
|
|
|
|
if (getLangOptions().Microsoft) return New;
|
|
|
|
|
2008-01-31 02:46:05 +03:00
|
|
|
// Redeclaration of a type is a constraint violation (6.7.2.3p1).
|
|
|
|
// Apparently GCC, Intel, and Sun all silently ignore the redeclaration if
|
|
|
|
// *either* declaration is in a system header. The code below implements
|
|
|
|
// this adhoc compatibility rule. FIXME: The following code will not
|
|
|
|
// work properly when compiling ".i" files (containing preprocessed output).
|
|
|
|
SourceManager &SrcMgr = Context.getSourceManager();
|
2008-08-29 21:02:23 +04:00
|
|
|
if (SrcMgr.isInSystemHeader(Old->getLocation()))
|
|
|
|
return New;
|
|
|
|
if (SrcMgr.isInSystemHeader(New->getLocation()))
|
|
|
|
return New;
|
2008-06-11 10:20:39 +04:00
|
|
|
|
2008-05-24 01:28:18 +04:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
2007-07-11 21:01:13 +04:00
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2008-06-26 22:38:35 +04:00
|
|
|
/// DeclhasAttr - returns true if decl Declaration already has the target
|
|
|
|
/// attribute.
|
2008-03-03 06:28:21 +03:00
|
|
|
static bool DeclHasAttr(const Decl *decl, const Attr *target) {
|
|
|
|
for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext())
|
|
|
|
if (attr->getKind() == target->getKind())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// MergeAttributes - append attributes from the Old decl to the New one.
|
|
|
|
static void MergeAttributes(Decl *New, Decl *Old) {
|
|
|
|
Attr *attr = const_cast<Attr*>(Old->getAttrs()), *tmp;
|
|
|
|
|
|
|
|
while (attr) {
|
|
|
|
tmp = attr;
|
|
|
|
attr = attr->getNext();
|
|
|
|
|
|
|
|
if (!DeclHasAttr(New, tmp)) {
|
|
|
|
New->addAttr(tmp);
|
|
|
|
} else {
|
|
|
|
tmp->setNext(0);
|
|
|
|
delete(tmp);
|
|
|
|
}
|
|
|
|
}
|
2008-06-02 02:53:53 +04:00
|
|
|
|
|
|
|
Old->invalidateAttrs();
|
2008-03-03 06:28:21 +03:00
|
|
|
}
|
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
/// MergeFunctionDecl - We just parsed a function 'New' from
|
|
|
|
/// declarator D 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.
|
2008-04-21 06:02:58 +04:00
|
|
|
/// Redeclaration will be set true if thisNew is a redeclaration OldD.
|
|
|
|
FunctionDecl *
|
|
|
|
Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
|
|
|
|
Redeclaration = false;
|
2007-07-11 21:01:13 +04: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;
|
|
|
|
}
|
2008-04-08 08:40:51 +04:00
|
|
|
|
2008-04-07 03:10:54 +04:00
|
|
|
QualType OldQType = Context.getCanonicalType(Old->getType());
|
|
|
|
QualType NewQType = Context.getCanonicalType(New->getType());
|
2007-11-20 22:04:50 +03:00
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
// C++ [dcl.fct]p3:
|
|
|
|
// All declarations for a function shall agree exactly in both the
|
|
|
|
// return type and the parameter-type-list.
|
2008-04-21 06:02:58 +04:00
|
|
|
if (getLangOptions().CPlusPlus && OldQType == NewQType) {
|
|
|
|
MergeAttributes(New, Old);
|
|
|
|
Redeclaration = true;
|
2008-04-08 08:40:51 +04:00
|
|
|
return MergeCXXFunctionDecl(New, Old);
|
2008-04-21 06:02:58 +04:00
|
|
|
}
|
2008-04-08 08:40:51 +04:00
|
|
|
|
|
|
|
// C: Function types need to be compatible, not identical. This handles
|
2008-01-14 23:51:29 +03:00
|
|
|
// duplicate function decls like "void f(int); void f(enum X);" properly.
|
2008-04-08 08:40:51 +04:00
|
|
|
if (!getLangOptions().CPlusPlus &&
|
2008-08-22 04:56:42 +04:00
|
|
|
Context.typesAreCompatible(OldQType, NewQType)) {
|
2008-04-21 06:02:58 +04:00
|
|
|
MergeAttributes(New, Old);
|
|
|
|
Redeclaration = true;
|
2008-01-14 23:51:29 +03:00
|
|
|
return New;
|
2008-04-08 08:40:51 +04:00
|
|
|
}
|
2007-11-06 09:07:26 +03:00
|
|
|
|
2008-01-16 18:01:34 +03:00
|
|
|
// A function that has already been declared has been redeclared or defined
|
|
|
|
// with a different type- show appropriate diagnostic
|
2008-04-04 18:32:09 +04:00
|
|
|
diag::kind PrevDiag;
|
2008-04-21 06:02:58 +04:00
|
|
|
if (Old->isThisDeclarationADefinition())
|
2008-04-04 18:32:09 +04:00
|
|
|
PrevDiag = diag::err_previous_definition;
|
|
|
|
else if (Old->isImplicit())
|
|
|
|
PrevDiag = diag::err_previous_implicit_declaration;
|
2008-04-08 08:40:51 +04:00
|
|
|
else
|
2008-04-04 18:32:09 +04:00
|
|
|
PrevDiag = diag::err_previous_declaration;
|
2008-01-16 18:01:34 +03:00
|
|
|
|
2007-07-11 21:01:13 +04: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; ...
|
2008-01-16 18:01:34 +03:00
|
|
|
Diag(New->getLocation(), diag::err_conflicting_types, New->getName());
|
|
|
|
Diag(Old->getLocation(), PrevDiag);
|
2007-07-11 21:01:13 +04:00
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2008-08-08 21:50:35 +04:00
|
|
|
/// Predicate for C "tentative" external object definitions (C99 6.9.2).
|
2008-08-10 19:28:06 +04:00
|
|
|
static bool isTentativeDefinition(VarDecl *VD) {
|
2008-08-08 21:50:35 +04:00
|
|
|
if (VD->isFileVarDecl())
|
|
|
|
return (!VD->getInit() &&
|
|
|
|
(VD->getStorageClass() == VarDecl::None ||
|
|
|
|
VD->getStorageClass() == VarDecl::Static));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// CheckForFileScopedRedefinitions - Make sure we forgo redefinition errors
|
|
|
|
/// when dealing with C "tentative" external object definitions (C99 6.9.2).
|
|
|
|
void Sema::CheckForFileScopedRedefinitions(Scope *S, VarDecl *VD) {
|
|
|
|
bool VDIsTentative = isTentativeDefinition(VD);
|
2008-08-10 19:20:13 +04:00
|
|
|
bool VDIsIncompleteArray = VD->getType()->isIncompleteArrayType();
|
2008-08-08 21:50:35 +04:00
|
|
|
|
|
|
|
for (IdentifierResolver::iterator
|
|
|
|
I = IdResolver.begin(VD->getIdentifier(),
|
|
|
|
VD->getDeclContext(), false/*LookInParentCtx*/),
|
|
|
|
E = IdResolver.end(); I != E; ++I) {
|
|
|
|
if (*I != VD && IdResolver.isDeclInScope(*I, VD->getDeclContext(), S)) {
|
|
|
|
VarDecl *OldDecl = dyn_cast<VarDecl>(*I);
|
|
|
|
|
2008-08-10 19:20:13 +04:00
|
|
|
// Handle the following case:
|
|
|
|
// int a[10];
|
|
|
|
// int a[]; - the code below makes sure we set the correct type.
|
|
|
|
// int a[11]; - this is an error, size isn't 10.
|
|
|
|
if (OldDecl && VDIsTentative && VDIsIncompleteArray &&
|
|
|
|
OldDecl->getType()->isConstantArrayType())
|
|
|
|
VD->setType(OldDecl->getType());
|
|
|
|
|
2008-08-08 21:50:35 +04:00
|
|
|
// Check for "tentative" definitions. We can't accomplish this in
|
|
|
|
// MergeVarDecl since the initializer hasn't been attached.
|
|
|
|
if (!OldDecl || isTentativeDefinition(OldDecl) || VDIsTentative)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Handle __private_extern__ just like extern.
|
|
|
|
if (OldDecl->getStorageClass() != VarDecl::Extern &&
|
|
|
|
OldDecl->getStorageClass() != VarDecl::PrivateExtern &&
|
|
|
|
VD->getStorageClass() != VarDecl::Extern &&
|
|
|
|
VD->getStorageClass() != VarDecl::PrivateExtern) {
|
|
|
|
Diag(VD->getLocation(), diag::err_redefinition, VD->getName());
|
|
|
|
Diag(OldDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
/// 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.
|
|
|
|
///
|
2008-08-08 21:50:35 +04:00
|
|
|
/// Tentative definition rules (C99 6.9.2p2) are checked by
|
|
|
|
/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
|
|
|
|
/// definitions here, since the initializer hasn't been attached.
|
2007-07-11 21:01:13 +04:00
|
|
|
///
|
2008-04-02 03:04:06 +04:00
|
|
|
VarDecl *Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
|
2007-07-11 21:01:13 +04: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;
|
|
|
|
}
|
2008-03-03 06:28:21 +03:00
|
|
|
|
|
|
|
MergeAttributes(New, Old);
|
|
|
|
|
2008-01-30 03:44:01 +03:00
|
|
|
// Verify the types match.
|
2008-04-07 03:10:54 +04:00
|
|
|
QualType OldCType = Context.getCanonicalType(Old->getType());
|
|
|
|
QualType NewCType = Context.getCanonicalType(New->getType());
|
2008-08-09 20:04:40 +04:00
|
|
|
if (OldCType != NewCType && !Context.typesAreCompatible(OldCType, NewCType)) {
|
2008-01-30 03:44:01 +03:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
// C99 6.2.2p4: Check if we have a static decl followed by a non-static.
|
|
|
|
if (New->getStorageClass() == VarDecl::Static &&
|
|
|
|
(Old->getStorageClass() == VarDecl::None ||
|
|
|
|
Old->getStorageClass() == VarDecl::Extern)) {
|
|
|
|
Diag(New->getLocation(), diag::err_static_non_static, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
// C99 6.2.2p4: Check if we have a non-static decl followed by a static.
|
|
|
|
if (New->getStorageClass() != VarDecl::Static &&
|
|
|
|
Old->getStorageClass() == VarDecl::Static) {
|
|
|
|
Diag(New->getLocation(), diag::err_non_static_static, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
return New;
|
|
|
|
}
|
2008-08-08 21:50:35 +04:00
|
|
|
// File scoped variables are analyzed in FinalizeDeclaratorGroup.
|
|
|
|
if (!New->isFileVarDecl()) {
|
2007-07-11 21:01:13 +04:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition, New->getName());
|
|
|
|
Diag(Old->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
/// CheckParmsForFunctionDef - Check that the parameters of the given
|
|
|
|
/// function are appropriate for the definition of a function. This
|
|
|
|
/// takes care of any checks that cannot be performed on the
|
|
|
|
/// declaration itself, e.g., that the types of each of the function
|
|
|
|
/// parameters are complete.
|
|
|
|
bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
|
|
|
|
bool HasInvalidParm = false;
|
|
|
|
for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
|
|
|
|
ParmVarDecl *Param = FD->getParamDecl(p);
|
|
|
|
|
|
|
|
// C99 6.7.5.3p4: the parameters in a parameter type list in a
|
|
|
|
// function declarator that is part of a function definition of
|
|
|
|
// that function shall not have incomplete type.
|
|
|
|
if (Param->getType()->isIncompleteType() &&
|
|
|
|
!Param->isInvalidDecl()) {
|
|
|
|
Diag(Param->getLocation(), diag::err_typecheck_decl_incomplete_type,
|
|
|
|
Param->getType().getAsString());
|
|
|
|
Param->setInvalidDecl();
|
|
|
|
HasInvalidParm = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return HasInvalidParm;
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04: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(...);
|
|
|
|
|
2007-11-18 00:37:36 +03:00
|
|
|
return dyn_cast_or_null<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-01-11 01:15:12 +03:00
|
|
|
bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) {
|
2007-09-02 06:04:30 +04:00
|
|
|
// Get the type before calling CheckSingleAssignmentConstraints(), since
|
|
|
|
// it can promote the expression.
|
2008-01-04 21:04:52 +03:00
|
|
|
QualType InitType = Init->getType();
|
2007-09-02 06:04:30 +04:00
|
|
|
|
2008-01-04 21:04:52 +03:00
|
|
|
AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init);
|
|
|
|
return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
|
|
|
|
InitType, Init, "initializing");
|
2007-09-02 06:04:30 +04:00
|
|
|
}
|
|
|
|
|
2008-01-22 03:55:40 +03:00
|
|
|
bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) {
|
2008-08-04 11:31:14 +04:00
|
|
|
const ArrayType *AT = Context.getAsArrayType(DeclT);
|
|
|
|
|
|
|
|
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
|
2008-01-22 03:55:40 +03:00
|
|
|
// C99 6.7.8p14. We have an array of character type with unknown size
|
|
|
|
// being initialized to a string literal.
|
|
|
|
llvm::APSInt ConstVal(32);
|
|
|
|
ConstVal = strLiteral->getByteLength() + 1;
|
|
|
|
// Return a new array type (C99 6.7.8p22).
|
2008-02-15 21:16:39 +03:00
|
|
|
DeclT = Context.getConstantArrayType(IAT->getElementType(), ConstVal,
|
2008-01-22 03:55:40 +03:00
|
|
|
ArrayType::Normal, 0);
|
2008-08-04 11:31:14 +04:00
|
|
|
} else {
|
|
|
|
const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);
|
2008-01-22 03:55:40 +03:00
|
|
|
// C99 6.7.8p14. We have an array of character type with known size.
|
2008-08-04 11:31:14 +04:00
|
|
|
// FIXME: Avoid truncation for 64-bit length strings.
|
|
|
|
if (strLiteral->getByteLength() > (unsigned)CAT->getSize().getZExtValue())
|
2008-01-22 03:55:40 +03:00
|
|
|
Diag(strLiteral->getSourceRange().getBegin(),
|
|
|
|
diag::warn_initializer_string_for_char_array_too_long,
|
|
|
|
strLiteral->getSourceRange());
|
|
|
|
}
|
|
|
|
// Set type from "char *" to "constant array of char".
|
|
|
|
strLiteral->setType(DeclT);
|
|
|
|
// For now, we always return false (meaning success).
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringLiteral *Sema::IsStringLiteralInit(Expr *Init, QualType DeclType) {
|
2008-08-04 11:31:14 +04:00
|
|
|
const ArrayType *AT = Context.getAsArrayType(DeclType);
|
2008-01-25 03:51:06 +03:00
|
|
|
if (AT && AT->getElementType()->isCharType()) {
|
|
|
|
return dyn_cast<StringLiteral>(Init);
|
|
|
|
}
|
2008-01-22 03:55:40 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-25 03:51:06 +03:00
|
|
|
bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) {
|
2008-01-22 02:53:58 +03: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.
|
2008-08-04 11:31:14 +04:00
|
|
|
if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType))
|
2008-01-22 02:53:58 +03:00
|
|
|
return Diag(VAT->getSizeExpr()->getLocStart(),
|
|
|
|
diag::err_variable_object_no_init,
|
|
|
|
VAT->getSizeExpr()->getSourceRange());
|
|
|
|
|
2007-09-02 06:04:30 +04:00
|
|
|
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
|
2007-12-11 01:44:33 +03:00
|
|
|
if (!InitList) {
|
2008-01-22 03:55:40 +03:00
|
|
|
// FIXME: Handle wide strings
|
|
|
|
if (StringLiteral *strLiteral = IsStringLiteralInit(Init, DeclType))
|
|
|
|
return CheckStringLiteralInit(strLiteral, DeclType);
|
2008-02-08 03:48:24 +03:00
|
|
|
|
|
|
|
if (DeclType->isArrayType())
|
|
|
|
return Diag(Init->getLocStart(),
|
|
|
|
diag::err_array_init_list_required,
|
|
|
|
Init->getSourceRange());
|
|
|
|
|
2008-01-11 01:15:12 +03:00
|
|
|
return CheckSingleInitializer(Init, DeclType);
|
2007-12-11 01:44:33 +03:00
|
|
|
}
|
2008-06-06 23:40:52 +04:00
|
|
|
|
2008-05-02 02:18:59 +04:00
|
|
|
InitListChecker CheckInitList(this, InitList, DeclType);
|
|
|
|
return CheckInitList.HadError();
|
2007-09-02 06:04:30 +04:00
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
Sema::DeclTy *
|
2008-08-05 20:28:08 +04:00
|
|
|
Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
|
2007-09-14 03:52:58 +04:00
|
|
|
ScopedDecl *LastDeclarator = dyn_cast_or_null<ScopedDecl>((Decl *)lastDecl);
|
2007-07-11 21:01:13 +04:00
|
|
|
IdentifierInfo *II = D.getIdentifier();
|
|
|
|
|
2007-07-25 04:24:17 +04: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 02:36:42 +04:00
|
|
|
Diag(D.getDeclSpec().getSourceRange().getBegin(),
|
2007-08-28 10:17:15 +04:00
|
|
|
diag::err_declarator_need_ident,
|
2007-07-25 04:24:17 +04:00
|
|
|
D.getDeclSpec().getSourceRange(), D.getSourceRange());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-26 10:24:45 +04: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-07-11 21:01:13 +04:00
|
|
|
// See if this is a redefinition of a variable in the same scope.
|
2008-04-02 18:35:35 +04:00
|
|
|
Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S);
|
2007-09-13 22:10:37 +04:00
|
|
|
ScopedDecl *New;
|
2007-08-29 00:14:24 +04:00
|
|
|
bool InvalidDecl = false;
|
2008-04-14 01:07:44 +04:00
|
|
|
|
|
|
|
// In C++, the previous declaration we find might be a tag type
|
|
|
|
// (class or enum). In this case, the new declaration will hide the
|
|
|
|
// tag type.
|
|
|
|
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
|
|
|
|
PrevDecl = 0;
|
|
|
|
|
2007-11-14 09:34:38 +03:00
|
|
|
QualType R = GetTypeForDeclarator(D, S);
|
|
|
|
assert(!R.isNull() && "GetTypeForDeclarator() returned null type");
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
2008-05-07 08:49:29 +04:00
|
|
|
// Check that there are no default arguments (C++ only).
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
CheckExtraCXXDefaultArguments(D);
|
|
|
|
|
2007-11-14 09:34:38 +03:00
|
|
|
TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator);
|
2007-07-11 21:01:13 +04:00
|
|
|
if (!NewTD) return 0;
|
|
|
|
|
|
|
|
// Handle attributes prior to checking for duplicates in MergeVarDecl
|
2008-06-29 04:02:00 +04:00
|
|
|
ProcessDeclAttributes(NewTD, D);
|
2008-01-10 02:34:55 +03:00
|
|
|
// Merge the decl with the existing one if appropriate. If the decl is
|
|
|
|
// in an outer scope, it isn't the same thing.
|
2008-05-10 03:39:43 +04:00
|
|
|
if (PrevDecl && IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
|
2007-07-11 21:01:13 +04:00
|
|
|
NewTD = MergeTypeDefDecl(NewTD, PrevDecl);
|
|
|
|
if (NewTD == 0) return 0;
|
|
|
|
}
|
|
|
|
New = NewTD;
|
2008-05-10 03:39:43 +04:00
|
|
|
if (S->getFnParent() == 0) {
|
2007-07-11 21:01:13 +04:00
|
|
|
// C99 6.7.7p2: If a typedef name specifies a variably modified type
|
|
|
|
// then it shall have block scope.
|
2008-02-15 15:53:51 +03:00
|
|
|
if (NewTD->getUnderlyingType()->isVariablyModifiedType()) {
|
|
|
|
// FIXME: Diagnostic needs to be fixed.
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_typecheck_illegal_vla);
|
2007-08-31 21:20:07 +04:00
|
|
|
InvalidDecl = true;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
2007-11-14 09:34:38 +03:00
|
|
|
} else if (R.getTypePtr()->isFunctionType()) {
|
2007-09-27 19:15:46 +04:00
|
|
|
FunctionDecl::StorageClass SC = FunctionDecl::None;
|
2007-07-11 21:01:13 +04:00
|
|
|
switch (D.getDeclSpec().getStorageClassSpec()) {
|
|
|
|
default: assert(0 && "Unknown storage class!");
|
|
|
|
case DeclSpec::SCS_auto:
|
|
|
|
case DeclSpec::SCS_register:
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func,
|
|
|
|
R.getAsString());
|
2007-08-29 00:14:24 +04:00
|
|
|
InvalidDecl = true;
|
|
|
|
break;
|
2007-07-11 21:01:13 +04: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;
|
2008-01-29 00:57:15 +03:00
|
|
|
case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-03-16 00:24:04 +03:00
|
|
|
bool isInline = D.getDeclSpec().isInlineSpecified();
|
2008-07-01 14:37:29 +04:00
|
|
|
FunctionDecl *NewFD;
|
|
|
|
if (D.getContext() == Declarator::MemberContext) {
|
|
|
|
// This is a C++ method declaration.
|
|
|
|
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
|
|
|
|
D.getIdentifierLoc(), II, R,
|
|
|
|
(SC == FunctionDecl::Static), isInline,
|
|
|
|
LastDeclarator);
|
|
|
|
} else {
|
|
|
|
NewFD = FunctionDecl::Create(Context, CurContext,
|
|
|
|
D.getIdentifierLoc(),
|
|
|
|
II, R, SC, isInline,
|
|
|
|
LastDeclarator);
|
|
|
|
}
|
2008-02-28 01:18:07 +03:00
|
|
|
// Handle attributes.
|
2008-06-29 04:02:00 +04:00
|
|
|
ProcessDeclAttributes(NewFD, D);
|
2008-04-08 08:40:51 +04:00
|
|
|
|
2008-08-05 05:35:17 +04:00
|
|
|
// Handle GNU asm-label extension (encoded as an attribute).
|
2008-08-05 20:28:08 +04:00
|
|
|
if (Expr *E = (Expr*) D.getAsmLabel()) {
|
2008-08-05 05:35:17 +04:00
|
|
|
// The parser guarantees this is a string.
|
|
|
|
StringLiteral *SE = cast<StringLiteral>(E);
|
|
|
|
NewFD->addAttr(new AsmLabelAttr(std::string(SE->getStrData(),
|
|
|
|
SE->getByteLength())));
|
|
|
|
}
|
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
// Copy the parameter declarations from the declarator D to
|
|
|
|
// the function declaration NewFD, if they are available.
|
2008-08-26 01:31:01 +04:00
|
|
|
if (D.getNumTypeObjects() > 0) {
|
2008-04-08 08:40:51 +04:00
|
|
|
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
|
|
|
|
|
|
|
|
// Create Decl objects for each parameter, adding them to the
|
|
|
|
// FunctionDecl.
|
|
|
|
llvm::SmallVector<ParmVarDecl*, 16> Params;
|
|
|
|
|
|
|
|
// Check for C99 6.7.5.3p10 - foo(void) is a non-varargs
|
|
|
|
// function that takes no arguments, not a function that takes a
|
2008-04-10 06:22:51 +04:00
|
|
|
// single void argument.
|
2008-05-22 12:54:03 +04:00
|
|
|
// We let through "const void" here because Sema::GetTypeForDeclarator
|
|
|
|
// already checks for that case.
|
2008-04-08 08:40:51 +04:00
|
|
|
if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
|
|
|
|
FTI.ArgInfo[0].Param &&
|
|
|
|
((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
|
|
|
|
// empty arg list, don't push any params.
|
2008-04-10 06:22:51 +04:00
|
|
|
ParmVarDecl *Param = (ParmVarDecl*)FTI.ArgInfo[0].Param;
|
|
|
|
|
2008-04-10 06:26:16 +04:00
|
|
|
// In C++, the empty parameter-type-list must be spelled "void"; a
|
|
|
|
// typedef of void is not permitted.
|
|
|
|
if (getLangOptions().CPlusPlus &&
|
2008-05-22 12:54:03 +04:00
|
|
|
Param->getType().getUnqualifiedType() != Context.VoidTy) {
|
2008-04-10 06:22:51 +04:00
|
|
|
Diag(Param->getLocation(), diag::ext_param_typedef_of_void);
|
|
|
|
}
|
|
|
|
|
2008-08-26 01:31:01 +04:00
|
|
|
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
|
2008-04-08 08:40:51 +04:00
|
|
|
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
|
|
|
|
Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
|
|
|
|
}
|
|
|
|
|
|
|
|
NewFD->setParams(&Params[0], Params.size());
|
|
|
|
}
|
|
|
|
|
2008-01-10 02:34:55 +03:00
|
|
|
// Merge the decl with the existing one if appropriate. Since C functions
|
|
|
|
// are in a flat namespace, make sure we consider decls in outer scopes.
|
2008-05-10 03:39:43 +04:00
|
|
|
if (PrevDecl &&
|
|
|
|
(!getLangOptions().CPlusPlus ||
|
|
|
|
IdResolver.isDeclInScope(PrevDecl, CurContext, S)) ) {
|
2008-04-21 06:02:58 +04:00
|
|
|
bool Redeclaration = false;
|
|
|
|
NewFD = MergeFunctionDecl(NewFD, PrevDecl, Redeclaration);
|
2007-07-11 21:01:13 +04:00
|
|
|
if (NewFD == 0) return 0;
|
2008-04-21 06:02:58 +04:00
|
|
|
if (Redeclaration) {
|
2008-05-27 09:07:37 +04:00
|
|
|
NewFD->setPreviousDeclaration(cast<FunctionDecl>(PrevDecl));
|
2008-04-21 06:02:58 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
New = NewFD;
|
2008-04-08 08:40:51 +04:00
|
|
|
|
|
|
|
// In C++, check default arguments now that we have merged decls.
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
CheckCXXDefaultArguments(NewFD);
|
2007-07-11 21:01:13 +04:00
|
|
|
} else {
|
2008-05-07 08:49:29 +04:00
|
|
|
// Check that there are no default arguments (C++ only).
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
CheckExtraCXXDefaultArguments(D);
|
|
|
|
|
2008-01-07 22:49:32 +03:00
|
|
|
if (R.getTypePtr()->isObjCInterfaceType()) {
|
2007-10-13 02:10:42 +04:00
|
|
|
Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object,
|
|
|
|
D.getIdentifier()->getName());
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
VarDecl *NewVD;
|
|
|
|
VarDecl::StorageClass SC;
|
|
|
|
switch (D.getDeclSpec().getStorageClassSpec()) {
|
2008-03-16 00:10:16 +03:00
|
|
|
default: assert(0 && "Unknown storage class!");
|
|
|
|
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;
|
|
|
|
case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-07-01 14:37:29 +04:00
|
|
|
if (D.getContext() == Declarator::MemberContext) {
|
|
|
|
assert(SC == VarDecl::Static && "Invalid storage class for member!");
|
|
|
|
// This is a static data member for a C++ class.
|
|
|
|
NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
|
|
|
|
D.getIdentifierLoc(), II,
|
|
|
|
R, LastDeclarator);
|
2007-09-02 06:04:30 +04:00
|
|
|
} else {
|
2008-07-01 14:37:29 +04:00
|
|
|
if (S->getFnParent() == 0) {
|
|
|
|
// C99 6.9p2: The storage-class specifiers auto and register shall not
|
|
|
|
// appear in the declaration specifiers in an external declaration.
|
|
|
|
if (SC == VarDecl::Auto || SC == VarDecl::Register) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope,
|
|
|
|
R.getAsString());
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
|
|
|
NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
|
|
|
|
II, R, SC, LastDeclarator);
|
|
|
|
} else {
|
|
|
|
NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
|
|
|
|
II, R, SC, LastDeclarator);
|
|
|
|
}
|
2007-08-28 22:45:29 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
// Handle attributes prior to checking for duplicates in MergeVarDecl
|
2008-06-29 04:02:00 +04:00
|
|
|
ProcessDeclAttributes(NewVD, D);
|
2008-03-14 21:07:10 +03:00
|
|
|
|
2008-08-06 04:03:29 +04:00
|
|
|
// Handle GNU asm-label extension (encoded as an attribute).
|
|
|
|
if (Expr *E = (Expr*) D.getAsmLabel()) {
|
|
|
|
// The parser guarantees this is a string.
|
|
|
|
StringLiteral *SE = cast<StringLiteral>(E);
|
|
|
|
NewVD->addAttr(new AsmLabelAttr(std::string(SE->getStrData(),
|
|
|
|
SE->getByteLength())));
|
|
|
|
}
|
|
|
|
|
2008-03-14 21:07:10 +03:00
|
|
|
// Emit an error if an address space was applied to decl with local storage.
|
|
|
|
// This includes arrays of objects with address space qualifiers, but not
|
|
|
|
// automatic variables that point to other address spaces.
|
|
|
|
// ISO/IEC TR 18037 S5.1.2
|
2008-03-25 21:36:32 +03:00
|
|
|
if (NewVD->hasLocalStorage() && (NewVD->getType().getAddressSpace() != 0)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_as_qualified_auto_decl);
|
|
|
|
InvalidDecl = true;
|
2008-03-14 03:22:18 +03:00
|
|
|
}
|
2008-01-10 02:34:55 +03:00
|
|
|
// Merge the decl with the existing one if appropriate. If the decl is
|
|
|
|
// in an outer scope, it isn't the same thing.
|
2008-05-10 03:39:43 +04:00
|
|
|
if (PrevDecl && IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
|
2007-07-11 21:01:13 +04:00
|
|
|
NewVD = MergeVarDecl(NewVD, PrevDecl);
|
|
|
|
if (NewVD == 0) return 0;
|
|
|
|
}
|
|
|
|
New = NewVD;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this has an identifier, add it to the scope stack.
|
2008-04-12 04:47:19 +04:00
|
|
|
if (II)
|
|
|
|
PushOnScopeChains(New, S);
|
2007-08-29 00:14:24 +04:00
|
|
|
// If any semantic error occurred, mark the decl as invalid.
|
|
|
|
if (D.getInvalidType() || InvalidDecl)
|
|
|
|
New->setInvalidDecl();
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
bool Sema::CheckAddressConstantExpressionLValue(const Expr* Init) {
|
|
|
|
switch (Init->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
2008-01-11 01:15:12 +03:00
|
|
|
return true;
|
2008-05-20 17:48:25 +04:00
|
|
|
case Expr::ParenExprClass: {
|
|
|
|
const ParenExpr* PE = cast<ParenExpr>(Init);
|
|
|
|
return CheckAddressConstantExpressionLValue(PE->getSubExpr());
|
2008-01-11 01:15:12 +03:00
|
|
|
}
|
2008-05-20 17:48:25 +04:00
|
|
|
case Expr::CompoundLiteralExprClass:
|
|
|
|
return cast<CompoundLiteralExpr>(Init)->isFileScope();
|
|
|
|
case Expr::DeclRefExprClass: {
|
|
|
|
const Decl *D = cast<DeclRefExpr>(Init)->getDecl();
|
2008-05-21 07:39:11 +04:00
|
|
|
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
if (VD->hasGlobalStorage())
|
|
|
|
return false;
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
2008-05-20 17:48:25 +04:00
|
|
|
if (isa<FunctionDecl>(D))
|
|
|
|
return false;
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::MemberExprClass: {
|
|
|
|
const MemberExpr *M = cast<MemberExpr>(Init);
|
|
|
|
if (M->isArrow())
|
|
|
|
return CheckAddressConstantExpression(M->getBase());
|
|
|
|
return CheckAddressConstantExpressionLValue(M->getBase());
|
|
|
|
}
|
|
|
|
case Expr::ArraySubscriptExprClass: {
|
|
|
|
// FIXME: Should we pedwarn for "x[0+0]" (where x is a pointer)?
|
|
|
|
const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(Init);
|
|
|
|
return CheckAddressConstantExpression(ASE->getBase()) ||
|
|
|
|
CheckArithmeticConstantExpression(ASE->getIdx());
|
|
|
|
}
|
|
|
|
case Expr::StringLiteralClass:
|
2008-08-10 05:53:14 +04:00
|
|
|
case Expr::PredefinedExprClass:
|
2008-05-20 17:48:25 +04:00
|
|
|
return false;
|
|
|
|
case Expr::UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *Exp = cast<UnaryOperator>(Init);
|
|
|
|
|
|
|
|
// C99 6.6p9
|
|
|
|
if (Exp->getOpcode() == UnaryOperator::Deref)
|
2008-05-21 07:39:11 +04:00
|
|
|
return CheckAddressConstantExpression(Exp->getSubExpr());
|
2008-05-20 17:48:25 +04:00
|
|
|
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sema::CheckAddressConstantExpression(const Expr* Init) {
|
|
|
|
switch (Init->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
case Expr::ParenExprClass: {
|
|
|
|
const ParenExpr* PE = cast<ParenExpr>(Init);
|
|
|
|
return CheckAddressConstantExpression(PE->getSubExpr());
|
|
|
|
}
|
|
|
|
case Expr::StringLiteralClass:
|
|
|
|
case Expr::ObjCStringLiteralClass:
|
|
|
|
return false;
|
|
|
|
case Expr::CallExprClass: {
|
|
|
|
const CallExpr *CE = cast<CallExpr>(Init);
|
|
|
|
if (CE->isBuiltinConstantExpr())
|
|
|
|
return false;
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *Exp = cast<UnaryOperator>(Init);
|
|
|
|
|
|
|
|
// C99 6.6p9
|
|
|
|
if (Exp->getOpcode() == UnaryOperator::AddrOf)
|
|
|
|
return CheckAddressConstantExpressionLValue(Exp->getSubExpr());
|
|
|
|
|
|
|
|
if (Exp->getOpcode() == UnaryOperator::Extension)
|
|
|
|
return CheckAddressConstantExpression(Exp->getSubExpr());
|
|
|
|
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::BinaryOperatorClass: {
|
|
|
|
// FIXME: Should we pedwarn for expressions like "a + 1 + 2"?
|
|
|
|
const BinaryOperator *Exp = cast<BinaryOperator>(Init);
|
|
|
|
|
|
|
|
Expr *PExp = Exp->getLHS();
|
|
|
|
Expr *IExp = Exp->getRHS();
|
|
|
|
if (IExp->getType()->isPointerType())
|
|
|
|
std::swap(PExp, IExp);
|
|
|
|
|
|
|
|
// FIXME: Should we pedwarn if IExp isn't an integer constant expression?
|
|
|
|
return CheckAddressConstantExpression(PExp) ||
|
|
|
|
CheckArithmeticConstantExpression(IExp);
|
|
|
|
}
|
2008-08-26 00:46:57 +04:00
|
|
|
case Expr::ImplicitCastExprClass:
|
2008-08-19 03:01:59 +04:00
|
|
|
case Expr::ExplicitCastExprClass: {
|
2008-05-20 17:48:25 +04:00
|
|
|
const Expr* SubExpr = cast<CastExpr>(Init)->getSubExpr();
|
2008-08-26 00:46:57 +04:00
|
|
|
if (Init->getStmtClass() == Expr::ImplicitCastExprClass) {
|
|
|
|
// Check for implicit promotion
|
|
|
|
if (SubExpr->getType()->isFunctionType() ||
|
|
|
|
SubExpr->getType()->isArrayType())
|
|
|
|
return CheckAddressConstantExpressionLValue(SubExpr);
|
|
|
|
}
|
2008-05-20 17:48:25 +04:00
|
|
|
|
|
|
|
// Check for pointer->pointer cast
|
|
|
|
if (SubExpr->getType()->isPointerType())
|
|
|
|
return CheckAddressConstantExpression(SubExpr);
|
|
|
|
|
2008-08-26 00:46:57 +04:00
|
|
|
if (SubExpr->getType()->isIntegralType()) {
|
|
|
|
// Check for the special-case of a pointer->int->pointer cast;
|
|
|
|
// this isn't standard, but some code requires it. See
|
|
|
|
// PR2720 for an example.
|
|
|
|
if (const CastExpr* SubCast = dyn_cast<CastExpr>(SubExpr)) {
|
|
|
|
if (SubCast->getSubExpr()->getType()->isPointerType()) {
|
|
|
|
unsigned IntWidth = Context.getIntWidth(SubCast->getType());
|
|
|
|
unsigned PointerWidth = Context.getTypeSize(Context.VoidPtrTy);
|
|
|
|
if (IntWidth >= PointerWidth) {
|
|
|
|
return CheckAddressConstantExpression(SubCast->getSubExpr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (SubExpr->getType()->isArithmeticType()) {
|
2008-05-20 17:48:25 +04:00
|
|
|
return CheckArithmeticConstantExpression(SubExpr);
|
2008-08-26 00:46:57 +04:00
|
|
|
}
|
2008-05-20 17:48:25 +04:00
|
|
|
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::ConditionalOperatorClass: {
|
|
|
|
// FIXME: Should we pedwarn here?
|
|
|
|
const ConditionalOperator *Exp = cast<ConditionalOperator>(Init);
|
|
|
|
if (!Exp->getCond()->getType()->isArithmeticType()) {
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (CheckArithmeticConstantExpression(Exp->getCond()))
|
|
|
|
return true;
|
|
|
|
if (Exp->getLHS() &&
|
|
|
|
CheckAddressConstantExpression(Exp->getLHS()))
|
|
|
|
return true;
|
|
|
|
return CheckAddressConstantExpression(Exp->getRHS());
|
|
|
|
}
|
|
|
|
case Expr::AddrLabelExprClass:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-09 09:05:07 +04:00
|
|
|
static const Expr* FindExpressionBaseAddress(const Expr* E);
|
|
|
|
|
|
|
|
static const Expr* FindExpressionBaseAddressLValue(const Expr* E) {
|
|
|
|
switch (E->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
return E;
|
|
|
|
case Expr::ParenExprClass: {
|
|
|
|
const ParenExpr* PE = cast<ParenExpr>(E);
|
|
|
|
return FindExpressionBaseAddressLValue(PE->getSubExpr());
|
|
|
|
}
|
|
|
|
case Expr::MemberExprClass: {
|
|
|
|
const MemberExpr *M = cast<MemberExpr>(E);
|
|
|
|
if (M->isArrow())
|
|
|
|
return FindExpressionBaseAddress(M->getBase());
|
|
|
|
return FindExpressionBaseAddressLValue(M->getBase());
|
|
|
|
}
|
|
|
|
case Expr::ArraySubscriptExprClass: {
|
|
|
|
const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(E);
|
|
|
|
return FindExpressionBaseAddress(ASE->getBase());
|
|
|
|
}
|
|
|
|
case Expr::UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *Exp = cast<UnaryOperator>(E);
|
|
|
|
|
|
|
|
if (Exp->getOpcode() == UnaryOperator::Deref)
|
|
|
|
return FindExpressionBaseAddress(Exp->getSubExpr());
|
|
|
|
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const Expr* FindExpressionBaseAddress(const Expr* E) {
|
|
|
|
switch (E->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
return E;
|
|
|
|
case Expr::ParenExprClass: {
|
|
|
|
const ParenExpr* PE = cast<ParenExpr>(E);
|
|
|
|
return FindExpressionBaseAddress(PE->getSubExpr());
|
|
|
|
}
|
|
|
|
case Expr::UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *Exp = cast<UnaryOperator>(E);
|
|
|
|
|
|
|
|
// C99 6.6p9
|
|
|
|
if (Exp->getOpcode() == UnaryOperator::AddrOf)
|
|
|
|
return FindExpressionBaseAddressLValue(Exp->getSubExpr());
|
|
|
|
|
|
|
|
if (Exp->getOpcode() == UnaryOperator::Extension)
|
|
|
|
return FindExpressionBaseAddress(Exp->getSubExpr());
|
|
|
|
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
case Expr::BinaryOperatorClass: {
|
|
|
|
const BinaryOperator *Exp = cast<BinaryOperator>(E);
|
|
|
|
|
|
|
|
Expr *PExp = Exp->getLHS();
|
|
|
|
Expr *IExp = Exp->getRHS();
|
|
|
|
if (IExp->getType()->isPointerType())
|
|
|
|
std::swap(PExp, IExp);
|
|
|
|
|
|
|
|
return FindExpressionBaseAddress(PExp);
|
|
|
|
}
|
|
|
|
case Expr::ImplicitCastExprClass: {
|
|
|
|
const Expr* SubExpr = cast<ImplicitCastExpr>(E)->getSubExpr();
|
|
|
|
|
|
|
|
// Check for implicit promotion
|
|
|
|
if (SubExpr->getType()->isFunctionType() ||
|
|
|
|
SubExpr->getType()->isArrayType())
|
|
|
|
return FindExpressionBaseAddressLValue(SubExpr);
|
|
|
|
|
|
|
|
// Check for pointer->pointer cast
|
|
|
|
if (SubExpr->getType()->isPointerType())
|
|
|
|
return FindExpressionBaseAddress(SubExpr);
|
|
|
|
|
|
|
|
// We assume that we have an arithmetic expression here;
|
|
|
|
// if we don't, we'll figure it out later
|
|
|
|
return 0;
|
|
|
|
}
|
2008-08-19 03:01:59 +04:00
|
|
|
case Expr::ExplicitCastExprClass: {
|
2008-06-09 09:05:07 +04:00
|
|
|
const Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
|
|
|
|
|
|
|
|
// Check for pointer->pointer cast
|
|
|
|
if (SubExpr->getType()->isPointerType())
|
|
|
|
return FindExpressionBaseAddress(SubExpr);
|
|
|
|
|
|
|
|
// We assume that we have an arithmetic expression here;
|
|
|
|
// if we don't, we'll figure it out later
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
bool Sema::CheckArithmeticConstantExpression(const Expr* Init) {
|
|
|
|
switch (Init->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
case Expr::ParenExprClass: {
|
|
|
|
const ParenExpr* PE = cast<ParenExpr>(Init);
|
|
|
|
return CheckArithmeticConstantExpression(PE->getSubExpr());
|
|
|
|
}
|
|
|
|
case Expr::FloatingLiteralClass:
|
|
|
|
case Expr::IntegerLiteralClass:
|
|
|
|
case Expr::CharacterLiteralClass:
|
|
|
|
case Expr::ImaginaryLiteralClass:
|
|
|
|
case Expr::TypesCompatibleExprClass:
|
|
|
|
case Expr::CXXBoolLiteralExprClass:
|
|
|
|
return false;
|
|
|
|
case Expr::CallExprClass: {
|
|
|
|
const CallExpr *CE = cast<CallExpr>(Init);
|
|
|
|
if (CE->isBuiltinConstantExpr())
|
|
|
|
return false;
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::DeclRefExprClass: {
|
|
|
|
const Decl *D = cast<DeclRefExpr>(Init)->getDecl();
|
|
|
|
if (isa<EnumConstantDecl>(D))
|
|
|
|
return false;
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::CompoundLiteralExprClass:
|
|
|
|
// Allow "(vector type){2,4}"; normal C constraints don't allow this,
|
|
|
|
// but vectors are allowed to be magic.
|
|
|
|
if (Init->getType()->isVectorType())
|
|
|
|
return false;
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
case Expr::UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *Exp = cast<UnaryOperator>(Init);
|
|
|
|
|
|
|
|
switch (Exp->getOpcode()) {
|
|
|
|
// Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
|
|
|
|
// See C99 6.6p3.
|
|
|
|
default:
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
case UnaryOperator::SizeOf:
|
|
|
|
case UnaryOperator::AlignOf:
|
|
|
|
case UnaryOperator::OffsetOf:
|
|
|
|
// sizeof(E) is a constantexpr if and only if E is not evaluted.
|
|
|
|
// See C99 6.5.3.4p2 and 6.6p3.
|
|
|
|
if (Exp->getSubExpr()->getType()->isConstantSizeType())
|
|
|
|
return false;
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
case UnaryOperator::Extension:
|
|
|
|
case UnaryOperator::LNot:
|
|
|
|
case UnaryOperator::Plus:
|
|
|
|
case UnaryOperator::Minus:
|
|
|
|
case UnaryOperator::Not:
|
|
|
|
return CheckArithmeticConstantExpression(Exp->getSubExpr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case Expr::SizeOfAlignOfTypeExprClass: {
|
|
|
|
const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(Init);
|
|
|
|
// Special check for void types, which are allowed as an extension
|
|
|
|
if (Exp->getArgumentType()->isVoidType())
|
|
|
|
return false;
|
|
|
|
// alignof always evaluates to a constant.
|
|
|
|
// FIXME: is sizeof(int[3.0]) a constant expression?
|
|
|
|
if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType()) {
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case Expr::BinaryOperatorClass: {
|
|
|
|
const BinaryOperator *Exp = cast<BinaryOperator>(Init);
|
|
|
|
|
|
|
|
if (Exp->getLHS()->getType()->isArithmeticType() &&
|
|
|
|
Exp->getRHS()->getType()->isArithmeticType()) {
|
|
|
|
return CheckArithmeticConstantExpression(Exp->getLHS()) ||
|
|
|
|
CheckArithmeticConstantExpression(Exp->getRHS());
|
|
|
|
}
|
|
|
|
|
2008-06-09 09:05:07 +04:00
|
|
|
if (Exp->getLHS()->getType()->isPointerType() &&
|
|
|
|
Exp->getRHS()->getType()->isPointerType()) {
|
|
|
|
const Expr* LHSBase = FindExpressionBaseAddress(Exp->getLHS());
|
|
|
|
const Expr* RHSBase = FindExpressionBaseAddress(Exp->getRHS());
|
|
|
|
|
|
|
|
// Only allow a null (constant integer) base; we could
|
|
|
|
// allow some additional cases if necessary, but this
|
|
|
|
// is sufficient to cover offsetof-like constructs.
|
|
|
|
if (!LHSBase && !RHSBase) {
|
|
|
|
return CheckAddressConstantExpression(Exp->getLHS()) ||
|
|
|
|
CheckAddressConstantExpression(Exp->getRHS());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::ImplicitCastExprClass:
|
2008-08-19 03:01:59 +04:00
|
|
|
case Expr::ExplicitCastExprClass: {
|
|
|
|
const Expr *SubExpr = cast<CastExpr>(Init)->getSubExpr();
|
2008-09-02 02:08:17 +04:00
|
|
|
if (SubExpr->getType()->isArithmeticType())
|
|
|
|
return CheckArithmeticConstantExpression(SubExpr);
|
|
|
|
|
2008-09-02 13:37:00 +04:00
|
|
|
if (SubExpr->getType()->isPointerType()) {
|
|
|
|
const Expr* Base = FindExpressionBaseAddress(SubExpr);
|
|
|
|
// If the pointer has a null base, this is an offsetof-like construct
|
|
|
|
if (!Base)
|
|
|
|
return CheckAddressConstantExpression(SubExpr);
|
|
|
|
}
|
|
|
|
|
2008-09-02 02:08:17 +04:00
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
return true;
|
2008-05-20 17:48:25 +04:00
|
|
|
}
|
|
|
|
case Expr::ConditionalOperatorClass: {
|
|
|
|
const ConditionalOperator *Exp = cast<ConditionalOperator>(Init);
|
|
|
|
if (CheckArithmeticConstantExpression(Exp->getCond()))
|
|
|
|
return true;
|
|
|
|
if (Exp->getLHS() &&
|
|
|
|
CheckArithmeticConstantExpression(Exp->getLHS()))
|
|
|
|
return true;
|
|
|
|
return CheckArithmeticConstantExpression(Exp->getRHS());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
|
2008-07-07 20:46:50 +04:00
|
|
|
Init = Init->IgnoreParens();
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
// Look through CXXDefaultArgExprs; they have no meaning in this context.
|
|
|
|
if (CXXDefaultArgExpr* DAE = dyn_cast<CXXDefaultArgExpr>(Init))
|
|
|
|
return CheckForConstantInitializer(DAE->getExpr(), DclT);
|
|
|
|
|
2008-07-07 20:46:50 +04:00
|
|
|
if (CompoundLiteralExpr *e = dyn_cast<CompoundLiteralExpr>(Init))
|
|
|
|
return CheckForConstantInitializer(e->getInitializer(), DclT);
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
if (Init->getType()->isReferenceType()) {
|
|
|
|
// FIXME: Work out how the heck reference types work
|
|
|
|
return false;
|
|
|
|
#if 0
|
|
|
|
// A reference is constant if the address of the expression
|
|
|
|
// is constant
|
|
|
|
// We look through initlists here to simplify
|
|
|
|
// CheckAddressConstantExpressionLValue.
|
|
|
|
if (InitListExpr *Exp = dyn_cast<InitListExpr>(Init)) {
|
|
|
|
assert(Exp->getNumInits() > 0 &&
|
|
|
|
"Refernce initializer cannot be empty");
|
|
|
|
Init = Exp->getInit(0);
|
|
|
|
}
|
|
|
|
return CheckAddressConstantExpressionLValue(Init);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InitListExpr *Exp = dyn_cast<InitListExpr>(Init)) {
|
|
|
|
unsigned numInits = Exp->getNumInits();
|
|
|
|
for (unsigned i = 0; i < numInits; i++) {
|
|
|
|
// FIXME: Need to get the type of the declaration for C++,
|
|
|
|
// because it could be a reference?
|
|
|
|
if (CheckForConstantInitializer(Exp->getInit(i),
|
|
|
|
Exp->getInit(i)->getType()))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Init->isNullPointerConstant(Context))
|
|
|
|
return false;
|
|
|
|
if (Init->getType()->isArithmeticType()) {
|
2008-07-27 02:17:49 +04:00
|
|
|
QualType InitTy = Context.getCanonicalType(Init->getType())
|
|
|
|
.getUnqualifiedType();
|
2008-05-30 22:14:48 +04:00
|
|
|
if (InitTy == Context.BoolTy) {
|
|
|
|
// Special handling for pointers implicitly cast to bool;
|
|
|
|
// (e.g. "_Bool rr = &rr;"). This is only legal at the top level.
|
|
|
|
if (ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(Init)) {
|
|
|
|
Expr* SubE = ICE->getSubExpr();
|
|
|
|
if (SubE->getType()->isPointerType() ||
|
|
|
|
SubE->getType()->isArrayType() ||
|
|
|
|
SubE->getType()->isFunctionType()) {
|
|
|
|
return CheckAddressConstantExpression(Init);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (InitTy->isIntegralType()) {
|
|
|
|
Expr* SubE = 0;
|
2008-08-19 03:01:59 +04:00
|
|
|
if (CastExpr* CE = dyn_cast<CastExpr>(Init))
|
2008-05-30 22:14:48 +04:00
|
|
|
SubE = CE->getSubExpr();
|
|
|
|
// Special check for pointer cast to int; we allow as an extension
|
|
|
|
// an address constant cast to an integer if the integer
|
|
|
|
// is of an appropriate width (this sort of code is apparently used
|
|
|
|
// in some places).
|
|
|
|
// FIXME: Add pedwarn?
|
|
|
|
// FIXME: Don't allow bitfields here! Need the FieldDecl for that.
|
|
|
|
if (SubE && (SubE->getType()->isPointerType() ||
|
|
|
|
SubE->getType()->isArrayType() ||
|
|
|
|
SubE->getType()->isFunctionType())) {
|
|
|
|
unsigned IntWidth = Context.getTypeSize(Init->getType());
|
|
|
|
unsigned PointerWidth = Context.getTypeSize(Context.VoidPtrTy);
|
|
|
|
if (IntWidth >= PointerWidth)
|
|
|
|
return CheckAddressConstantExpression(Init);
|
|
|
|
}
|
2008-05-20 17:48:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return CheckArithmeticConstantExpression(Init);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Init->getType()->isPointerType())
|
|
|
|
return CheckAddressConstantExpression(Init);
|
|
|
|
|
2008-05-30 22:14:48 +04:00
|
|
|
// An array type at the top level that isn't an init-list must
|
|
|
|
// be a string literal
|
2008-05-20 17:48:25 +04:00
|
|
|
if (Init->getType()->isArrayType())
|
|
|
|
return false;
|
|
|
|
|
2008-09-01 22:42:41 +04:00
|
|
|
if (Init->getType()->isFunctionType())
|
|
|
|
return false;
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
Diag(Init->getExprLoc(), diag::err_init_element_not_constant,
|
|
|
|
Init->getSourceRange());
|
|
|
|
return true;
|
2008-01-11 01:15:12 +03:00
|
|
|
}
|
|
|
|
|
2007-09-12 18:07:44 +04:00
|
|
|
void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) {
|
2007-09-13 00:13:48 +04:00
|
|
|
Decl *RealDecl = static_cast<Decl *>(dcl);
|
2007-09-12 18:07:44 +04:00
|
|
|
Expr *Init = static_cast<Expr *>(init);
|
2007-10-20 00:10:30 +04:00
|
|
|
assert(Init && "missing initializer");
|
2007-09-12 18:07:44 +04:00
|
|
|
|
2007-10-20 00:10:30 +04: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 18:07:44 +04:00
|
|
|
|
2007-09-13 00:13:48 +04:00
|
|
|
VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
|
|
|
|
if (!VDecl) {
|
2007-09-14 01:41:19 +04:00
|
|
|
Diag(dyn_cast<ScopedDecl>(RealDecl)->getLocation(),
|
|
|
|
diag::err_illegal_initializer);
|
2007-09-13 00:13:48 +04:00
|
|
|
RealDecl->setInvalidDecl();
|
|
|
|
return;
|
|
|
|
}
|
2007-09-12 18:07:44 +04:00
|
|
|
// Get the decls type and save a reference for later, since
|
2008-01-11 01:15:12 +03:00
|
|
|
// CheckInitializerTypes may change it.
|
2007-09-13 00:13:48 +04:00
|
|
|
QualType DclT = VDecl->getType(), SavT = DclT;
|
2008-04-16 02:42:06 +04:00
|
|
|
if (VDecl->isBlockVarDecl()) {
|
|
|
|
VarDecl::StorageClass SC = VDecl->getStorageClass();
|
2007-09-12 18:07:44 +04:00
|
|
|
if (SC == VarDecl::Extern) { // C99 6.7.8p5
|
2007-09-13 00:13:48 +04:00
|
|
|
Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
|
2008-04-16 02:42:06 +04:00
|
|
|
VDecl->setInvalidDecl();
|
|
|
|
} else if (!VDecl->isInvalidDecl()) {
|
2008-01-25 03:51:06 +03:00
|
|
|
if (CheckInitializerTypes(Init, DclT))
|
2008-04-16 02:42:06 +04:00
|
|
|
VDecl->setInvalidDecl();
|
2008-08-22 09:00:02 +04:00
|
|
|
|
|
|
|
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
|
|
|
|
if (!getLangOptions().CPlusPlus) {
|
|
|
|
if (SC == VarDecl::Static) // C99 6.7.8p4.
|
|
|
|
CheckForConstantInitializer(Init, DclT);
|
|
|
|
}
|
2007-09-12 18:07:44 +04:00
|
|
|
}
|
2008-04-16 02:42:06 +04:00
|
|
|
} else if (VDecl->isFileVarDecl()) {
|
|
|
|
if (VDecl->getStorageClass() == VarDecl::Extern)
|
2007-09-13 00:13:48 +04:00
|
|
|
Diag(VDecl->getLocation(), diag::warn_extern_init);
|
2008-04-16 02:42:06 +04:00
|
|
|
if (!VDecl->isInvalidDecl())
|
2008-01-25 03:51:06 +03:00
|
|
|
if (CheckInitializerTypes(Init, DclT))
|
2008-04-16 02:42:06 +04:00
|
|
|
VDecl->setInvalidDecl();
|
2008-01-11 01:15:12 +03:00
|
|
|
|
2008-08-22 09:00:02 +04:00
|
|
|
// C++ 3.6.2p2, allow dynamic initialization of static initializers.
|
|
|
|
if (!getLangOptions().CPlusPlus) {
|
|
|
|
// C99 6.7.8p4. All file scoped initializers need to be constant.
|
|
|
|
CheckForConstantInitializer(Init, DclT);
|
|
|
|
}
|
2007-09-12 18:07:44 +04:00
|
|
|
}
|
|
|
|
// 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-11-29 22:09:19 +03:00
|
|
|
if (!VDecl->isInvalidDecl() && (DclT != SavT)) {
|
2007-09-13 00:13:48 +04:00
|
|
|
VDecl->setType(DclT);
|
2007-11-29 22:09:19 +03:00
|
|
|
Init->setType(DclT);
|
|
|
|
}
|
2007-09-12 18:07:44 +04:00
|
|
|
|
|
|
|
// Attach the initializer to the decl.
|
2007-09-13 00:13:48 +04:00
|
|
|
VDecl->setInit(Init);
|
2007-09-12 18:07:44 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04: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 03:52:58 +04:00
|
|
|
Decl *GroupDecl = static_cast<Decl*>(group);
|
|
|
|
if (GroupDecl == 0)
|
2007-09-12 18:07:44 +04:00
|
|
|
return 0;
|
2007-09-14 03:52:58 +04:00
|
|
|
|
|
|
|
ScopedDecl *Group = dyn_cast<ScopedDecl>(GroupDecl);
|
|
|
|
ScopedDecl *NewGroup = 0;
|
2007-09-12 18:07:44 +04:00
|
|
|
if (Group->getNextDeclarator() == 0)
|
2007-07-11 21:01:13 +04:00
|
|
|
NewGroup = Group;
|
2007-09-12 18:07:44 +04:00
|
|
|
else { // reverse the list.
|
|
|
|
while (Group) {
|
2007-09-14 03:52:58 +04:00
|
|
|
ScopedDecl *Next = Group->getNextDeclarator();
|
2007-09-12 18:07:44 +04: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 03:52:58 +04:00
|
|
|
for (ScopedDecl *ID = NewGroup; ID; ID = ID->getNextDeclarator()) {
|
2007-09-12 18:07:44 +04:00
|
|
|
VarDecl *IDecl = dyn_cast<VarDecl>(ID);
|
|
|
|
if (!IDecl)
|
|
|
|
continue;
|
|
|
|
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.
|
2008-04-16 02:42:06 +04:00
|
|
|
if ((IDecl->isFileVarDecl() || IDecl->isBlockVarDecl()) &&
|
|
|
|
IDecl->getStorageClass() == VarDecl::Static) {
|
2008-08-04 11:31:14 +04:00
|
|
|
if (T->isVariableArrayType()) {
|
2008-02-15 21:16:39 +03:00
|
|
|
Diag(IDecl->getLocation(), diag::err_typecheck_illegal_vla);
|
|
|
|
IDecl->setInvalidDecl();
|
2007-09-12 18:07:44 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// 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...
|
2008-04-16 02:42:06 +04:00
|
|
|
if (IDecl->isBlockVarDecl() &&
|
|
|
|
IDecl->getStorageClass() != VarDecl::Extern) {
|
2008-04-02 05:05:10 +04:00
|
|
|
if (T->isIncompleteType() && !IDecl->isInvalidDecl()) {
|
2007-12-02 10:50:03 +03:00
|
|
|
Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type,
|
|
|
|
T.getAsString());
|
2007-09-12 18:07:44 +04:00
|
|
|
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).
|
2008-08-08 21:50:35 +04:00
|
|
|
if (isTentativeDefinition(IDecl)) {
|
2008-02-15 15:53:51 +03:00
|
|
|
if (T->isIncompleteArrayType()) {
|
2008-01-18 23:40:52 +03:00
|
|
|
// C99 6.9.2 (p2, p5): Implicit initialization causes an incomplete
|
|
|
|
// array to be completed. Don't issue a diagnostic.
|
2008-04-02 05:05:10 +04:00
|
|
|
} else if (T->isIncompleteType() && !IDecl->isInvalidDecl()) {
|
2008-01-18 23:40:52 +03:00
|
|
|
// 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.
|
2007-12-02 10:50:03 +03:00
|
|
|
Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type,
|
|
|
|
T.getAsString());
|
2007-09-12 18:07:44 +04:00
|
|
|
IDecl->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
2008-08-08 21:50:35 +04:00
|
|
|
if (IDecl->isFileVarDecl())
|
|
|
|
CheckForFileScopedRedefinitions(S, IDecl);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
return NewGroup;
|
|
|
|
}
|
2007-08-28 07:03:08 +04:00
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
|
|
|
|
/// to introduce parameters into function prototype scope.
|
|
|
|
Sema::DeclTy *
|
|
|
|
Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
|
2008-06-26 10:49:43 +04:00
|
|
|
const DeclSpec &DS = D.getDeclSpec();
|
2008-04-08 08:40:51 +04:00
|
|
|
|
|
|
|
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
|
2008-09-04 01:54:21 +04:00
|
|
|
VarDecl::StorageClass StorageClass = VarDecl::None;
|
|
|
|
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
|
|
|
|
StorageClass = VarDecl::Register;
|
|
|
|
} else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
|
2008-04-08 08:40:51 +04:00
|
|
|
Diag(DS.getStorageClassSpecLoc(),
|
|
|
|
diag::err_invalid_storage_class_in_func_decl);
|
2008-06-26 10:49:43 +04:00
|
|
|
D.getMutableDeclSpec().ClearStorageClassSpecs();
|
2008-04-08 08:40:51 +04:00
|
|
|
}
|
|
|
|
if (DS.isThreadSpecified()) {
|
|
|
|
Diag(DS.getThreadSpecLoc(),
|
|
|
|
diag::err_invalid_storage_class_in_func_decl);
|
2008-06-26 10:49:43 +04:00
|
|
|
D.getMutableDeclSpec().ClearStorageClassSpecs();
|
2008-04-08 08:40:51 +04:00
|
|
|
}
|
|
|
|
|
2008-05-07 08:49:29 +04:00
|
|
|
// Check that there are no default arguments inside the type of this
|
|
|
|
// parameter (C++ only).
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
CheckExtraCXXDefaultArguments(D);
|
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
// In this context, we *do not* check D.getInvalidType(). If the declarator
|
|
|
|
// type was invalid, GetTypeForDeclarator() still returns a "valid" type,
|
|
|
|
// though it will not reflect the user specified type.
|
|
|
|
QualType parmDeclType = GetTypeForDeclarator(D, S);
|
|
|
|
|
|
|
|
assert(!parmDeclType.isNull() && "GetTypeForDeclarator() returned null type");
|
|
|
|
|
2007-07-11 21:01:13 +04: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.
|
2008-04-08 08:40:51 +04:00
|
|
|
IdentifierInfo *II = D.getIdentifier();
|
|
|
|
if (Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S)) {
|
|
|
|
if (S->isDeclScope(PrevDecl)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_param_redefinition,
|
|
|
|
dyn_cast<NamedDecl>(PrevDecl)->getName());
|
|
|
|
|
|
|
|
// Recover by removing the name
|
|
|
|
II = 0;
|
|
|
|
D.SetIdentifier(0, D.getIdentifierLoc());
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2007-08-08 02:44:21 +04: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)...
|
|
|
|
//
|
2008-04-02 09:18:44 +04:00
|
|
|
if (parmDeclType->isArrayType()) {
|
2008-01-03 01:50:48 +03:00
|
|
|
// int x[restrict 4] -> int *restrict
|
2008-04-02 09:18:44 +04:00
|
|
|
parmDeclType = Context.getArrayDecayedType(parmDeclType);
|
2008-01-03 01:50:48 +03:00
|
|
|
} else if (parmDeclType->isFunctionType())
|
2007-08-08 02:44:21 +04:00
|
|
|
parmDeclType = Context.getPointerType(parmDeclType);
|
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext,
|
|
|
|
D.getIdentifierLoc(), II,
|
2008-09-04 01:54:21 +04:00
|
|
|
parmDeclType, StorageClass,
|
2008-04-08 08:40:51 +04:00
|
|
|
0, 0);
|
2008-02-15 10:04:12 +03:00
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
if (D.getInvalidType())
|
2007-08-28 22:45:29 +04:00
|
|
|
New->setInvalidDecl();
|
|
|
|
|
2008-04-12 04:47:19 +04:00
|
|
|
if (II)
|
|
|
|
PushOnScopeChains(New, S);
|
2008-02-18 00:20:31 +03:00
|
|
|
|
2008-06-29 04:02:00 +04:00
|
|
|
ProcessDeclAttributes(New, D);
|
2007-07-11 21:01:13 +04:00
|
|
|
return New;
|
2008-04-08 08:40:51 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2007-11-09 02:49:49 +03:00
|
|
|
|
2007-10-09 21:14:05 +04:00
|
|
|
Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
|
2008-06-28 10:07:14 +04:00
|
|
|
assert(getCurFunctionDecl() == 0 && "Function parsing confused");
|
2007-07-11 21:01:13 +04:00
|
|
|
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
|
|
|
|
"Not a function declarator!");
|
|
|
|
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
|
2008-04-08 08:40:51 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// 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) {
|
2008-04-08 08:40:51 +04:00
|
|
|
if (FTI.ArgInfo[i].Param == 0) {
|
2007-07-11 21:01:13 +04:00
|
|
|
Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared,
|
|
|
|
FTI.ArgInfo[i].Ident->getName());
|
|
|
|
// Implicitly declare the argument as type 'int' for lack of a better
|
|
|
|
// type.
|
2008-04-08 08:40:51 +04:00
|
|
|
DeclSpec DS;
|
|
|
|
const char* PrevSpec; // unused
|
|
|
|
DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
|
|
|
|
PrevSpec);
|
|
|
|
Declarator ParamD(DS, Declarator::KNRTypeListContext);
|
|
|
|
ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc);
|
|
|
|
FTI.ArgInfo[i].Param = ActOnParamDeclarator(FnBodyScope, ParamD);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2008-04-08 08:40:51 +04:00
|
|
|
// FIXME: Diagnose arguments without names in C.
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Scope *GlobalScope = FnBodyScope->getParent();
|
2008-01-14 23:51:29 +03:00
|
|
|
|
|
|
|
// See if this is a redefinition.
|
2008-04-02 03:04:06 +04:00
|
|
|
Decl *PrevDcl = LookupDecl(D.getIdentifier(), Decl::IDNS_Ordinary,
|
2008-04-02 18:35:35 +04:00
|
|
|
GlobalScope);
|
2008-05-10 03:39:43 +04:00
|
|
|
if (PrevDcl && IdResolver.isDeclInScope(PrevDcl, CurContext)) {
|
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PrevDcl)) {
|
|
|
|
const FunctionDecl *Definition;
|
|
|
|
if (FD->getBody(Definition)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_redefinition,
|
|
|
|
D.getIdentifier()->getName());
|
|
|
|
Diag(Definition->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
2008-01-14 23:51:29 +03:00
|
|
|
}
|
|
|
|
}
|
2008-07-01 14:37:29 +04:00
|
|
|
|
|
|
|
return ActOnStartOfFunctionDef(FnBodyScope,
|
2008-08-05 20:28:08 +04:00
|
|
|
ActOnDeclarator(GlobalScope, D, 0));
|
2008-07-01 14:37:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
|
|
|
|
Decl *decl = static_cast<Decl*>(D);
|
2008-02-16 04:20:36 +03:00
|
|
|
FunctionDecl *FD = cast<FunctionDecl>(decl);
|
2008-04-06 08:47:34 +04:00
|
|
|
PushDeclContext(FD);
|
2008-04-08 08:40:51 +04:00
|
|
|
|
|
|
|
// Check the validity of our function parameters
|
|
|
|
CheckParmsForFunctionDef(FD);
|
|
|
|
|
|
|
|
// Introduce our parameters into the function scope
|
|
|
|
for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
|
|
|
|
ParmVarDecl *Param = FD->getParamDecl(p);
|
|
|
|
// If this has an identifier, add it to the scope stack.
|
2008-04-12 04:47:19 +04:00
|
|
|
if (Param->getIdentifier())
|
|
|
|
PushOnScopeChains(Param, FnBodyScope);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-04-08 08:40:51 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
return FD;
|
|
|
|
}
|
|
|
|
|
2007-11-12 02:20:51 +03:00
|
|
|
Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtTy *Body) {
|
|
|
|
Decl *dcl = static_cast<Decl *>(D);
|
2008-07-25 21:57:26 +04:00
|
|
|
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) {
|
2007-11-12 02:20:51 +03:00
|
|
|
FD->setBody((Stmt*)Body);
|
2008-06-28 10:07:14 +04:00
|
|
|
assert(FD == getCurFunctionDecl() && "Function parsing confused");
|
2008-07-25 21:57:26 +04:00
|
|
|
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
|
2007-11-12 02:20:51 +03:00
|
|
|
MD->setBody((Stmt*)Body);
|
2008-07-25 21:57:26 +04:00
|
|
|
} else
|
|
|
|
return 0;
|
2008-04-06 08:47:34 +04:00
|
|
|
PopDeclContext();
|
2007-11-10 19:31:34 +03:00
|
|
|
// Verify and clean out per-function state.
|
|
|
|
|
|
|
|
// Check goto/label use.
|
|
|
|
for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
|
|
|
|
I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) {
|
|
|
|
// 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.
|
|
|
|
Diag(L->getIdentLoc(), diag::err_undeclared_label_use, L->getName());
|
|
|
|
|
|
|
|
// 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.
|
2008-01-25 03:01:10 +03:00
|
|
|
if (Body) {
|
|
|
|
L->setSubStmt(new NullStmt(L->getIdentLoc()));
|
|
|
|
cast<CompoundStmt>((Stmt*)Body)->push_back(L);
|
|
|
|
} else {
|
|
|
|
// The whole function wasn't parsed correctly, just delete this.
|
|
|
|
delete L;
|
|
|
|
}
|
2007-11-10 19:31:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
LabelMap.clear();
|
2007-11-12 02:20:51 +03:00
|
|
|
|
|
|
|
return D;
|
2007-11-10 19:31:34 +03:00
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04: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-16 20:16:00 +04:00
|
|
|
ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
|
|
|
|
IdentifierInfo &II, Scope *S) {
|
2008-05-06 01:18:06 +04:00
|
|
|
// Extension in C99. Legal in C90, but warn about it.
|
|
|
|
if (getLangOptions().C99)
|
2007-07-11 21:01:13 +04:00
|
|
|
Diag(Loc, diag::ext_implicit_function_decl, II.getName());
|
2008-05-06 01:18:06 +04:00
|
|
|
else
|
2007-07-11 21:01:13 +04:00
|
|
|
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();
|
|
|
|
const char *Dummy;
|
|
|
|
DeclSpec DS;
|
|
|
|
bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy);
|
|
|
|
Error = Error; // Silence warning.
|
|
|
|
assert(!Error && "Error setting up implicit decl!");
|
|
|
|
Declarator D(DS, Declarator::BlockContext);
|
|
|
|
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, Loc));
|
|
|
|
D.SetIdentifier(&II, Loc);
|
|
|
|
|
2008-05-02 01:04:16 +04:00
|
|
|
// Insert this function into translation-unit scope.
|
|
|
|
|
|
|
|
DeclContext *PrevDC = CurContext;
|
|
|
|
CurContext = Context.getTranslationUnitDecl();
|
|
|
|
|
2008-04-04 18:32:09 +04:00
|
|
|
FunctionDecl *FD =
|
2008-08-05 20:28:08 +04:00
|
|
|
dyn_cast<FunctionDecl>(static_cast<Decl*>(ActOnDeclarator(TUScope, D, 0)));
|
2008-04-04 18:32:09 +04:00
|
|
|
FD->setImplicit();
|
2008-05-02 01:04:16 +04:00
|
|
|
|
|
|
|
CurContext = PrevDC;
|
|
|
|
|
2008-04-04 18:32:09 +04:00
|
|
|
return FD;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-14 09:34:38 +03:00
|
|
|
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
|
2007-09-14 03:52:58 +04:00
|
|
|
ScopedDecl *LastDeclarator) {
|
2007-07-11 21:01:13 +04:00
|
|
|
assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
|
2007-08-29 00:14:24 +04:00
|
|
|
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
// Scope manipulation handled by caller.
|
2008-04-04 10:12:32 +04:00
|
|
|
TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext,
|
|
|
|
D.getIdentifierLoc(),
|
2008-03-15 09:12:44 +03:00
|
|
|
D.getIdentifier(),
|
2008-03-16 00:32:50 +03:00
|
|
|
T, LastDeclarator);
|
2007-08-29 00:14:24 +04:00
|
|
|
if (D.getInvalidType())
|
|
|
|
NewTD->setInvalidDecl();
|
|
|
|
return NewTD;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2007-09-15 22:49:24 +04:00
|
|
|
/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the
|
2007-07-11 21:01:13 +04: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-15 22:49:24 +04:00
|
|
|
Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
|
2007-07-11 21:01:13 +04:00
|
|
|
SourceLocation KWLoc, IdentifierInfo *Name,
|
|
|
|
SourceLocation NameLoc, AttributeList *Attr) {
|
|
|
|
// If this is a use of an existing tag, it must have a name.
|
|
|
|
assert((Name != 0 || TK == TK_Definition) &&
|
|
|
|
"Nameless record must be a definition!");
|
|
|
|
|
2008-06-10 03:19:58 +04:00
|
|
|
TagDecl::TagKind Kind;
|
2007-07-11 21:01:13 +04:00
|
|
|
switch (TagType) {
|
|
|
|
default: assert(0 && "Unknown tag type!");
|
2008-06-10 03:19:58 +04:00
|
|
|
case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
|
|
|
|
case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
|
|
|
|
case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
|
|
|
|
case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
// Two code paths: a new one for structs/unions/classes where we create
|
|
|
|
// separate decls for forward declarations, and an old (eventually to
|
|
|
|
// be removed) code path for enums.
|
|
|
|
if (Kind != TagDecl::TK_enum)
|
|
|
|
return ActOnTagStruct(S, Kind, TK, KWLoc, Name, NameLoc, Attr);
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// If this is a named struct, check to see if there was a previous forward
|
|
|
|
// declaration or definition.
|
2008-04-27 17:50:30 +04:00
|
|
|
// Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
|
2008-09-03 01:26:19 +04:00
|
|
|
ScopedDecl *PrevDecl =
|
|
|
|
dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag, S));
|
|
|
|
|
|
|
|
if (PrevDecl) {
|
2008-04-27 17:50:30 +04:00
|
|
|
assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) &&
|
|
|
|
"unexpected Decl type");
|
|
|
|
if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
|
2008-07-03 07:30:58 +04: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
|
2008-04-27 17:50:30 +04:00
|
|
|
// rementions the tag), reuse the decl.
|
2008-05-10 03:39:43 +04:00
|
|
|
if (TK == TK_Reference ||
|
|
|
|
IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
|
2008-07-03 07:30:58 +04:00
|
|
|
// Make sure that this wasn't declared as an enum and now used as a
|
|
|
|
// struct or something similar.
|
2008-06-10 03:19:58 +04:00
|
|
|
if (PrevTagDecl->getTagKind() != Kind) {
|
2008-04-27 17:50:30 +04:00
|
|
|
Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_use);
|
2008-07-03 07:30:58 +04:00
|
|
|
// Recover by making this an anonymous redefinition.
|
2008-04-27 17:50:30 +04:00
|
|
|
Name = 0;
|
2008-07-03 07:30:58 +04:00
|
|
|
PrevDecl = 0;
|
2008-04-27 17:50:30 +04:00
|
|
|
} else {
|
2008-07-03 07:30:58 +04:00
|
|
|
// If this is a use or a forward declaration, we're good.
|
|
|
|
if (TK != TK_Definition)
|
|
|
|
return PrevDecl;
|
|
|
|
|
|
|
|
// Diagnose attempts to redefine a tag.
|
|
|
|
if (PrevTagDecl->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;
|
|
|
|
}
|
2008-04-27 17:50:30 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-04-27 17:50:30 +04: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.
|
|
|
|
} else {
|
2008-07-16 11:45:46 +04:00
|
|
|
// PrevDecl is a namespace.
|
|
|
|
if (IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
|
2008-09-03 22:03:35 +04:00
|
|
|
// The tag name clashes with a namespace name, issue an error and
|
|
|
|
// recover by making this tag be anonymous.
|
2008-07-16 11:45:46 +04:00
|
|
|
Diag(NameLoc, diag::err_redefinition_different_kind, Name->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
Name = 0;
|
|
|
|
}
|
2007-07-11 21:01:13 +04: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;
|
|
|
|
|
|
|
|
// Otherwise, if this is the first time we've seen this tag, create the decl.
|
|
|
|
TagDecl *New;
|
2008-06-10 03:19:58 +04:00
|
|
|
if (Kind == TagDecl::TK_enum) {
|
2007-07-11 21:01:13 +04:00
|
|
|
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
|
|
|
|
// enum X { A, B, C } D; D should chain to X.
|
2008-04-04 10:12:32 +04:00
|
|
|
New = EnumDecl::Create(Context, CurContext, Loc, Name, 0);
|
2007-07-11 21:01:13 +04:00
|
|
|
// If this is an undefined enum, warn.
|
|
|
|
if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum);
|
2008-06-10 03:19:58 +04:00
|
|
|
} else {
|
|
|
|
// struct/union/class
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
|
|
|
|
// struct X { int A; } D; D should chain to X.
|
2008-07-01 14:37:29 +04:00
|
|
|
if (getLangOptions().CPlusPlus)
|
2008-09-05 21:39:33 +04:00
|
|
|
// FIXME: Look for a way to use RecordDecl for simple structs.
|
2008-09-05 05:34:33 +04:00
|
|
|
New = CXXRecordDecl::Create(Context, Kind, CurContext, Loc, Name);
|
2008-07-01 14:37:29 +04:00
|
|
|
else
|
2008-09-05 05:34:33 +04:00
|
|
|
New = RecordDecl::Create(Context, Kind, CurContext, Loc, Name);
|
2008-07-01 14:37:29 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
// If this has an identifier, add it to the scope stack.
|
|
|
|
if (Name) {
|
2007-08-26 10:24:45 +04: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.
|
2008-04-12 04:47:19 +04:00
|
|
|
PushOnScopeChains(New, S);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-02-06 03:51:33 +03:00
|
|
|
|
2008-06-29 03:58:55 +04:00
|
|
|
if (Attr)
|
|
|
|
ProcessDeclAttributeList(New, Attr);
|
2007-07-11 21:01:13 +04:00
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
/// ActOnTagStruct - New "ActOnTag" logic for structs/unions/classes. Unlike
|
|
|
|
/// the logic for enums, we create separate decls for forward declarations.
|
|
|
|
/// This is called by ActOnTag, but eventually will replace its logic.
|
|
|
|
Sema::DeclTy *Sema::ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK,
|
|
|
|
SourceLocation KWLoc, IdentifierInfo *Name,
|
|
|
|
SourceLocation NameLoc, AttributeList *Attr) {
|
|
|
|
|
|
|
|
// If this is a named struct, check to see if there was a previous forward
|
|
|
|
// declaration or definition.
|
|
|
|
// Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
|
|
|
|
ScopedDecl *PrevDecl =
|
|
|
|
dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag, S));
|
|
|
|
|
|
|
|
if (PrevDecl) {
|
|
|
|
assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) &&
|
|
|
|
"unexpected Decl type");
|
|
|
|
|
|
|
|
if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
|
|
|
|
// 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.
|
|
|
|
if (TK == TK_Reference ||
|
|
|
|
IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
|
|
|
|
// Make sure that this wasn't declared as an enum and now used as a
|
|
|
|
// struct or something similar.
|
|
|
|
if (PrevTagDecl->getTagKind() != Kind) {
|
|
|
|
Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_use);
|
|
|
|
// Recover by making this an anonymous redefinition.
|
|
|
|
Name = 0;
|
|
|
|
PrevDecl = 0;
|
|
|
|
} else {
|
|
|
|
// If this is a use, return the original decl.
|
|
|
|
|
|
|
|
// FIXME: In the future, return a variant or some other clue
|
|
|
|
// for the consumer of this Decl to know it doesn't own it.
|
|
|
|
// For our current ASTs this shouldn't be a problem, but will
|
|
|
|
// need to be changed with DeclGroups.
|
|
|
|
if (TK == TK_Reference)
|
|
|
|
return PrevDecl;
|
|
|
|
|
|
|
|
// The new decl is a definition?
|
|
|
|
if (TK == TK_Definition) {
|
|
|
|
// Diagnose attempts to redefine a tag.
|
|
|
|
if (RecordDecl* DefRecord =
|
|
|
|
cast<RecordDecl>(PrevTagDecl)->getDefinition(Context)) {
|
|
|
|
Diag(NameLoc, diag::err_redefinition, Name->getName());
|
|
|
|
Diag(DefRecord->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;
|
|
|
|
PrevDecl = 0;
|
|
|
|
}
|
|
|
|
// Okay, this is definition of a previously declared or referenced
|
|
|
|
// tag. We're going to create a new Decl.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If we get here we have (another) forward declaration. Just create
|
|
|
|
// a new decl.
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// 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 decl/type. We set PrevDecl to NULL so that the Records
|
|
|
|
// have distinct types.
|
|
|
|
PrevDecl = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// PrevDecl is a namespace.
|
|
|
|
if (IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
|
|
|
|
// The tag name clashes with a namespace name, issue an error and
|
|
|
|
// recover by making this tag be anonymous.
|
|
|
|
Diag(NameLoc, diag::err_redefinition_different_kind, Name->getName());
|
|
|
|
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
|
|
|
|
Name = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// Otherwise, if this is the first time we've seen this tag, create the decl.
|
|
|
|
TagDecl *New;
|
|
|
|
|
|
|
|
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
|
|
|
|
// struct X { int A; } D; D should chain to X.
|
|
|
|
if (getLangOptions().CPlusPlus)
|
2008-09-05 21:39:33 +04:00
|
|
|
// FIXME: Look for a way to use RecordDecl for simple structs.
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
New = CXXRecordDecl::Create(Context, Kind, CurContext, Loc, Name,
|
|
|
|
dyn_cast_or_null<CXXRecordDecl>(PrevDecl));
|
|
|
|
else
|
|
|
|
New = RecordDecl::Create(Context, Kind, CurContext, Loc, Name,
|
|
|
|
dyn_cast_or_null<RecordDecl>(PrevDecl));
|
|
|
|
|
|
|
|
// If this has an identifier, add it to the scope stack.
|
|
|
|
if ((TK == TK_Definition || !PrevDecl) && Name) {
|
|
|
|
// 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.
|
|
|
|
PushOnScopeChains(New, S);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Attr)
|
|
|
|
ProcessDeclAttributeList(New, Attr);
|
|
|
|
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-06-21 23:39:06 +04:00
|
|
|
/// Collect the instance variables declared in an Objective-C object. Used in
|
|
|
|
/// the creation of structures from objects using the @defs directive.
|
2008-08-20 07:26:33 +04:00
|
|
|
static void CollectIvars(ObjCInterfaceDecl *Class, ASTContext& Ctx,
|
2008-07-22 02:17:28 +04:00
|
|
|
llvm::SmallVectorImpl<Sema::DeclTy*> &ivars) {
|
2008-06-21 23:39:06 +04:00
|
|
|
if (Class->getSuperClass())
|
2008-08-20 07:26:33 +04:00
|
|
|
CollectIvars(Class->getSuperClass(), Ctx, ivars);
|
|
|
|
|
|
|
|
// For each ivar, create a fresh ObjCAtDefsFieldDecl.
|
2008-09-03 22:03:35 +04:00
|
|
|
for (ObjCInterfaceDecl::ivar_iterator
|
|
|
|
I=Class->ivar_begin(), E=Class->ivar_end(); I!=E; ++I) {
|
|
|
|
|
2008-08-20 07:26:33 +04:00
|
|
|
ObjCIvarDecl* ID = *I;
|
|
|
|
ivars.push_back(ObjCAtDefsFieldDecl::Create(Ctx, ID->getLocation(),
|
|
|
|
ID->getIdentifier(),
|
|
|
|
ID->getType(),
|
|
|
|
ID->getBitWidth()));
|
|
|
|
}
|
2008-06-21 23:39:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Called whenever @defs(ClassName) is encountered in the source. Inserts the
|
|
|
|
/// instance variables of ClassName into Decls.
|
|
|
|
void Sema::ActOnDefs(Scope *S, SourceLocation DeclStart,
|
|
|
|
IdentifierInfo *ClassName,
|
2008-07-22 02:17:28 +04:00
|
|
|
llvm::SmallVectorImpl<DeclTy*> &Decls) {
|
2008-06-21 23:39:06 +04:00
|
|
|
// Check that ClassName is a valid class
|
|
|
|
ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName);
|
|
|
|
if (!Class) {
|
|
|
|
Diag(DeclStart, diag::err_undef_interface, ClassName->getName());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Collect the instance variables
|
2008-08-20 07:26:33 +04:00
|
|
|
CollectIvars(Class, Context, Decls);
|
2008-06-21 23:39:06 +04:00
|
|
|
}
|
|
|
|
|
2008-06-04 01:01:11 +04:00
|
|
|
QualType Sema::TryFixInvalidVariablyModifiedType(QualType T) {
|
|
|
|
// This method tries to turn a variable array into a constant
|
|
|
|
// array even when the size isn't an ICE. This is necessary
|
|
|
|
// for compatibility with code that depends on gcc's buggy
|
|
|
|
// constant expression folding, like struct {char x[(int)(char*)2];}
|
|
|
|
if (const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T)) {
|
2008-07-03 08:20:39 +04:00
|
|
|
APValue Result;
|
2008-06-04 01:01:11 +04:00
|
|
|
if (VLATy->getSizeExpr() &&
|
2008-07-11 23:19:21 +04:00
|
|
|
VLATy->getSizeExpr()->tryEvaluate(Result, Context) && Result.isInt()) {
|
|
|
|
llvm::APSInt &Res = Result.getInt();
|
|
|
|
if (Res > llvm::APSInt(Res.getBitWidth(), Res.isUnsigned()))
|
|
|
|
return Context.getConstantArrayType(VLATy->getElementType(),
|
|
|
|
Res, ArrayType::Normal, 0);
|
2008-06-04 01:01:11 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
2007-09-15 22:49:24 +04:00
|
|
|
/// ActOnField - Each field of a struct/union/class is passed into this in order
|
2007-07-11 21:01:13 +04:00
|
|
|
/// to create a FieldDecl object for it.
|
2008-04-11 03:32:45 +04:00
|
|
|
Sema::DeclTy *Sema::ActOnField(Scope *S,
|
2007-07-11 21:01:13 +04:00
|
|
|
SourceLocation DeclStart,
|
|
|
|
Declarator &D, ExprTy *BitfieldWidth) {
|
|
|
|
IdentifierInfo *II = D.getIdentifier();
|
|
|
|
Expr *BitWidth = (Expr*)BitfieldWidth;
|
|
|
|
SourceLocation Loc = DeclStart;
|
|
|
|
if (II) Loc = D.getIdentifierLoc();
|
|
|
|
|
|
|
|
// FIXME: Unnamed fields can be handled in various different ways, for
|
|
|
|
// example, unnamed unions inject all members into the struct namespace!
|
2008-09-03 22:03:35 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
if (BitWidth) {
|
|
|
|
// TODO: Validate.
|
|
|
|
//printf("WARNING: BITFIELDS IGNORED!\n");
|
|
|
|
|
|
|
|
// 6.7.2.1p3
|
|
|
|
// 6.7.2.1p4
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Not a bitfield.
|
|
|
|
|
|
|
|
// validate II.
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType T = GetTypeForDeclarator(D, S);
|
2007-08-29 00:14:24 +04:00
|
|
|
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
|
|
|
bool InvalidDecl = false;
|
2007-08-31 21:20:07 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// C99 6.7.2.1p8: A member of a structure or union may have any type other
|
|
|
|
// than a variably modified type.
|
2008-02-15 15:53:51 +03:00
|
|
|
if (T->isVariablyModifiedType()) {
|
2008-06-04 01:01:11 +04:00
|
|
|
QualType FixedTy = TryFixInvalidVariablyModifiedType(T);
|
|
|
|
if (!FixedTy.isNull()) {
|
|
|
|
Diag(Loc, diag::warn_illegal_constant_array_size, Loc);
|
|
|
|
T = FixedTy;
|
|
|
|
} else {
|
|
|
|
// FIXME: This diagnostic needs work
|
|
|
|
Diag(Loc, diag::err_typecheck_illegal_vla, Loc);
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
// FIXME: Chain fielddecls together.
|
2008-07-01 14:37:29 +04:00
|
|
|
FieldDecl *NewFD;
|
|
|
|
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
// FIXME: Replace CXXFieldDecls with FieldDecls for simple structs.
|
|
|
|
NewFD = CXXFieldDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
|
|
|
|
Loc, II, T, BitWidth);
|
|
|
|
if (II)
|
|
|
|
PushOnScopeChains(NewFD, S);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
NewFD = FieldDecl::Create(Context, Loc, II, T, BitWidth);
|
2007-09-12 01:17:26 +04:00
|
|
|
|
2008-06-29 04:02:00 +04:00
|
|
|
ProcessDeclAttributes(NewFD, D);
|
2008-02-16 03:29:18 +03:00
|
|
|
|
2007-08-29 00:14:24 +04:00
|
|
|
if (D.getInvalidType() || InvalidDecl)
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
return NewFD;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2007-10-01 20:53:59 +04:00
|
|
|
/// TranslateIvarVisibility - Translate visibility from a token ID to an
|
|
|
|
/// AST enum value.
|
2008-01-07 22:49:32 +03:00
|
|
|
static ObjCIvarDecl::AccessControl
|
2007-10-01 20:53:59 +04:00
|
|
|
TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
|
2007-09-15 03:09:53 +04:00
|
|
|
switch (ivarVisibility) {
|
2008-01-07 22:49:32 +03: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;
|
2007-10-01 20:53:59 +04:00
|
|
|
default: assert(false && "Unknown visitibility kind");
|
2007-09-15 03:09:53 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-11 20:55:42 +04:00
|
|
|
/// ActOnIvar - Each ivar field of an objective-c class is passed into this
|
|
|
|
/// in order to create an IvarDecl object for it.
|
2008-04-11 03:32:45 +04:00
|
|
|
Sema::DeclTy *Sema::ActOnIvar(Scope *S,
|
2008-04-11 20:55:42 +04:00
|
|
|
SourceLocation DeclStart,
|
|
|
|
Declarator &D, ExprTy *BitfieldWidth,
|
|
|
|
tok::ObjCKeywordKind Visibility) {
|
2008-04-11 03:32:45 +04:00
|
|
|
IdentifierInfo *II = D.getIdentifier();
|
|
|
|
Expr *BitWidth = (Expr*)BitfieldWidth;
|
|
|
|
SourceLocation Loc = DeclStart;
|
|
|
|
if (II) Loc = D.getIdentifierLoc();
|
|
|
|
|
|
|
|
// FIXME: Unnamed fields can be handled in various different ways, for
|
|
|
|
// example, unnamed unions inject all members into the struct namespace!
|
|
|
|
|
|
|
|
|
|
|
|
if (BitWidth) {
|
|
|
|
// TODO: Validate.
|
|
|
|
//printf("WARNING: BITFIELDS IGNORED!\n");
|
|
|
|
|
|
|
|
// 6.7.2.1p3
|
|
|
|
// 6.7.2.1p4
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Not a bitfield.
|
|
|
|
|
|
|
|
// validate II.
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType T = GetTypeForDeclarator(D, S);
|
|
|
|
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
|
|
|
bool InvalidDecl = false;
|
|
|
|
|
|
|
|
// C99 6.7.2.1p8: A member of a structure or union may have any type other
|
|
|
|
// than a variably modified type.
|
|
|
|
if (T->isVariablyModifiedType()) {
|
|
|
|
// FIXME: This diagnostic needs work
|
|
|
|
Diag(Loc, diag::err_typecheck_illegal_vla, Loc);
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
|
|
|
|
2008-07-23 22:04:17 +04:00
|
|
|
// Get the visibility (access control) for this ivar.
|
|
|
|
ObjCIvarDecl::AccessControl ac =
|
|
|
|
Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility)
|
|
|
|
: ObjCIvarDecl::None;
|
|
|
|
|
|
|
|
// Construct the decl.
|
|
|
|
ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, Loc, II, T, ac,
|
2008-07-16 22:22:22 +04:00
|
|
|
(Expr *)BitfieldWidth);
|
2008-04-11 03:32:45 +04:00
|
|
|
|
2008-07-23 22:04:17 +04:00
|
|
|
// Process attributes attached to the ivar.
|
2008-06-29 04:02:00 +04:00
|
|
|
ProcessDeclAttributes(NewID, D);
|
2008-04-11 03:32:45 +04:00
|
|
|
|
|
|
|
if (D.getInvalidType() || InvalidDecl)
|
|
|
|
NewID->setInvalidDecl();
|
2008-07-23 22:04:17 +04:00
|
|
|
|
2008-04-11 03:32:45 +04:00
|
|
|
return NewID;
|
|
|
|
}
|
|
|
|
|
2007-09-29 04:54:24 +04:00
|
|
|
void Sema::ActOnFields(Scope* S,
|
2007-10-04 04:45:27 +04:00
|
|
|
SourceLocation RecLoc, DeclTy *RecDecl,
|
2007-09-15 22:49:24 +04:00
|
|
|
DeclTy **Fields, unsigned NumFields,
|
2008-04-11 03:32:45 +04:00
|
|
|
SourceLocation LBrac, SourceLocation RBrac) {
|
2007-09-15 02:20:54 +04:00
|
|
|
Decl *EnclosingDecl = static_cast<Decl*>(RecDecl);
|
|
|
|
assert(EnclosingDecl && "missing record or interface decl");
|
|
|
|
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
if (Record)
|
|
|
|
if (RecordDecl* DefRecord = Record->getDefinition(Context)) {
|
|
|
|
// Diagnose code like:
|
|
|
|
// struct S { struct S {} X; };
|
|
|
|
// We discover this when we complete the outer S. Reject and ignore the
|
|
|
|
// outer S.
|
|
|
|
Diag(DefRecord->getLocation(), diag::err_nested_redefinition,
|
|
|
|
DefRecord->getKindName());
|
|
|
|
Diag(RecLoc, diag::err_previous_definition);
|
|
|
|
Record->setInvalidDecl();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// Verify that all the fields are okay.
|
|
|
|
unsigned NumNamedMembers = 0;
|
|
|
|
llvm::SmallVector<FieldDecl*, 32> RecFields;
|
|
|
|
llvm::SmallSet<const IdentifierInfo*, 32> FieldIDs;
|
2007-09-15 02:20:54 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
for (unsigned i = 0; i != NumFields; ++i) {
|
2007-09-14 20:27:55 +04:00
|
|
|
|
2007-09-15 02:20:54 +04: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-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
// Get the type for the field.
|
2007-08-01 01:33:24 +04:00
|
|
|
Type *FDTy = FD->getType().getTypePtr();
|
2007-09-15 03:09:53 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// C99 6.7.2.1p2 - A field may not be a function type.
|
2007-08-01 01:33:24 +04:00
|
|
|
if (FDTy->isFunctionType()) {
|
2007-09-15 02:20:54 +04:00
|
|
|
Diag(FD->getLocation(), diag::err_field_declared_as_function,
|
2007-07-11 21:01:13 +04:00
|
|
|
FD->getName());
|
2007-09-15 02:20:54 +04:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-07-11 21:01:13 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// C99 6.7.2.1p2 - A field may not be an incomplete type except...
|
|
|
|
if (FDTy->isIncompleteType()) {
|
2007-09-14 20:27:55 +04:00
|
|
|
if (!Record) { // Incomplete ivar type is always an error.
|
2007-10-04 04:45:27 +04:00
|
|
|
Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName());
|
2007-09-15 02:20:54 +04:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-10-04 04:45:27 +04:00
|
|
|
continue;
|
2007-09-14 20:27:55 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
if (i != NumFields-1 || // ... that the last member ...
|
2008-06-10 03:19:58 +04:00
|
|
|
!Record->isStruct() || // ... of a structure ...
|
2007-08-01 01:33:24 +04:00
|
|
|
!FDTy->isArrayType()) { //... may have incomplete array type.
|
2007-07-11 21:01:13 +04:00
|
|
|
Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName());
|
2007-09-15 02:20:54 +04:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-07-11 21:01:13 +04:00
|
|
|
continue;
|
|
|
|
}
|
2007-09-14 20:27:55 +04:00
|
|
|
if (NumNamedMembers < 1) { //... must have more than named member ...
|
2007-07-11 21:01:13 +04:00
|
|
|
Diag(FD->getLocation(), diag::err_flexible_array_empty_struct,
|
|
|
|
FD->getName());
|
2007-09-15 02:20:54 +04:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-07-11 21:01:13 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Okay, we have a legal flexible array member at the end of the struct.
|
2007-09-14 20:27:55 +04:00
|
|
|
if (Record)
|
|
|
|
Record->setHasFlexibleArrayMember(true);
|
2007-07-11 21:01:13 +04: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 01:33:24 +04:00
|
|
|
if (const RecordType *FDTTy = FDTy->getAsRecordType()) {
|
2007-07-11 21:01:13 +04:00
|
|
|
if (FDTTy->getDecl()->hasFlexibleArrayMember()) {
|
|
|
|
// If this is a member of a union, then entire union becomes "flexible".
|
2008-06-10 03:19:58 +04:00
|
|
|
if (Record && Record->isUnion()) {
|
2007-07-11 21:01:13 +04:00
|
|
|
Record->setHasFlexibleArrayMember(true);
|
|
|
|
} 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 02:20:54 +04:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-07-11 21:01:13 +04: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 04:45:27 +04:00
|
|
|
if (Record)
|
2007-09-14 20:27:55 +04:00
|
|
|
Record->setHasFlexibleArrayMember(true);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-10-13 02:10:42 +04:00
|
|
|
/// A field cannot be an Objective-c object
|
2008-01-07 22:49:32 +03:00
|
|
|
if (FDTy->isObjCInterfaceType()) {
|
2007-10-13 02:10:42 +04:00
|
|
|
Diag(FD->getLocation(), diag::err_statically_allocated_object,
|
|
|
|
FD->getName());
|
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
|
|
|
continue;
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
// Keep track of the number of named members.
|
|
|
|
if (IdentifierInfo *II = FD->getIdentifier()) {
|
|
|
|
// Detect duplicate member names.
|
|
|
|
if (!FieldIDs.insert(II)) {
|
|
|
|
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 02:20:54 +04:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
2007-07-11 21:01:13 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
++NumNamedMembers;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Okay, we successfully defined 'Record'.
|
2008-02-06 03:51:33 +03:00
|
|
|
if (Record) {
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55839 91177308-0d34-0410-b5e6-96231b3b80d8
2008-09-05 21:16:31 +04:00
|
|
|
Record->defineBody(Context, &RecFields[0], RecFields.size());
|
2008-08-09 04:58:37 +04:00
|
|
|
// If this is a C++ record, HandleTagDeclDefinition will be invoked in
|
|
|
|
// Sema::ActOnFinishCXXClassDef.
|
|
|
|
if (!isa<CXXRecordDecl>(Record))
|
|
|
|
Consumer.HandleTagDeclDefinition(Record);
|
2008-02-06 03:51:33 +03:00
|
|
|
} else {
|
2008-02-06 01:40:55 +03:00
|
|
|
ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(&RecFields[0]);
|
|
|
|
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl))
|
|
|
|
ID->addInstanceVariablesToClass(ClsFields, RecFields.size(), RBrac);
|
|
|
|
else if (ObjCImplementationDecl *IMPDecl =
|
|
|
|
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
|
2008-01-07 22:49:32 +03:00
|
|
|
assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl");
|
|
|
|
IMPDecl->ObjCAddInstanceVariablesToClassImpl(ClsFields, RecFields.size());
|
2007-10-31 21:48:14 +03:00
|
|
|
CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac);
|
2007-09-26 22:27:25 +04:00
|
|
|
}
|
2007-09-15 01:08:27 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2007-09-15 22:49:24 +04:00
|
|
|
Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl,
|
2007-07-11 21:01:13 +04:00
|
|
|
DeclTy *lastEnumConst,
|
|
|
|
SourceLocation IdLoc, IdentifierInfo *Id,
|
|
|
|
SourceLocation EqualLoc, ExprTy *val) {
|
2008-04-04 10:12:32 +04:00
|
|
|
EnumDecl *TheEnumDecl = cast<EnumDecl>(static_cast<Decl*>(theEnumDecl));
|
2007-07-11 21:01:13 +04:00
|
|
|
EnumConstantDecl *LastEnumConst =
|
|
|
|
cast_or_null<EnumConstantDecl>(static_cast<Decl*>(lastEnumConst));
|
|
|
|
Expr *Val = static_cast<Expr*>(val);
|
|
|
|
|
2007-08-26 10:24:45 +04: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-07-11 21:01:13 +04:00
|
|
|
// Verify that there isn't already something declared with this name in this
|
|
|
|
// scope.
|
2008-04-02 18:35:35 +04:00
|
|
|
if (Decl *PrevDecl = LookupDecl(Id, Decl::IDNS_Ordinary, S)) {
|
2008-07-17 01:01:53 +04:00
|
|
|
// When in C++, we may get a TagDecl with the same name; in this case the
|
|
|
|
// enum constant will 'hide' the tag.
|
|
|
|
assert((getLangOptions().CPlusPlus || !isa<TagDecl>(PrevDecl)) &&
|
|
|
|
"Received TagDecl when not in C++!");
|
|
|
|
if (!isa<TagDecl>(PrevDecl) &&
|
|
|
|
IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
|
2007-07-11 21:01:13 +04:00
|
|
|
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);
|
2008-02-26 03:33:57 +03:00
|
|
|
delete Val;
|
2007-07-11 21:01:13 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::APSInt EnumVal(32);
|
|
|
|
QualType EltTy;
|
|
|
|
if (Val) {
|
2007-08-28 01:16:18 +04:00
|
|
|
// Make sure to promote the operand type to int.
|
|
|
|
UsualUnaryConversions(Val);
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// C99 6.7.2.2p2: Make sure we have an integer constant expression.
|
|
|
|
SourceLocation ExpLoc;
|
2007-07-16 03:26:56 +04:00
|
|
|
if (!Val->isIntegerConstantExpr(EnumVal, Context, &ExpLoc)) {
|
2007-07-11 21:01:13 +04:00
|
|
|
Diag(ExpLoc, diag::err_enum_value_not_integer_constant_expr,
|
|
|
|
Id->getName());
|
2008-02-26 03:33:57 +03:00
|
|
|
delete Val;
|
2007-08-27 21:37:24 +04:00
|
|
|
Val = 0; // Just forget about it.
|
2007-08-29 20:03:41 +04:00
|
|
|
} else {
|
|
|
|
EltTy = Val->getType();
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2007-08-27 21:37:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Val) {
|
|
|
|
if (LastEnumConst) {
|
|
|
|
// Assign the last value + 1.
|
|
|
|
EnumVal = LastEnumConst->getInitVal();
|
|
|
|
++EnumVal;
|
2007-08-28 01:16:18 +04:00
|
|
|
|
|
|
|
// Check for overflow on increment.
|
|
|
|
if (EnumVal < LastEnumConst->getInitVal())
|
|
|
|
Diag(IdLoc, diag::warn_enum_value_overflow);
|
|
|
|
|
2007-08-27 21:37:24 +04:00
|
|
|
EltTy = LastEnumConst->getType();
|
|
|
|
} else {
|
|
|
|
// First value, set to zero.
|
|
|
|
EltTy = Context.IntTy;
|
2008-03-05 21:54:05 +03:00
|
|
|
EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
|
2007-08-27 21:37:24 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-03-15 09:12:44 +03:00
|
|
|
EnumConstantDecl *New =
|
2008-04-04 10:12:32 +04:00
|
|
|
EnumConstantDecl::Create(Context, TheEnumDecl, IdLoc, Id, EltTy,
|
|
|
|
Val, EnumVal,
|
2008-03-16 00:32:50 +03:00
|
|
|
LastEnumConst);
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
// Register this decl in the current scope stack.
|
2008-04-12 04:47:19 +04:00
|
|
|
PushOnScopeChains(New, S);
|
2007-07-11 21:01:13 +04:00
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2008-08-07 18:08:16 +04:00
|
|
|
// FIXME: For consistency with ActOnFields(), we should have the parser
|
|
|
|
// pass in the source location for the left/right braces.
|
2007-09-15 22:49:24 +04:00
|
|
|
void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
|
2007-07-11 21:01:13 +04:00
|
|
|
DeclTy **Elements, unsigned NumElements) {
|
|
|
|
EnumDecl *Enum = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX));
|
|
|
|
|
2008-08-07 18:08:16 +04:00
|
|
|
if (Enum && Enum->isDefinition()) {
|
|
|
|
// Diagnose code like:
|
|
|
|
// enum e0 {
|
|
|
|
// E0 = sizeof(enum e0 { E1 })
|
|
|
|
// };
|
|
|
|
Diag(Enum->getLocation(), diag::err_nested_redefinition,
|
|
|
|
Enum->getName());
|
|
|
|
Diag(EnumLoc, diag::err_previous_definition);
|
|
|
|
Enum->setInvalidDecl();
|
|
|
|
return;
|
|
|
|
}
|
2007-08-28 09:10:31 +04: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.
|
2008-03-05 21:54:05 +03:00
|
|
|
unsigned IntWidth = Context.Target.getIntWidth();
|
2007-08-28 09:10:31 +04:00
|
|
|
|
2007-08-28 10:15:15 +04: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-07-11 21:01:13 +04:00
|
|
|
EnumConstantDecl *EltList = 0;
|
|
|
|
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 09:27:00 +04:00
|
|
|
|
|
|
|
// If the enum value doesn't fit in an int, emit an extension warning.
|
|
|
|
const llvm::APSInt &InitVal = ECD->getInitVal();
|
2008-02-26 03:33:57 +03:00
|
|
|
assert(InitVal.getBitWidth() >= IntWidth &&
|
|
|
|
"Should have promoted value to int");
|
2007-08-28 09:27:00 +04:00
|
|
|
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,
|
2008-08-17 11:19:51 +04:00
|
|
|
InitVal.toString(10));
|
2007-08-28 09:27:00 +04:00
|
|
|
}
|
2007-08-28 10:15:15 +04:00
|
|
|
|
|
|
|
// Keep track of the size of positive and negative values.
|
2008-02-26 03:33:57 +03:00
|
|
|
if (InitVal.isUnsigned() || InitVal.isNonNegative())
|
2008-01-15 00:47:29 +03:00
|
|
|
NumPositiveBits = std::max(NumPositiveBits,
|
|
|
|
(unsigned)InitVal.getActiveBits());
|
2007-08-28 10:15:15 +04:00
|
|
|
else
|
2008-01-15 00:47:29 +03:00
|
|
|
NumNegativeBits = std::max(NumNegativeBits,
|
|
|
|
(unsigned)InitVal.getMinSignedBits());
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2007-08-28 10:15:15 +04:00
|
|
|
// Keep track of whether every enum element has type int (very commmon).
|
|
|
|
if (AllElementsInt)
|
|
|
|
AllElementsInt = ECD->getType() == Context.IntTy;
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
ECD->setNextDeclarator(EltList);
|
|
|
|
EltList = ECD;
|
|
|
|
}
|
|
|
|
|
2007-08-28 10:15:15 +04: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-29 21:31:48 +04:00
|
|
|
unsigned BestWidth;
|
2007-08-28 10:15:15 +04:00
|
|
|
|
|
|
|
if (NumNegativeBits) {
|
|
|
|
// If there is a negative value, figure out the smallest integer type (of
|
|
|
|
// int/long/longlong) that fits.
|
2007-08-29 21:31:48 +04:00
|
|
|
if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
|
2007-08-28 10:15:15 +04:00
|
|
|
BestType = Context.IntTy;
|
2007-08-29 21:31:48 +04:00
|
|
|
BestWidth = IntWidth;
|
|
|
|
} else {
|
2008-03-05 21:54:05 +03:00
|
|
|
BestWidth = Context.Target.getLongWidth();
|
2007-12-13 01:39:36 +03:00
|
|
|
|
2007-08-29 21:31:48 +04:00
|
|
|
if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth)
|
2007-08-28 10:15:15 +04:00
|
|
|
BestType = Context.LongTy;
|
|
|
|
else {
|
2008-03-05 21:54:05 +03:00
|
|
|
BestWidth = Context.Target.getLongLongWidth();
|
2007-12-13 01:39:36 +03:00
|
|
|
|
2007-08-29 21:31:48 +04:00
|
|
|
if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
|
2007-08-28 10:15:15 +04: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-29 21:31:48 +04:00
|
|
|
if (NumPositiveBits <= IntWidth) {
|
2007-08-28 10:15:15 +04:00
|
|
|
BestType = Context.UnsignedIntTy;
|
2007-08-29 21:31:48 +04:00
|
|
|
BestWidth = IntWidth;
|
|
|
|
} else if (NumPositiveBits <=
|
2008-03-05 21:54:05 +03:00
|
|
|
(BestWidth = Context.Target.getLongWidth())) {
|
2007-08-28 10:15:15 +04:00
|
|
|
BestType = Context.UnsignedLongTy;
|
2008-03-05 21:54:05 +03:00
|
|
|
} else {
|
|
|
|
BestWidth = Context.Target.getLongLongWidth();
|
2007-08-29 21:31:48 +04:00
|
|
|
assert(NumPositiveBits <= BestWidth &&
|
2007-08-28 10:15:15 +04:00
|
|
|
"How could an initializer get larger than ULL?");
|
|
|
|
BestType = Context.UnsignedLongLongTy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-29 21:31:48 +04: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'.
|
2008-02-26 03:33:57 +03:00
|
|
|
if (ECD->getType() == Context.IntTy) {
|
|
|
|
// Make sure the init value is signed.
|
|
|
|
llvm::APSInt IV = ECD->getInitVal();
|
|
|
|
IV.setIsSigned(true);
|
|
|
|
ECD->setInitVal(IV);
|
2007-08-29 21:31:48 +04:00
|
|
|
continue; // Already int type.
|
2008-02-26 03:33:57 +03:00
|
|
|
}
|
2007-08-29 21:31:48 +04:00
|
|
|
|
|
|
|
// 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 10:15:15 +04:00
|
|
|
|
2007-08-28 22:24:31 +04:00
|
|
|
Enum->defineElements(EltList, BestType);
|
2008-02-06 03:51:33 +03:00
|
|
|
Consumer.HandleTagDeclDefinition(Enum);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-02-08 03:33:21 +03:00
|
|
|
Sema::DeclTy *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
|
|
|
|
ExprTy *expr) {
|
|
|
|
StringLiteral *AsmString = cast<StringLiteral>((Expr*)expr);
|
|
|
|
|
2008-03-16 03:16:02 +03:00
|
|
|
return FileScopeAsmDecl::Create(Context, Loc, AsmString);
|
2008-02-08 03:33:21 +03:00
|
|
|
}
|
|
|
|
|
2008-01-12 10:05:38 +03:00
|
|
|
Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc,
|
2008-02-26 00:04:36 +03:00
|
|
|
SourceLocation LBrace,
|
|
|
|
SourceLocation RBrace,
|
|
|
|
const char *Lang,
|
|
|
|
unsigned StrSize,
|
|
|
|
DeclTy *D) {
|
2008-01-12 10:05:38 +03:00
|
|
|
LinkageSpecDecl::LanguageIDs Language;
|
|
|
|
Decl *dcl = static_cast<Decl *>(D);
|
|
|
|
if (strncmp(Lang, "\"C\"", StrSize) == 0)
|
|
|
|
Language = LinkageSpecDecl::lang_c;
|
|
|
|
else if (strncmp(Lang, "\"C++\"", StrSize) == 0)
|
|
|
|
Language = LinkageSpecDecl::lang_cxx;
|
|
|
|
else {
|
|
|
|
Diag(Loc, diag::err_bad_language);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Add all the various semantics of linkage specifications
|
2008-03-16 03:16:02 +03:00
|
|
|
return LinkageSpecDecl::Create(Context, Loc, Language, dcl);
|
2008-01-12 10:05:38 +03:00
|
|
|
}
|