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"
|
2008-10-14 09:35:18 +04:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
using namespace clang;
|
|
|
|
|
2008-11-08 19:45:02 +03:00
|
|
|
Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S,
|
|
|
|
const CXXScopeSpec *SS) {
|
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-11-07 23:08:42 +03:00
|
|
|
std::string Sema::getTypeAsString(TypeTy *Type) {
|
|
|
|
QualType Ty = QualType::getFromOpaquePtr(Type);
|
|
|
|
return Ty.getAsString();
|
|
|
|
}
|
|
|
|
|
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*/);
|
2008-09-10 01:18:04 +04:00
|
|
|
if (I != IdResolver.end() && 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-10-21 20:13:35 +04:00
|
|
|
return;
|
|
|
|
}
|
2008-10-23 03:08:24 +04:00
|
|
|
} else if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
|
|
|
|
FunctionDecl *FD = cast<FunctionDecl>(D);
|
2008-10-21 20:13:35 +04:00
|
|
|
// We are pushing the name of a function, which might be an
|
|
|
|
// overloaded name.
|
|
|
|
IdentifierResolver::iterator
|
|
|
|
I = IdResolver.begin(FD->getIdentifier(),
|
|
|
|
FD->getDeclContext(), false/*LookInParentCtx*/);
|
|
|
|
if (I != IdResolver.end() &&
|
|
|
|
IdResolver.isDeclInScope(*I, FD->getDeclContext(), S) &&
|
|
|
|
(isa<OverloadedFunctionDecl>(*I) || isa<FunctionDecl>(*I))) {
|
|
|
|
// There is already a declaration with the same name in the same
|
|
|
|
// scope. It must be a function or an overloaded function.
|
|
|
|
OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(*I);
|
|
|
|
if (!Ovl) {
|
|
|
|
// We haven't yet overloaded this function. Take the existing
|
|
|
|
// FunctionDecl and put it into an OverloadedFunctionDecl.
|
|
|
|
Ovl = OverloadedFunctionDecl::Create(Context,
|
|
|
|
FD->getDeclContext(),
|
|
|
|
FD->getIdentifier());
|
|
|
|
Ovl->addOverload(dyn_cast<FunctionDecl>(*I));
|
|
|
|
|
|
|
|
// Remove the name binding to the existing FunctionDecl...
|
|
|
|
IdResolver.RemoveDecl(*I);
|
|
|
|
|
|
|
|
// ... and put the OverloadedFunctionDecl in its place.
|
|
|
|
IdResolver.AddDecl(Ovl);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have an OverloadedFunctionDecl. Add the new FunctionDecl
|
|
|
|
// to its list of overloads.
|
|
|
|
Ovl->addOverload(FD);
|
|
|
|
|
2008-05-10 03:39:43 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2008-10-21 20:13:35 +04:00
|
|
|
|
2008-05-10 03:39:43 +04:00
|
|
|
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;
|
|
|
|
|
2008-09-28 09:54:29 +04:00
|
|
|
if (Context.BuiltinInfo.hasVAListUse(BID))
|
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) {
|
2008-09-09 18:32:20 +04:00
|
|
|
// Allow multiple definitions for ObjC built-in typedefs.
|
|
|
|
// FIXME: Verify the underlying types are equivalent!
|
|
|
|
if (getLangOptions().ObjC1) {
|
|
|
|
const IdentifierInfo *typeIdent = New->getIdentifier();
|
|
|
|
if (typeIdent == Ident_id) {
|
|
|
|
Context.setObjCIdType(New);
|
|
|
|
return New;
|
|
|
|
} else if (typeIdent == Ident_Class) {
|
|
|
|
Context.setObjCClassType(New);
|
|
|
|
return New;
|
|
|
|
} else if (typeIdent == Ident_SEL) {
|
|
|
|
Context.setObjCSelType(New);
|
|
|
|
return New;
|
|
|
|
} else if (typeIdent == Ident_Protocol) {
|
|
|
|
Context.setObjCProtoType(New->getUnderlyingType());
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
// Fall through - the typedef name was not a builtin type.
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
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).
|
2008-09-12 22:10:20 +04:00
|
|
|
if (PP.getDiagnostics().getSuppressSystemWarnings()) {
|
|
|
|
SourceManager &SrcMgr = Context.getSourceManager();
|
|
|
|
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-10-21 20:13:35 +04:00
|
|
|
/// Redeclaration will be set true if this New is a redeclaration OldD.
|
|
|
|
///
|
|
|
|
/// In C++, New and Old must be declarations that are not
|
|
|
|
/// overloaded. Use IsOverload to determine whether New and Old are
|
|
|
|
/// overloaded, and to select the Old declaration that New should be
|
|
|
|
/// merged with.
|
2008-04-21 06:02:58 +04:00
|
|
|
FunctionDecl *
|
|
|
|
Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
|
2008-10-21 20:13:35 +04:00
|
|
|
assert(!isa<OverloadedFunctionDecl>(OldD) &&
|
|
|
|
"Cannot merge with an overloaded function declaration");
|
|
|
|
|
2008-04-21 06:02:58 +04:00
|
|
|
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-10-21 20:13:35 +04:00
|
|
|
|
|
|
|
// Determine whether the previous declaration was a definition,
|
|
|
|
// implicit declaration, or a declaration.
|
|
|
|
diag::kind PrevDiag;
|
|
|
|
if (Old->isThisDeclarationADefinition())
|
|
|
|
PrevDiag = diag::err_previous_definition;
|
|
|
|
else if (Old->isImplicit())
|
|
|
|
PrevDiag = diag::err_previous_implicit_declaration;
|
|
|
|
else
|
|
|
|
PrevDiag = diag::err_previous_declaration;
|
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-10-21 20:13:35 +04:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
// (C++98 13.1p2):
|
|
|
|
// Certain function declarations cannot be overloaded:
|
|
|
|
// -- Function declarations that differ only in the return type
|
|
|
|
// cannot be overloaded.
|
|
|
|
QualType OldReturnType
|
|
|
|
= cast<FunctionType>(OldQType.getTypePtr())->getResultType();
|
|
|
|
QualType NewReturnType
|
|
|
|
= cast<FunctionType>(NewQType.getTypePtr())->getResultType();
|
|
|
|
if (OldReturnType != NewReturnType) {
|
|
|
|
Diag(New->getLocation(), diag::err_ovl_diff_return_type);
|
|
|
|
Diag(Old->getLocation(), PrevDiag);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
|
|
|
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
|
|
|
|
const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
|
|
|
|
if (OldMethod && NewMethod) {
|
|
|
|
// -- Member function declarations with the same name and the
|
|
|
|
// same parameter types cannot be overloaded if any of them
|
|
|
|
// is a static member function declaration.
|
|
|
|
if (OldMethod->isStatic() || NewMethod->isStatic()) {
|
|
|
|
Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member);
|
|
|
|
Diag(Old->getLocation(), PrevDiag);
|
|
|
|
return New;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// (C++98 8.3.5p3):
|
|
|
|
// All declarations for a function shall agree exactly in both the
|
|
|
|
// return type and the parameter-type-list.
|
|
|
|
if (OldQType == NewQType) {
|
|
|
|
// We have a redeclaration.
|
|
|
|
MergeAttributes(New, Old);
|
|
|
|
Redeclaration = true;
|
|
|
|
return MergeCXXFunctionDecl(New, Old);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall through for conflicting redeclarations and redefinitions.
|
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
|
|
|
|
|
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) {
|
2008-09-10 01:18:04 +04:00
|
|
|
if (*I != VD && isDeclInScope(*I, VD->getDeclContext(), S)) {
|
2008-08-08 21:50:35 +04:00
|
|
|
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-09-17 18:05:40 +04:00
|
|
|
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
|
|
|
|
if (New->getStorageClass() != VarDecl::Extern && !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-11-05 18:29:30 +03:00
|
|
|
bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
|
|
|
|
SourceLocation InitLoc,
|
|
|
|
std::string InitEntity) {
|
2008-10-29 03:13:59 +03:00
|
|
|
// C++ [dcl.init.ref]p1:
|
|
|
|
// A variable declared to be a T&, that is “reference to type T”
|
|
|
|
// (8.3.2), shall be initialized by an object, or function, of
|
|
|
|
// type T or by an object that can be converted into a T.
|
|
|
|
if (DeclType->isReferenceType())
|
|
|
|
return CheckReferenceInit(Init, 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-11-05 18:29:30 +03:00
|
|
|
return Diag(InitLoc,
|
2008-01-22 02:53:58 +03:00
|
|
|
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
|
|
|
|
2008-11-05 18:29:30 +03:00
|
|
|
// C++ [dcl.init]p14:
|
|
|
|
// -- If the destination type is a (possibly cv-qualified) class
|
|
|
|
// type:
|
|
|
|
if (getLangOptions().CPlusPlus && DeclType->isRecordType()) {
|
|
|
|
QualType DeclTypeC = Context.getCanonicalType(DeclType);
|
|
|
|
QualType InitTypeC = Context.getCanonicalType(Init->getType());
|
|
|
|
|
|
|
|
// -- If the initialization is direct-initialization, or if it is
|
|
|
|
// copy-initialization where the cv-unqualified version of the
|
|
|
|
// source type is the same class as, or a derived class of, the
|
|
|
|
// class of the destination, constructors are considered.
|
|
|
|
if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) ||
|
|
|
|
IsDerivedFrom(InitTypeC, DeclTypeC)) {
|
|
|
|
CXXConstructorDecl *Constructor
|
|
|
|
= PerformInitializationByConstructor(DeclType, &Init, 1,
|
|
|
|
InitLoc, Init->getSourceRange(),
|
|
|
|
InitEntity, IK_Copy);
|
|
|
|
return Constructor == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -- Otherwise (i.e., for the remaining copy-initialization
|
|
|
|
// cases), user-defined conversion sequences that can
|
|
|
|
// convert from the source type to the destination type or
|
|
|
|
// (when a conversion function is used) to a derived class
|
|
|
|
// thereof are enumerated as described in 13.3.1.4, and the
|
|
|
|
// best one is chosen through overload resolution
|
|
|
|
// (13.3). If the conversion cannot be done or is
|
|
|
|
// ambiguous, the initialization is ill-formed. The
|
|
|
|
// function selected is called with the initializer
|
|
|
|
// expression as its argument; if the function is a
|
|
|
|
// constructor, the call initializes a temporary of the
|
|
|
|
// destination type.
|
|
|
|
// FIXME: We're pretending to do copy elision here; return to
|
|
|
|
// this when we have ASTs for such things.
|
|
|
|
if (PerformImplicitConversion(Init, DeclType))
|
|
|
|
return Diag(InitLoc,
|
|
|
|
diag::err_typecheck_convert_incompatible,
|
|
|
|
DeclType.getAsString(), InitEntity,
|
|
|
|
"initializing",
|
|
|
|
Init->getSourceRange());
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-09-30 00:07:05 +04:00
|
|
|
// C99 6.7.8p16.
|
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);
|
2008-11-05 19:20:31 +03:00
|
|
|
} else if (getLangOptions().CPlusPlus) {
|
|
|
|
// C++ [dcl.init]p14:
|
|
|
|
// [...] If the class is an aggregate (8.5.1), and the initializer
|
|
|
|
// is a brace-enclosed list, see 8.5.1.
|
|
|
|
//
|
|
|
|
// Note: 8.5.1 is handled below; here, we diagnose the case where
|
|
|
|
// we have an initializer list and a destination type that is not
|
|
|
|
// an aggregate.
|
|
|
|
// FIXME: In C++0x, this is yet another form of initialization.
|
|
|
|
if (const RecordType *ClassRec = DeclType->getAsRecordType()) {
|
|
|
|
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
|
|
|
|
if (!ClassDecl->isAggregate())
|
|
|
|
return Diag(InitLoc,
|
|
|
|
diag::err_init_non_aggr_init_list,
|
|
|
|
DeclType.getAsString(),
|
|
|
|
Init->getSourceRange());
|
|
|
|
}
|
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-09-10 01:18:04 +04:00
|
|
|
if (PrevDecl && 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-11-05 23:51:48 +03:00
|
|
|
// bool isVirtual = D.getDeclSpec().isVirtualSpecified();
|
2008-10-31 12:07:45 +03:00
|
|
|
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
|
|
|
|
|
2008-07-01 14:37:29 +04:00
|
|
|
FunctionDecl *NewFD;
|
2008-11-05 23:51:48 +03:00
|
|
|
if (D.getKind() == Declarator::DK_Constructor) {
|
2008-10-31 12:07:45 +03:00
|
|
|
// This is a C++ constructor declaration.
|
2008-11-08 01:02:30 +03:00
|
|
|
assert(CurContext->isCXXRecord() &&
|
2008-10-31 12:07:45 +03:00
|
|
|
"Constructors can only be declared in a member context");
|
|
|
|
|
2008-11-05 23:51:48 +03:00
|
|
|
bool isInvalidDecl = CheckConstructorDeclarator(D, R, SC);
|
2008-10-31 12:07:45 +03:00
|
|
|
|
|
|
|
// Create the new declaration
|
|
|
|
NewFD = CXXConstructorDecl::Create(Context,
|
|
|
|
cast<CXXRecordDecl>(CurContext),
|
|
|
|
D.getIdentifierLoc(), II, R,
|
|
|
|
isExplicit, isInline,
|
|
|
|
/*isImplicitlyDeclared=*/false);
|
|
|
|
|
2008-11-05 23:51:48 +03:00
|
|
|
if (isInvalidDecl)
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
} else if (D.getKind() == Declarator::DK_Destructor) {
|
|
|
|
// This is a C++ destructor declaration.
|
2008-11-08 01:02:30 +03:00
|
|
|
if (CurContext->isCXXRecord()) {
|
|
|
|
bool isInvalidDecl = CheckDestructorDeclarator(D, R, SC);
|
2008-11-05 23:51:48 +03:00
|
|
|
|
2008-11-08 01:02:30 +03:00
|
|
|
NewFD = CXXDestructorDecl::Create(Context,
|
|
|
|
cast<CXXRecordDecl>(CurContext),
|
|
|
|
D.getIdentifierLoc(), II, R,
|
|
|
|
isInline,
|
|
|
|
/*isImplicitlyDeclared=*/false);
|
2008-11-05 23:51:48 +03:00
|
|
|
|
2008-11-08 01:02:30 +03:00
|
|
|
if (isInvalidDecl)
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
} else {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
|
|
|
|
// Create a FunctionDecl to satisfy the function definition parsing
|
|
|
|
// code path.
|
|
|
|
NewFD = FunctionDecl::Create(Context, CurContext, D.getIdentifierLoc(),
|
|
|
|
II, R, SC, isInline, LastDeclarator,
|
|
|
|
// FIXME: Move to DeclGroup...
|
|
|
|
D.getDeclSpec().getSourceRange().getBegin());
|
2008-11-05 23:51:48 +03:00
|
|
|
NewFD->setInvalidDecl();
|
2008-11-08 01:02:30 +03:00
|
|
|
}
|
2008-11-07 23:08:42 +03:00
|
|
|
} else if (D.getKind() == Declarator::DK_Conversion) {
|
2008-11-08 01:02:30 +03:00
|
|
|
if (!CurContext->isCXXRecord()) {
|
2008-11-07 23:08:42 +03:00
|
|
|
Diag(D.getIdentifierLoc(),
|
|
|
|
diag::err_conv_function_not_member);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
bool isInvalidDecl = CheckConversionDeclarator(D, R, SC);
|
|
|
|
|
|
|
|
NewFD = CXXConversionDecl::Create(Context,
|
|
|
|
cast<CXXRecordDecl>(CurContext),
|
|
|
|
D.getIdentifierLoc(), II, R,
|
|
|
|
isInline, isExplicit);
|
|
|
|
|
|
|
|
if (isInvalidDecl)
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
}
|
2008-11-08 01:02:30 +03:00
|
|
|
} else if (CurContext->isCXXRecord()) {
|
2008-07-01 14:37:29 +04:00
|
|
|
// 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(),
|
2008-10-03 04:02:03 +04:00
|
|
|
II, R, SC, isInline, LastDeclarator,
|
|
|
|
// FIXME: Move to DeclGroup...
|
|
|
|
D.getDeclSpec().getSourceRange().getBegin());
|
2008-07-01 14:37:29 +04:00
|
|
|
}
|
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-10-24 22:09:54 +04:00
|
|
|
} else if (R->getAsTypedefType()) {
|
|
|
|
// When we're declaring a function with a typedef, as in the
|
|
|
|
// following example, we'll need to synthesize (unnamed)
|
|
|
|
// parameters for use in the declaration.
|
|
|
|
//
|
|
|
|
// @code
|
|
|
|
// typedef void fn(int);
|
|
|
|
// fn f;
|
|
|
|
// @endcode
|
|
|
|
const FunctionTypeProto *FT = R->getAsFunctionTypeProto();
|
|
|
|
if (!FT) {
|
|
|
|
// This is a typedef of a function with no prototype, so we
|
|
|
|
// don't need to do anything.
|
|
|
|
} else if ((FT->getNumArgs() == 0) ||
|
|
|
|
(FT->getNumArgs() == 1 && !FT->isVariadic() &&
|
|
|
|
FT->getArgType(0)->isVoidType())) {
|
|
|
|
// This is a zero-argument function. We don't need to do anything.
|
|
|
|
} else {
|
|
|
|
// Synthesize a parameter for each argument type.
|
|
|
|
llvm::SmallVector<ParmVarDecl*, 16> Params;
|
|
|
|
for (FunctionTypeProto::arg_type_iterator ArgType = FT->arg_type_begin();
|
|
|
|
ArgType != FT->arg_type_end(); ++ArgType) {
|
|
|
|
Params.push_back(ParmVarDecl::Create(Context, CurContext,
|
|
|
|
SourceLocation(), 0,
|
|
|
|
*ArgType, VarDecl::None,
|
|
|
|
0, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
NewFD->setParams(&Params[0], Params.size());
|
|
|
|
}
|
2008-04-08 08:40:51 +04:00
|
|
|
}
|
|
|
|
|
2008-11-05 23:51:48 +03:00
|
|
|
// C++ constructors and destructors are handled by separate
|
|
|
|
// routines, since they don't require any declaration merging (C++
|
|
|
|
// [class.mfct]p2) and they aren't ever pushed into scope, because
|
|
|
|
// they can't be found by name lookup anyway (C++ [class.ctor]p2).
|
|
|
|
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
|
|
|
|
return ActOnConstructorDeclarator(Constructor);
|
|
|
|
else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
|
|
|
|
return ActOnDestructorDeclarator(Destructor);
|
2008-11-07 23:08:42 +03:00
|
|
|
else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
|
|
|
|
return ActOnConversionDeclarator(Conversion);
|
2008-10-31 12:07:45 +03:00
|
|
|
|
2008-11-07 01:13:31 +03:00
|
|
|
// Extra checking for C++ overloaded operators (C++ [over.oper]).
|
|
|
|
if (NewFD->isOverloadedOperator() &&
|
|
|
|
CheckOverloadedOperatorDeclaration(NewFD))
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
|
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 &&
|
2008-09-10 01:18:04 +04:00
|
|
|
(!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, CurContext, S))) {
|
2008-04-21 06:02:58 +04:00
|
|
|
bool Redeclaration = false;
|
2008-10-21 20:13:35 +04:00
|
|
|
|
|
|
|
// If C++, determine whether NewFD is an overload of PrevDecl or
|
|
|
|
// a declaration that requires merging. If it's an overload,
|
|
|
|
// there's no more work to do here; we'll just add the new
|
|
|
|
// function to the scope.
|
|
|
|
OverloadedFunctionDecl::function_iterator MatchedDecl;
|
|
|
|
if (!getLangOptions().CPlusPlus ||
|
|
|
|
!IsOverload(NewFD, PrevDecl, MatchedDecl)) {
|
|
|
|
Decl *OldDecl = PrevDecl;
|
|
|
|
|
|
|
|
// If PrevDecl was an overloaded function, extract the
|
|
|
|
// FunctionDecl that matched.
|
|
|
|
if (isa<OverloadedFunctionDecl>(PrevDecl))
|
|
|
|
OldDecl = *MatchedDecl;
|
|
|
|
|
|
|
|
// NewFD and PrevDecl represent declarations that need to be
|
|
|
|
// merged.
|
|
|
|
NewFD = MergeFunctionDecl(NewFD, OldDecl, Redeclaration);
|
|
|
|
|
|
|
|
if (NewFD == 0) return 0;
|
|
|
|
if (Redeclaration) {
|
|
|
|
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
|
|
|
|
|
|
|
|
if (OldDecl == PrevDecl) {
|
|
|
|
// Remove the name binding for the previous
|
|
|
|
// declaration. We'll add the binding back later, but then
|
|
|
|
// it will refer to the new declaration (which will
|
|
|
|
// contain more information).
|
|
|
|
IdResolver.RemoveDecl(cast<NamedDecl>(PrevDecl));
|
|
|
|
} else {
|
|
|
|
// We need to update the OverloadedFunctionDecl with the
|
|
|
|
// latest declaration of this function, so that name
|
|
|
|
// lookup will always refer to the latest declaration of
|
|
|
|
// this function.
|
|
|
|
*MatchedDecl = NewFD;
|
|
|
|
|
|
|
|
// Add the redeclaration to the current scope, since we'll
|
|
|
|
// be skipping PushOnScopeChains.
|
|
|
|
S->AddDecl(NewFD);
|
|
|
|
|
|
|
|
return NewFD;
|
|
|
|
}
|
|
|
|
}
|
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-11-08 01:02:30 +03:00
|
|
|
if (CurContext->isCXXRecord()) {
|
2008-07-01 14:37:29 +04:00
|
|
|
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-09-09 00:05:47 +04:00
|
|
|
bool ThreadSpecified = D.getDeclSpec().isThreadSpecified();
|
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;
|
|
|
|
}
|
|
|
|
}
|
2008-09-09 00:05:47 +04:00
|
|
|
NewVD = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
|
2008-10-03 04:02:03 +04:00
|
|
|
II, R, SC, LastDeclarator,
|
|
|
|
// FIXME: Move to DeclGroup...
|
|
|
|
D.getDeclSpec().getSourceRange().getBegin());
|
2008-09-09 00:05:47 +04:00
|
|
|
NewVD->setThreadSpecified(ThreadSpecified);
|
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-09-10 01:18:04 +04:00
|
|
|
if (PrevDecl && 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-10-27 14:34:16 +03:00
|
|
|
void Sema::InitializerElementNotConstant(const Expr *Init) {
|
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::err_init_element_not_constant, Init->getSourceRange());
|
|
|
|
}
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
bool Sema::CheckAddressConstantExpressionLValue(const Expr* Init) {
|
|
|
|
switch (Init->getStmtClass()) {
|
|
|
|
default:
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
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;
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-21 07:39:11 +04:00
|
|
|
return true;
|
|
|
|
}
|
2008-05-20 17:48:25 +04:00
|
|
|
if (isa<FunctionDecl>(D))
|
|
|
|
return false;
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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
|
|
|
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sema::CheckAddressConstantExpression(const Expr* Init) {
|
|
|
|
switch (Init->getStmtClass()) {
|
|
|
|
default:
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
return true;
|
2008-10-06 11:26:43 +04:00
|
|
|
case Expr::ParenExprClass:
|
|
|
|
return CheckAddressConstantExpression(cast<ParenExpr>(Init)->getSubExpr());
|
2008-05-20 17:48:25 +04:00
|
|
|
case Expr::StringLiteralClass:
|
|
|
|
case Expr::ObjCStringLiteralClass:
|
|
|
|
return false;
|
2008-10-06 11:26:43 +04:00
|
|
|
case Expr::CallExprClass:
|
|
|
|
// __builtin___CFStringMakeConstantString is a valid constant l-value.
|
|
|
|
if (cast<CallExpr>(Init)->isBuiltinCall() ==
|
|
|
|
Builtin::BI__builtin___CFStringMakeConstantString)
|
|
|
|
return false;
|
|
|
|
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-10-06 11:26:43 +04:00
|
|
|
return true;
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
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());
|
|
|
|
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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-10-28 18:36:24 +03:00
|
|
|
case Expr::CStyleCastExprClass: {
|
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
|
|
|
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::ConditionalOperatorClass: {
|
|
|
|
// FIXME: Should we pedwarn here?
|
|
|
|
const ConditionalOperator *Exp = cast<ConditionalOperator>(Init);
|
|
|
|
if (!Exp->getCond()->getType()->isArithmeticType()) {
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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-10-28 18:36:24 +03:00
|
|
|
case Expr::CStyleCastExprClass: {
|
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:
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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);
|
2008-10-06 10:49:02 +04:00
|
|
|
|
|
|
|
// Allow any constant foldable calls to builtins.
|
|
|
|
if (CE->isBuiltinCall() && CE->isEvaluatable(Context))
|
2008-05-20 17:48:25 +04:00
|
|
|
return false;
|
2008-10-06 10:49:02 +04:00
|
|
|
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::DeclRefExprClass: {
|
|
|
|
const Decl *D = cast<DeclRefExpr>(Init)->getDecl();
|
|
|
|
if (isa<EnumConstantDecl>(D))
|
|
|
|
return false;
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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;
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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:
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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;
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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()) {
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case Expr::ImplicitCastExprClass:
|
2008-10-28 18:36:24 +03:00
|
|
|
case Expr::CStyleCastExprClass: {
|
2008-08-19 03:01:59 +04:00
|
|
|
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-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-09-02 02:08:17 +04:00
|
|
|
return true;
|
2008-05-20 17:48:25 +04:00
|
|
|
}
|
|
|
|
case Expr::ConditionalOperatorClass: {
|
|
|
|
const ConditionalOperator *Exp = cast<ConditionalOperator>(Init);
|
2008-10-06 09:42:39 +04:00
|
|
|
|
|
|
|
// If GNU extensions are disabled, we require all operands to be arithmetic
|
|
|
|
// constant expressions.
|
|
|
|
if (getLangOptions().NoExtensions) {
|
|
|
|
return CheckArithmeticConstantExpression(Exp->getCond()) ||
|
|
|
|
(Exp->getLHS() && CheckArithmeticConstantExpression(Exp->getLHS())) ||
|
|
|
|
CheckArithmeticConstantExpression(Exp->getRHS());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we have to emulate some of the behavior of fold here.
|
|
|
|
// Basically GCC treats things like "4 ? 1 : somefunc()" as a constant
|
|
|
|
// because it can constant fold things away. To retain compatibility with
|
|
|
|
// GCC code, we see if we can fold the condition to a constant (which we
|
|
|
|
// should always be able to do in theory). If so, we only require the
|
|
|
|
// specified arm of the conditional to be a constant. This is a horrible
|
|
|
|
// hack, but is require by real world code that uses __builtin_constant_p.
|
|
|
|
APValue Val;
|
|
|
|
if (!Exp->getCond()->tryEvaluate(Val, Context)) {
|
|
|
|
// If the tryEvaluate couldn't fold it, CheckArithmeticConstantExpression
|
|
|
|
// won't be able to either. Use it to emit the diagnostic though.
|
|
|
|
bool Res = CheckArithmeticConstantExpression(Exp->getCond());
|
|
|
|
assert(Res && "tryEvaluate couldn't evaluate this constant?");
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that the side following the condition is also a constant.
|
|
|
|
const Expr *TrueSide = Exp->getLHS(), *FalseSide = Exp->getRHS();
|
|
|
|
if (Val.getInt() == 0)
|
|
|
|
std::swap(TrueSide, FalseSide);
|
|
|
|
|
|
|
|
if (TrueSide && CheckArithmeticConstantExpression(TrueSide))
|
2008-05-20 17:48:25 +04:00
|
|
|
return true;
|
2008-10-06 09:42:39 +04:00
|
|
|
|
|
|
|
// Okay, the evaluated side evaluates to a constant, so we accept this.
|
|
|
|
// Check to see if the other side is obviously not a constant. If so,
|
|
|
|
// emit a warning that this is a GNU extension.
|
2008-10-06 10:49:02 +04:00
|
|
|
if (FalseSide && !FalseSide->isEvaluatable(Context))
|
2008-10-06 09:42:39 +04:00
|
|
|
Diag(Init->getExprLoc(),
|
|
|
|
diag::ext_typecheck_expression_not_constant_but_accepted,
|
|
|
|
FalseSide->getSourceRange());
|
|
|
|
return false;
|
2008-05-20 17:48:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 (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-10-02 21:12:56 +04:00
|
|
|
// Allow block exprs at top level.
|
|
|
|
if (Init->getType()->isBlockPointerType())
|
|
|
|
return false;
|
|
|
|
|
2008-10-27 14:34:16 +03:00
|
|
|
InitializerElementNotConstant(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
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-11-05 18:29:30 +03:00
|
|
|
if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
|
|
|
|
VDecl->getName()))
|
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-11-05 18:29:30 +03:00
|
|
|
if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
|
|
|
|
VDecl->getName()))
|
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;
|
|
|
|
}
|
|
|
|
|
2008-10-29 03:13:59 +03:00
|
|
|
void Sema::ActOnUninitializedDecl(DeclTy *dcl) {
|
|
|
|
Decl *RealDecl = static_cast<Decl *>(dcl);
|
|
|
|
|
2008-11-07 16:01:22 +03:00
|
|
|
// If there is no declaration, there was an error parsing it. Just ignore it.
|
|
|
|
if (RealDecl == 0)
|
|
|
|
return;
|
|
|
|
|
2008-10-29 03:13:59 +03:00
|
|
|
if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
|
|
|
|
QualType Type = Var->getType();
|
|
|
|
// C++ [dcl.init.ref]p3:
|
|
|
|
// The initializer can be omitted for a reference only in a
|
|
|
|
// parameter declaration (8.3.5), in the declaration of a
|
|
|
|
// function return type, in the declaration of a class member
|
|
|
|
// within its class declaration (9.2), and where the extern
|
|
|
|
// specifier is explicitly used.
|
2008-11-03 23:45:27 +03:00
|
|
|
if (Type->isReferenceType() && Var->getStorageClass() != VarDecl::Extern) {
|
2008-10-29 03:13:59 +03:00
|
|
|
Diag(Var->getLocation(),
|
|
|
|
diag::err_reference_var_requires_init,
|
|
|
|
Var->getName(),
|
|
|
|
SourceRange(Var->getLocation(), Var->getLocation()));
|
2008-11-03 23:45:27 +03:00
|
|
|
Var->setInvalidDecl();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ [dcl.init]p9:
|
|
|
|
//
|
|
|
|
// If no initializer is specified for an object, and the object
|
|
|
|
// is of (possibly cv-qualified) non-POD class type (or array
|
|
|
|
// thereof), the object shall be default-initialized; if the
|
|
|
|
// object is of const-qualified type, the underlying class type
|
|
|
|
// shall have a user-declared default constructor.
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
QualType InitType = Type;
|
|
|
|
if (const ArrayType *Array = Context.getAsArrayType(Type))
|
|
|
|
InitType = Array->getElementType();
|
|
|
|
if (InitType->isRecordType()) {
|
2008-11-05 18:29:30 +03:00
|
|
|
const CXXConstructorDecl *Constructor
|
|
|
|
= PerformInitializationByConstructor(InitType, 0, 0,
|
|
|
|
Var->getLocation(),
|
|
|
|
SourceRange(Var->getLocation(),
|
|
|
|
Var->getLocation()),
|
|
|
|
Var->getName(),
|
|
|
|
IK_Default);
|
2008-11-03 23:45:27 +03:00
|
|
|
if (!Constructor)
|
|
|
|
Var->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
2008-10-29 03:13:59 +03:00
|
|
|
|
2008-10-29 16:50:18 +03:00
|
|
|
#if 0
|
|
|
|
// FIXME: Temporarily disabled because we are not properly parsing
|
|
|
|
// linkage specifications on declarations, e.g.,
|
|
|
|
//
|
|
|
|
// extern "C" const CGPoint CGPointerZero;
|
|
|
|
//
|
2008-10-29 03:13:59 +03:00
|
|
|
// C++ [dcl.init]p9:
|
|
|
|
//
|
|
|
|
// If no initializer is specified for an object, and the
|
|
|
|
// object is of (possibly cv-qualified) non-POD class type (or
|
|
|
|
// array thereof), the object shall be default-initialized; if
|
|
|
|
// the object is of const-qualified type, the underlying class
|
|
|
|
// type shall have a user-declared default
|
|
|
|
// constructor. Otherwise, if no initializer is specified for
|
|
|
|
// an object, the object and its subobjects, if any, have an
|
|
|
|
// indeterminate initial value; if the object or any of its
|
|
|
|
// subobjects are of const-qualified type, the program is
|
|
|
|
// ill-formed.
|
|
|
|
//
|
|
|
|
// This isn't technically an error in C, so we don't diagnose it.
|
|
|
|
//
|
|
|
|
// FIXME: Actually perform the POD/user-defined default
|
|
|
|
// constructor check.
|
|
|
|
if (getLangOptions().CPlusPlus &&
|
2008-10-29 16:50:18 +03:00
|
|
|
Context.getCanonicalType(Type).isConstQualified() &&
|
|
|
|
Var->getStorageClass() != VarDecl::Extern)
|
2008-10-29 03:13:59 +03:00
|
|
|
Diag(Var->getLocation(),
|
|
|
|
diag::err_const_var_requires_init,
|
|
|
|
Var->getName(),
|
|
|
|
SourceRange(Var->getLocation(), Var->getLocation()));
|
2008-10-29 16:50:18 +03:00
|
|
|
#endif
|
2008-10-29 03:13:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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-10-29 18:10:40 +03:00
|
|
|
|
|
|
|
// See if this is a redefinition.
|
|
|
|
const FunctionDecl *Definition;
|
|
|
|
if (FD->getBody(Definition)) {
|
|
|
|
Diag(FD->getLocation(), diag::err_redefinition,
|
|
|
|
FD->getName());
|
|
|
|
Diag(Definition->getLocation(), diag::err_previous_definition);
|
|
|
|
}
|
|
|
|
|
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);
|
2008-10-25 01:46:40 +04:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, 0, Loc));
|
2007-07-11 21:01:13 +04:00
|
|
|
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,
|
2008-11-08 19:45:02 +03:00
|
|
|
SourceLocation KWLoc, const CXXScopeSpec &SS,
|
|
|
|
IdentifierInfo *Name, SourceLocation NameLoc,
|
|
|
|
AttributeList *Attr) {
|
2007-07-11 21:01:13 +04:00
|
|
|
// 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-09-10 01:18:04 +04:00
|
|
|
if (TK == TK_Reference || 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.
|
2008-09-10 01:18:04 +04:00
|
|
|
if (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.
|
2008-09-10 01:18:04 +04:00
|
|
|
if (TK == TK_Reference || isDeclInScope(PrevDecl, CurContext, S)) {
|
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
|
|
|
// 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.
|
2008-09-10 01:18:04 +04:00
|
|
|
if (isDeclInScope(PrevDecl, CurContext, S)) {
|
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
|
|
|
// 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);
|
|
|
|
}
|
2008-10-16 06:34:03 +04:00
|
|
|
|
|
|
|
// Handle #pragma pack: if the #pragma pack stack has non-default
|
|
|
|
// alignment, make up a packed attribute for this decl. These
|
|
|
|
// attributes are checked when the ASTContext lays out the
|
|
|
|
// structure.
|
|
|
|
//
|
|
|
|
// It is important for implementing the correct semantics that this
|
|
|
|
// happen here (in act on tag decl). The #pragma pack stack is
|
|
|
|
// maintained as a result of parser callbacks which can occur at
|
|
|
|
// many points during the parsing of a struct declaration (because
|
|
|
|
// the #pragma tokens are effectively skipped over during the
|
|
|
|
// parsing of the struct).
|
|
|
|
if (unsigned Alignment = PackContext.getAlignment())
|
|
|
|
New->addAttr(new PackedAttr(Alignment * 8));
|
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 (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-10-12 04:28:42 +04:00
|
|
|
default: assert(0 && "Unknown visitibility kind");
|
|
|
|
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-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-10-03 06:03:53 +04:00
|
|
|
SourceLocation LBrac, SourceLocation RBrac,
|
2008-10-03 21:33:35 +04:00
|
|
|
AttributeList *Attr) {
|
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;
|
2008-10-12 04:28:42 +04:00
|
|
|
for (unsigned i = 0; ; ++i) {
|
|
|
|
assert(i != RecFields.size() && "Didn't find previous def!");
|
2007-07-11 21:01:13 +04:00
|
|
|
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
|
|
|
}
|
2008-10-03 21:33:35 +04:00
|
|
|
|
|
|
|
if (Attr)
|
|
|
|
ProcessDeclAttributeList(Record, Attr);
|
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++!");
|
2008-09-10 01:18:04 +04:00
|
|
|
if (!isa<TagDecl>(PrevDecl) && 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
|
|
|
}
|
2008-10-14 09:35:18 +04:00
|
|
|
|
|
|
|
void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
|
|
|
|
ExprTy *alignment, SourceLocation PragmaLoc,
|
|
|
|
SourceLocation LParenLoc, SourceLocation RParenLoc) {
|
|
|
|
Expr *Alignment = static_cast<Expr *>(alignment);
|
|
|
|
|
|
|
|
// If specified then alignment must be a "small" power of two.
|
|
|
|
unsigned AlignmentVal = 0;
|
|
|
|
if (Alignment) {
|
|
|
|
llvm::APSInt Val;
|
|
|
|
if (!Alignment->isIntegerConstantExpr(Val, Context) ||
|
|
|
|
!Val.isPowerOf2() ||
|
|
|
|
Val.getZExtValue() > 16) {
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
|
|
|
|
delete Alignment;
|
|
|
|
return; // Ignore
|
|
|
|
}
|
|
|
|
|
|
|
|
AlignmentVal = (unsigned) Val.getZExtValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Kind) {
|
|
|
|
case Action::PPK_Default: // pack([n])
|
|
|
|
PackContext.setAlignment(AlignmentVal);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Action::PPK_Show: // pack(show)
|
|
|
|
// Show the current alignment, making sure to show the right value
|
|
|
|
// for the default.
|
|
|
|
AlignmentVal = PackContext.getAlignment();
|
|
|
|
// FIXME: This should come from the target.
|
|
|
|
if (AlignmentVal == 0)
|
|
|
|
AlignmentVal = 8;
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pack_show, llvm::utostr(AlignmentVal));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Action::PPK_Push: // pack(push [, id] [, [n])
|
|
|
|
PackContext.push(Name);
|
|
|
|
// Set the new alignment if specified.
|
|
|
|
if (Alignment)
|
|
|
|
PackContext.setAlignment(AlignmentVal);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Action::PPK_Pop: // pack(pop [, id] [, n])
|
|
|
|
// MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
|
|
|
|
// "#pragma pack(pop, identifier, n) is undefined"
|
|
|
|
if (Alignment && Name)
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
|
|
|
|
|
|
|
|
// Do the pop.
|
|
|
|
if (!PackContext.pop(Name)) {
|
|
|
|
// If a name was specified then failure indicates the name
|
|
|
|
// wasn't found. Otherwise failure indicates the stack was
|
|
|
|
// empty.
|
|
|
|
Diag(PragmaLoc, diag::warn_pragma_pack_pop_failed,
|
|
|
|
Name ? "no record matching name" : "stack empty");
|
|
|
|
|
|
|
|
// FIXME: Warn about popping named records as MSVC does.
|
|
|
|
} else {
|
|
|
|
// Pop succeeded, set the new alignment if specified.
|
|
|
|
if (Alignment)
|
|
|
|
PackContext.setAlignment(AlignmentVal);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert(0 && "Invalid #pragma pack kind.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PragmaPackStack::pop(IdentifierInfo *Name) {
|
|
|
|
if (Stack.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If name is empty just pop top.
|
|
|
|
if (!Name) {
|
|
|
|
Alignment = Stack.back().first;
|
|
|
|
Stack.pop_back();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, find the named record.
|
|
|
|
for (unsigned i = Stack.size(); i != 0; ) {
|
|
|
|
--i;
|
|
|
|
if (strcmp(Stack[i].second.c_str(), Name->getName()) == 0) {
|
|
|
|
// Found it, pop up to and including this record.
|
|
|
|
Alignment = Stack[i].first;
|
|
|
|
Stack.erase(Stack.begin() + i, Stack.end());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|