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"
|
2009-02-04 22:02:06 +03:00
|
|
|
#include "clang/AST/DeclTemplate.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"
|
|
|
|
#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-12-11 23:41:00 +03:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2008-12-24 00:05:05 +03:00
|
|
|
#include <algorithm>
|
|
|
|
#include <functional>
|
2007-07-11 21:01:13 +04:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-02-04 22:16:12 +03:00
|
|
|
/// \brief If the identifier refers to a type name within this scope,
|
|
|
|
/// return the declaration of that type.
|
|
|
|
///
|
|
|
|
/// This routine performs ordinary name lookup of the identifier II
|
|
|
|
/// within the given scope, with optional C++ scope specifier SS, to
|
2009-02-09 18:09:02 +03:00
|
|
|
/// determine whether the name refers to a type. If so, returns an
|
|
|
|
/// opaque pointer (actually a QualType) corresponding to that
|
|
|
|
/// type. Otherwise, returns NULL.
|
2009-02-04 22:16:12 +03:00
|
|
|
///
|
|
|
|
/// If name lookup results in an ambiguity, this routine will complain
|
|
|
|
/// and then return NULL.
|
2009-02-09 18:09:02 +03:00
|
|
|
Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
|
2009-02-04 20:00:24 +03:00
|
|
|
Scope *S, const CXXScopeSpec *SS) {
|
2009-02-17 01:07:16 +03:00
|
|
|
NamedDecl *IIDecl = 0;
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
LookupResult Result = LookupParsedName(S, SS, &II, LookupOrdinaryName,
|
|
|
|
false, false);
|
2009-01-15 03:26:24 +03:00
|
|
|
switch (Result.getKind()) {
|
2009-02-17 01:07:16 +03:00
|
|
|
case LookupResult::NotFound:
|
|
|
|
case LookupResult::FoundOverloaded:
|
|
|
|
return 0;
|
2009-02-04 20:00:24 +03:00
|
|
|
|
2009-02-17 01:07:16 +03:00
|
|
|
case LookupResult::AmbiguousBaseSubobjectTypes:
|
|
|
|
case LookupResult::AmbiguousBaseSubobjects:
|
|
|
|
case LookupResult::AmbiguousReference:
|
|
|
|
DiagnoseAmbiguousLookup(Result, DeclarationName(&II), NameLoc);
|
|
|
|
return 0;
|
2009-02-04 20:00:24 +03:00
|
|
|
|
2009-02-17 01:07:16 +03:00
|
|
|
case LookupResult::Found:
|
|
|
|
IIDecl = Result.getAsDecl();
|
|
|
|
break;
|
2009-01-15 03:26:24 +03:00
|
|
|
}
|
|
|
|
|
2009-01-29 21:09:31 +03:00
|
|
|
if (IIDecl) {
|
2009-02-17 01:07:16 +03:00
|
|
|
if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
|
2009-02-19 00:56:37 +03:00
|
|
|
// Check whether we can use this type
|
|
|
|
(void)DiagnoseUseOfDecl(IIDecl, NameLoc);
|
2009-02-17 01:07:16 +03:00
|
|
|
|
2009-02-09 18:09:02 +03:00
|
|
|
return Context.getTypeDeclType(TD).getAsOpaquePtr();
|
2009-02-17 01:07:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
|
2009-02-19 00:56:37 +03:00
|
|
|
// Check whether we can use this interface.
|
|
|
|
(void)DiagnoseUseOfDecl(IIDecl, NameLoc);
|
2009-02-17 01:07:16 +03:00
|
|
|
|
2009-02-09 18:09:02 +03:00
|
|
|
return Context.getObjCInterfaceType(IDecl).getAsOpaquePtr();
|
2009-02-17 01:07:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, could be a variable, function etc.
|
2009-01-29 21:09:31 +03:00
|
|
|
}
|
2007-09-07 01:24:23 +04:00
|
|
|
return 0;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-11-08 20:17:31 +03:00
|
|
|
DeclContext *Sema::getContainingDC(DeclContext *DC) {
|
2008-07-01 14:37:29 +04:00
|
|
|
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) {
|
2008-11-08 20:17:31 +03:00
|
|
|
// A C++ out-of-line method will return to the file declaration context.
|
2008-11-10 02:41:00 +03:00
|
|
|
if (MD->isOutOfLineDefinition())
|
|
|
|
return MD->getLexicalDeclContext();
|
2008-11-08 20:17:31 +03:00
|
|
|
|
2009-02-16 01:43:40 +03:00
|
|
|
// A C++ inline method is parsed *after* the topmost class it was declared
|
|
|
|
// in is fully parsed (it's "complete").
|
2008-11-08 20:17:31 +03:00
|
|
|
// The parsing of a C++ inline method happens at the declaration context of
|
2008-11-19 21:01:13 +03:00
|
|
|
// the topmost (non-nested) class it is lexically declared in.
|
2008-07-01 14:37:29 +04:00
|
|
|
assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record.");
|
|
|
|
DC = MD->getParent();
|
2008-11-19 21:01:13 +03:00
|
|
|
while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getLexicalParent()))
|
2008-07-01 14:37:29 +04:00
|
|
|
DC = RD;
|
|
|
|
|
|
|
|
// Return the declaration context of the topmost class the inline method is
|
|
|
|
// declared in.
|
|
|
|
return DC;
|
|
|
|
}
|
|
|
|
|
2008-11-10 02:41:00 +03:00
|
|
|
if (isa<ObjCMethodDecl>(DC))
|
|
|
|
return Context.getTranslationUnitDecl();
|
|
|
|
|
2008-11-19 21:01:13 +03:00
|
|
|
return DC->getLexicalParent();
|
2008-07-01 14:37:29 +04:00
|
|
|
}
|
|
|
|
|
2008-12-11 19:49:14 +03:00
|
|
|
void Sema::PushDeclContext(Scope *S, DeclContext *DC) {
|
2008-11-08 20:17:31 +03:00
|
|
|
assert(getContainingDC(DC) == CurContext &&
|
2008-12-08 10:14:51 +03:00
|
|
|
"The next DeclContext should be lexically contained in the current one.");
|
2008-04-22 22:39:57 +04:00
|
|
|
CurContext = DC;
|
2008-12-11 19:49:14 +03:00
|
|
|
S->setEntity(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-12-11 19:49:14 +03:00
|
|
|
|
2008-11-08 20:17:31 +03:00
|
|
|
CurContext = getContainingDC(CurContext);
|
2008-04-04 10:12:32 +04:00
|
|
|
}
|
|
|
|
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64336 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-12 02:02:49 +03:00
|
|
|
/// \brief Determine whether we allow overloading of the function
|
|
|
|
/// PrevDecl with another declaration.
|
|
|
|
///
|
|
|
|
/// This routine determines whether overloading is possible, not
|
|
|
|
/// whether some new function is actually an overload. It will return
|
|
|
|
/// true in C++ (where we can always provide overloads) or, as an
|
|
|
|
/// extension, in C when the previous function is already an
|
|
|
|
/// overloaded function declaration or has the "overloadable"
|
|
|
|
/// attribute.
|
|
|
|
static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) {
|
|
|
|
if (Context.getLangOptions().CPlusPlus)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (isa<OverloadedFunctionDecl>(PrevDecl))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return PrevDecl->getAttr<OverloadableAttr>() != 0;
|
|
|
|
}
|
|
|
|
|
2008-04-12 04:47:19 +04:00
|
|
|
/// Add this decl to the scope shadowed decl chains.
|
|
|
|
void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
|
2009-01-05 22:45:36 +03:00
|
|
|
// Move up the scope chain until we find the nearest enclosing
|
|
|
|
// non-transparent context. The declaration will be introduced into this
|
|
|
|
// scope.
|
|
|
|
while (S->getEntity() &&
|
|
|
|
((DeclContext *)S->getEntity())->isTransparentContext())
|
|
|
|
S = S->getParent();
|
|
|
|
|
2008-04-12 04:47:19 +04:00
|
|
|
S->AddDecl(D);
|
2008-05-10 03:39:43 +04:00
|
|
|
|
2008-12-24 00:05:05 +03:00
|
|
|
// Add scoped declarations into their context, so that they can be
|
|
|
|
// found later. Declarations without a context won't be inserted
|
|
|
|
// into any context.
|
2009-01-20 04:17:11 +03:00
|
|
|
CurContext->addDecl(D);
|
2008-12-24 00:05:05 +03:00
|
|
|
|
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).
|
2009-01-07 19:34:42 +03:00
|
|
|
if (CurContext->getLookupContext()
|
|
|
|
== TD->getDeclContext()->getLookupContext()) {
|
2008-12-11 19:49:14 +03:00
|
|
|
// We're pushing the tag into the current context, which might
|
|
|
|
// require some reshuffling in the identifier resolver.
|
|
|
|
IdentifierResolver::iterator
|
Eliminated LookupCriteria, whose creation was causing a bottleneck for
LookupName et al. Instead, use an enum and a bool to describe its
contents.
Optimized the C/Objective-C path through LookupName, eliminating any
unnecessarily C++isms. Simplify IdentifierResolver::iterator, removing
some code and arguments that are no longer used.
Eliminated LookupDeclInScope/LookupDeclInContext, moving all callers
over to LookupName, LookupQualifiedName, or LookupParsedName, as
appropriate.
All together, I'm seeing a 0.2% speedup on Cocoa.h with PTH and
-disable-free. Plus, we're down to three name-lookup routines.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63354 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-30 04:04:22 +03:00
|
|
|
I = IdResolver.begin(TD->getDeclName()),
|
2008-12-24 00:05:05 +03:00
|
|
|
IEnd = IdResolver.end();
|
|
|
|
if (I != IEnd && isDeclInScope(*I, CurContext, S)) {
|
|
|
|
NamedDecl *PrevDecl = *I;
|
|
|
|
for (; I != IEnd && isDeclInScope(*I, CurContext, S);
|
|
|
|
PrevDecl = *I, ++I) {
|
|
|
|
if (TD->declarationReplaces(*I)) {
|
|
|
|
// This is a redeclaration. Remove it from the chain and
|
|
|
|
// break out, so that we'll add in the shadowed
|
|
|
|
// declaration.
|
|
|
|
S->RemoveDecl(*I);
|
|
|
|
if (PrevDecl == *I) {
|
|
|
|
IdResolver.RemoveDecl(*I);
|
|
|
|
IdResolver.AddDecl(TD);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
IdResolver.RemoveDecl(*I);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// There is already a declaration with the same name in the same
|
|
|
|
// scope, which is not a tag declaration. It must be found
|
|
|
|
// before we find the new declaration, so insert the new
|
|
|
|
// declaration at the end of the chain.
|
|
|
|
IdResolver.AddShadowedDecl(TD, PrevDecl);
|
|
|
|
|
|
|
|
return;
|
2008-12-11 19:49:14 +03:00
|
|
|
}
|
2008-10-21 20:13:35 +04:00
|
|
|
}
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64336 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-12 02:02:49 +03:00
|
|
|
} else if (isa<FunctionDecl>(D) &&
|
|
|
|
AllowOverloadingOfFunction(D, Context)) {
|
2008-10-21 20:13:35 +04:00
|
|
|
// We are pushing the name of a function, which might be an
|
|
|
|
// overloaded name.
|
2008-12-11 19:49:14 +03:00
|
|
|
FunctionDecl *FD = cast<FunctionDecl>(D);
|
2008-12-24 00:05:05 +03:00
|
|
|
IdentifierResolver::iterator Redecl
|
Eliminated LookupCriteria, whose creation was causing a bottleneck for
LookupName et al. Instead, use an enum and a bool to describe its
contents.
Optimized the C/Objective-C path through LookupName, eliminating any
unnecessarily C++isms. Simplify IdentifierResolver::iterator, removing
some code and arguments that are no longer used.
Eliminated LookupDeclInScope/LookupDeclInContext, moving all callers
over to LookupName, LookupQualifiedName, or LookupParsedName, as
appropriate.
All together, I'm seeing a 0.2% speedup on Cocoa.h with PTH and
-disable-free. Plus, we're down to three name-lookup routines.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63354 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-30 04:04:22 +03:00
|
|
|
= std::find_if(IdResolver.begin(FD->getDeclName()),
|
2008-12-24 00:05:05 +03:00
|
|
|
IdResolver.end(),
|
2009-01-20 04:17:11 +03:00
|
|
|
std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
|
2008-12-24 00:05:05 +03:00
|
|
|
FD));
|
|
|
|
if (Redecl != IdResolver.end()) {
|
|
|
|
// There is already a declaration of a function on our
|
|
|
|
// IdResolver chain. Replace it with this declaration.
|
|
|
|
S->RemoveDecl(*Redecl);
|
|
|
|
IdResolver.RemoveDecl(*Redecl);
|
2008-05-10 03:39:43 +04:00
|
|
|
}
|
|
|
|
}
|
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;
|
2008-12-05 21:15:24 +03:00
|
|
|
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
|
|
|
|
"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
|
|
|
|
2008-12-11 19:49:14 +03:00
|
|
|
assert(isa<NamedDecl>(TmpD) && "Decl isn't NamedDecl?");
|
|
|
|
NamedDecl *D = cast<NamedDecl>(TmpD);
|
2008-06-10 05:32:09 +04:00
|
|
|
|
2008-12-11 19:49:14 +03:00
|
|
|
if (!D->getDeclName()) continue;
|
|
|
|
|
|
|
|
// Remove this name from our lexical scope.
|
|
|
|
IdResolver.RemoveDecl(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.
|
2009-02-04 20:27:36 +03:00
|
|
|
NamedDecl *IDecl = LookupName(TUScope, Id, LookupOrdinaryName);
|
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
|
|
|
}
|
|
|
|
|
2009-01-12 21:45:55 +03:00
|
|
|
/// getNonFieldDeclScope - Retrieves the innermost scope, starting
|
|
|
|
/// from S, where a non-field would be declared. This routine copes
|
|
|
|
/// with the difference between C and C++ scoping rules in structs and
|
|
|
|
/// unions. For example, the following code is well-formed in C but
|
|
|
|
/// ill-formed in C++:
|
|
|
|
/// @code
|
|
|
|
/// struct S6 {
|
|
|
|
/// enum { BAR } e;
|
|
|
|
/// };
|
|
|
|
///
|
|
|
|
/// void test_S6() {
|
|
|
|
/// struct S6 a;
|
|
|
|
/// a.e = BAR;
|
|
|
|
/// }
|
|
|
|
/// @endcode
|
|
|
|
/// For the declaration of BAR, this routine will return a different
|
|
|
|
/// scope. The scope S will be the scope of the unnamed enumeration
|
|
|
|
/// within S6. In C++, this routine will return the scope associated
|
|
|
|
/// with S6, because the enumeration's scope is a transparent
|
|
|
|
/// context but structures can contain non-field names. In C, this
|
|
|
|
/// routine will return the translation unit scope, since the
|
|
|
|
/// enumeration's scope is a transparent context and structures cannot
|
|
|
|
/// contain non-field names.
|
|
|
|
Scope *Sema::getNonFieldDeclScope(Scope *S) {
|
|
|
|
while (((S->getFlags() & Scope::DeclScope) == 0) ||
|
|
|
|
(S->getEntity() &&
|
|
|
|
((DeclContext *)S->getEntity())->isTransparentContext()) ||
|
|
|
|
(S->isClassScope() && !getLangOptions().CPlusPlus))
|
|
|
|
S = S->getParent();
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
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");
|
2009-02-04 20:27:36 +03:00
|
|
|
NamedDecl *VaDecl = LookupName(TUScope, VaIdent, LookupOrdinaryName);
|
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));
|
|
|
|
}
|
|
|
|
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
/// LazilyCreateBuiltin - The specified Builtin-ID was first used at
|
|
|
|
/// file scope. lazily create a decl for it. ForRedeclaration is true
|
|
|
|
/// if we're creating this built-in in anticipation of redeclaring the
|
|
|
|
/// built-in.
|
2009-01-20 04:17:11 +03:00
|
|
|
NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
Scope *S, bool ForRedeclaration,
|
|
|
|
SourceLocation Loc) {
|
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();
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
|
2009-02-14 04:52:53 +03:00
|
|
|
Builtin::Context::GetBuiltinTypeError Error;
|
|
|
|
QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context, Error);
|
|
|
|
switch (Error) {
|
|
|
|
case Builtin::Context::GE_None:
|
|
|
|
// Okay
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Builtin::Context::GE_Missing_FILE:
|
|
|
|
if (ForRedeclaration)
|
|
|
|
Diag(Loc, diag::err_implicit_decl_requires_stdio)
|
|
|
|
<< Context.BuiltinInfo.GetName(BID);
|
|
|
|
return 0;
|
|
|
|
}
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
|
|
|
|
if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
|
|
|
|
Diag(Loc, diag::ext_implicit_lib_function_decl)
|
|
|
|
<< Context.BuiltinInfo.GetName(BID)
|
|
|
|
<< R;
|
2009-02-17 00:58:21 +03:00
|
|
|
if (Context.BuiltinInfo.getHeaderName(BID) &&
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
Diags.getDiagnosticMapping(diag::ext_implicit_lib_function_decl)
|
|
|
|
!= diag::MAP_IGNORE)
|
|
|
|
Diag(Loc, diag::note_please_include_header)
|
|
|
|
<< Context.BuiltinInfo.getHeaderName(BID)
|
|
|
|
<< Context.BuiltinInfo.GetName(BID);
|
|
|
|
}
|
|
|
|
|
2008-04-17 18:47:13 +04:00
|
|
|
FunctionDecl *New = FunctionDecl::Create(Context,
|
|
|
|
Context.getTranslationUnitDecl(),
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
Loc, II, R,
|
2009-01-20 04:17:11 +03:00
|
|
|
FunctionDecl::Extern, false);
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
New->setImplicit();
|
|
|
|
|
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,
|
2009-01-20 04:17:11 +03:00
|
|
|
FT->getArgType(i), VarDecl::None, 0));
|
2009-01-14 03:42:25 +03:00
|
|
|
New->setParams(Context, &Params[0], Params.size());
|
2008-05-06 02:18:14 +04:00
|
|
|
}
|
|
|
|
|
2009-02-14 21:57:46 +03:00
|
|
|
AddKnownFunctionAttributes(New);
|
2008-05-06 02:18:14 +04:00
|
|
|
|
2008-04-11 11:00:53 +04:00
|
|
|
// TUScope is the translation-unit scope to insert this function into.
|
2009-01-09 21:51:29 +03:00
|
|
|
// FIXME: This is hideous. We need to teach PushOnScopeChains to
|
|
|
|
// relate Scopes to DeclContexts, and probably eliminate CurContext
|
|
|
|
// entirely, but we're not there yet.
|
|
|
|
DeclContext *SavedContext = CurContext;
|
|
|
|
CurContext = Context.getTranslationUnitDecl();
|
2008-05-10 03:39:43 +04:00
|
|
|
PushOnScopeChains(New, TUScope);
|
2009-01-09 21:51:29 +03:00
|
|
|
CurContext = SavedContext;
|
2007-07-11 21:01:13 +04:00
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
2008-11-11 14:37:55 +03:00
|
|
|
/// GetStdNamespace - This method gets the C++ "std" namespace. This is where
|
|
|
|
/// everything from the standard library is defined.
|
|
|
|
NamespaceDecl *Sema::GetStdNamespace() {
|
|
|
|
if (!StdNamespace) {
|
2008-11-20 08:45:14 +03:00
|
|
|
IdentifierInfo *StdIdent = &PP.getIdentifierTable().get("std");
|
2008-11-11 14:37:55 +03:00
|
|
|
DeclContext *Global = Context.getTranslationUnitDecl();
|
Eliminated LookupCriteria, whose creation was causing a bottleneck for
LookupName et al. Instead, use an enum and a bool to describe its
contents.
Optimized the C/Objective-C path through LookupName, eliminating any
unnecessarily C++isms. Simplify IdentifierResolver::iterator, removing
some code and arguments that are no longer used.
Eliminated LookupDeclInScope/LookupDeclInContext, moving all callers
over to LookupName, LookupQualifiedName, or LookupParsedName, as
appropriate.
All together, I'm seeing a 0.2% speedup on Cocoa.h with PTH and
-disable-free. Plus, we're down to three name-lookup routines.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63354 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-30 04:04:22 +03:00
|
|
|
Decl *Std = LookupQualifiedName(Global, StdIdent, LookupNamespaceName);
|
2008-11-11 14:37:55 +03:00
|
|
|
StdNamespace = dyn_cast_or_null<NamespaceDecl>(Std);
|
|
|
|
}
|
|
|
|
return StdNamespace;
|
|
|
|
}
|
|
|
|
|
2009-02-16 20:45:42 +03:00
|
|
|
/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the
|
|
|
|
/// same name and scope as a previous declaration 'Old'. Figure out
|
|
|
|
/// how to resolve this situation, merging decls or emitting
|
|
|
|
/// diagnostics as appropriate. Returns true if there was an error,
|
|
|
|
/// false otherwise.
|
2007-07-11 21:01:13 +04:00
|
|
|
///
|
2009-02-16 20:45:42 +03:00
|
|
|
bool Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
|
2009-01-16 22:58:32 +03:00
|
|
|
bool objc_types = false;
|
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) {
|
2008-11-20 08:41:43 +03:00
|
|
|
const IdentifierInfo *TypeID = New->getIdentifier();
|
|
|
|
switch (TypeID->getLength()) {
|
|
|
|
default: break;
|
|
|
|
case 2:
|
|
|
|
if (!TypeID->isStr("id"))
|
|
|
|
break;
|
2008-09-09 18:32:20 +04:00
|
|
|
Context.setObjCIdType(New);
|
2009-01-16 22:58:32 +03:00
|
|
|
objc_types = true;
|
|
|
|
break;
|
2008-11-20 08:41:43 +03:00
|
|
|
case 5:
|
|
|
|
if (!TypeID->isStr("Class"))
|
|
|
|
break;
|
2008-09-09 18:32:20 +04:00
|
|
|
Context.setObjCClassType(New);
|
2009-01-16 22:58:32 +03:00
|
|
|
objc_types = true;
|
2009-02-16 20:45:42 +03:00
|
|
|
return false;
|
2008-11-20 08:41:43 +03:00
|
|
|
case 3:
|
|
|
|
if (!TypeID->isStr("SEL"))
|
|
|
|
break;
|
2008-09-09 18:32:20 +04:00
|
|
|
Context.setObjCSelType(New);
|
2009-01-16 22:58:32 +03:00
|
|
|
objc_types = true;
|
2009-02-16 20:45:42 +03:00
|
|
|
return false;
|
2008-11-20 08:41:43 +03:00
|
|
|
case 8:
|
|
|
|
if (!TypeID->isStr("Protocol"))
|
|
|
|
break;
|
2008-09-09 18:32:20 +04:00
|
|
|
Context.setObjCProtoType(New->getUnderlyingType());
|
2009-01-16 22:58:32 +03:00
|
|
|
objc_types = true;
|
2009-02-16 20:45:42 +03:00
|
|
|
return false;
|
2008-09-09 18:32:20 +04:00
|
|
|
}
|
|
|
|
// Fall through - the typedef name was not a builtin type.
|
|
|
|
}
|
2009-01-28 20:15:10 +03:00
|
|
|
// Verify the old decl was also a type.
|
|
|
|
TypeDecl *Old = dyn_cast<TypeDecl>(OldD);
|
2007-07-11 21:01:13 +04:00
|
|
|
if (!Old) {
|
2009-01-28 20:15:10 +03:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_kind)
|
2008-11-24 00:45:46 +03:00
|
|
|
<< New->getDeclName();
|
2009-01-16 22:58:32 +03:00
|
|
|
if (!objc_types)
|
|
|
|
Diag(OldD->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2009-01-28 20:15:10 +03:00
|
|
|
|
|
|
|
// Determine the "old" type we'll use for checking and diagnostics.
|
|
|
|
QualType OldType;
|
|
|
|
if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old))
|
|
|
|
OldType = OldTypedef->getUnderlyingType();
|
|
|
|
else
|
|
|
|
OldType = Context.getTypeDeclType(Old);
|
|
|
|
|
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.
|
2009-01-28 20:15:10 +03:00
|
|
|
|
|
|
|
if (OldType != New->getUnderlyingType() &&
|
|
|
|
Context.getCanonicalType(OldType) !=
|
2008-07-25 22:44:27 +04:00
|
|
|
Context.getCanonicalType(New->getUnderlyingType())) {
|
2008-11-20 09:13:02 +03:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_typedef)
|
2009-01-28 20:15:10 +03:00
|
|
|
<< New->getUnderlyingType() << OldType;
|
2009-01-16 22:58:32 +03:00
|
|
|
if (!objc_types)
|
|
|
|
Diag(Old->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2008-07-25 22:44:27 +04:00
|
|
|
}
|
2009-02-16 20:45:42 +03:00
|
|
|
if (objc_types) return false;
|
|
|
|
if (getLangOptions().Microsoft) return false;
|
2008-06-11 10:20:39 +04:00
|
|
|
|
2008-11-21 19:29:06 +03:00
|
|
|
// C++ [dcl.typedef]p2:
|
|
|
|
// In a given non-class scope, a typedef specifier can be used to
|
|
|
|
// redefine the name of any type declared in that scope to refer
|
|
|
|
// to the type to which it already refers.
|
|
|
|
if (getLangOptions().CPlusPlus && !isa<CXXRecordDecl>(CurContext))
|
2009-02-16 20:45:42 +03:00
|
|
|
return false;
|
2008-11-21 19:29:06 +03:00
|
|
|
|
|
|
|
// In C, redeclaration of a type is a constraint violation (6.7.2.3p1).
|
2008-01-31 02:46:05 +03:00
|
|
|
// 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()))
|
2009-02-16 20:45:42 +03:00
|
|
|
return false;
|
2008-09-12 22:10:20 +04:00
|
|
|
if (SrcMgr.isInSystemHeader(New->getLocation()))
|
2009-02-16 20:45:42 +03:00
|
|
|
return false;
|
2008-09-12 22:10:20 +04:00
|
|
|
}
|
2008-06-11 10:20:39 +04:00
|
|
|
|
2008-11-24 00:45:46 +03:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(Old->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
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) {
|
2009-02-13 03:26:38 +03:00
|
|
|
tmp = attr;
|
|
|
|
attr = attr->getNext();
|
2008-03-03 06:28:21 +03:00
|
|
|
|
2009-02-13 03:26:38 +03:00
|
|
|
if (!DeclHasAttr(New, tmp) && tmp->isMerged()) {
|
|
|
|
tmp->setInherited(true);
|
|
|
|
New->addAttr(tmp);
|
2008-03-03 06:28:21 +03:00
|
|
|
} else {
|
2009-02-13 03:26:38 +03:00
|
|
|
tmp->setNext(0);
|
|
|
|
delete(tmp);
|
2008-03-03 06:28:21 +03:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
///
|
|
|
|
/// 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.
|
2009-02-16 20:45:42 +03:00
|
|
|
///
|
|
|
|
/// Returns true if there was an error, false otherwise.
|
|
|
|
bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
|
2008-10-21 20:13:35 +04:00
|
|
|
assert(!isa<OverloadedFunctionDecl>(OldD) &&
|
|
|
|
"Cannot merge with an overloaded function declaration");
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// Verify the old decl was also a function.
|
|
|
|
FunctionDecl *Old = dyn_cast<FunctionDecl>(OldD);
|
|
|
|
if (!Old) {
|
2008-11-20 09:13:02 +03:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_kind)
|
2008-11-24 00:45:46 +03:00
|
|
|
<< New->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(OldD->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
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())
|
2008-11-24 02:12:31 +03:00
|
|
|
PrevDiag = diag::note_previous_definition;
|
2009-02-16 20:45:42 +03:00
|
|
|
else if (Old->isImplicit())
|
|
|
|
PrevDiag = diag::note_previous_implicit_declaration;
|
|
|
|
else
|
2008-11-24 02:12:31 +03:00
|
|
|
PrevDiag = diag::note_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);
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2008-10-21 20:13:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2008-10-21 20:13:35 +04:00
|
|
|
}
|
2008-12-16 00:24:18 +03:00
|
|
|
|
|
|
|
// C++ [class.mem]p1:
|
|
|
|
// [...] A member shall not be declared twice in the
|
|
|
|
// member-specification, except that a nested class or member
|
|
|
|
// class template can be declared and then later defined.
|
|
|
|
if (OldMethod->getLexicalDeclContext() ==
|
|
|
|
NewMethod->getLexicalDeclContext()) {
|
|
|
|
unsigned NewDiag;
|
|
|
|
if (isa<CXXConstructorDecl>(OldMethod))
|
|
|
|
NewDiag = diag::err_constructor_redeclared;
|
|
|
|
else if (isa<CXXDestructorDecl>(NewMethod))
|
|
|
|
NewDiag = diag::err_destructor_redeclared;
|
|
|
|
else if (isa<CXXConversionDecl>(NewMethod))
|
|
|
|
NewDiag = diag::err_conv_function_redeclared;
|
|
|
|
else
|
|
|
|
NewDiag = diag::err_member_redeclared;
|
|
|
|
|
|
|
|
Diag(New->getLocation(), NewDiag);
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
|
2008-12-16 00:24:18 +03:00
|
|
|
}
|
2008-10-21 20:13:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// (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);
|
2009-02-19 00:56:37 +03:00
|
|
|
|
|
|
|
// Merge the "deleted" flag.
|
|
|
|
if (Old->isDeleted())
|
|
|
|
New->setDeleted();
|
|
|
|
|
2008-10-21 20:13:35 +04:00
|
|
|
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)) {
|
2009-02-16 21:20:44 +03:00
|
|
|
const FunctionType *NewFuncType = NewQType->getAsFunctionType();
|
|
|
|
const FunctionTypeProto *OldProto = 0;
|
|
|
|
if (isa<FunctionTypeNoProto>(NewFuncType) &&
|
|
|
|
(OldProto = OldQType->getAsFunctionTypeProto())) {
|
|
|
|
// The old declaration provided a function prototype, but the
|
|
|
|
// new declaration does not. Merge in the prototype.
|
|
|
|
llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
|
|
|
|
OldProto->arg_type_end());
|
|
|
|
NewQType = Context.getFunctionType(NewFuncType->getResultType(),
|
|
|
|
&ParamTypes[0], ParamTypes.size(),
|
|
|
|
OldProto->isVariadic(),
|
|
|
|
OldProto->getTypeQuals());
|
|
|
|
New->setType(NewQType);
|
|
|
|
New->setInheritedPrototype();
|
2009-02-16 23:58:07 +03:00
|
|
|
|
|
|
|
// Synthesize a parameter for each argument type.
|
|
|
|
llvm::SmallVector<ParmVarDecl*, 16> Params;
|
|
|
|
for (FunctionTypeProto::arg_type_iterator
|
|
|
|
ParamType = OldProto->arg_type_begin(),
|
|
|
|
ParamEnd = OldProto->arg_type_end();
|
|
|
|
ParamType != ParamEnd; ++ParamType) {
|
|
|
|
ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
|
|
|
|
SourceLocation(), 0,
|
|
|
|
*ParamType, VarDecl::None,
|
|
|
|
0);
|
|
|
|
Param->setImplicit();
|
|
|
|
Params.push_back(Param);
|
|
|
|
}
|
|
|
|
|
|
|
|
New->setParams(Context, &Params[0], Params.size());
|
|
|
|
|
2009-02-16 21:20:44 +03:00
|
|
|
}
|
|
|
|
|
2008-04-21 06:02:58 +04:00
|
|
|
MergeAttributes(New, Old);
|
2009-02-19 00:56:37 +03:00
|
|
|
|
|
|
|
// Merge the "deleted" flag.
|
|
|
|
if (Old->isDeleted())
|
|
|
|
New->setDeleted();
|
2009-02-16 21:20:44 +03:00
|
|
|
|
2009-02-16 20:45:42 +03:00
|
|
|
return false;
|
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
|
2009-02-16 20:45:42 +03:00
|
|
|
if (unsigned BuiltinID = Old->getBuiltinID(Context)) {
|
|
|
|
// The user has declared a builtin function with an incompatible
|
|
|
|
// signature.
|
|
|
|
if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
|
|
|
|
// The function the user is redeclaring is a library-defined
|
|
|
|
// function like 'malloc' or 'printf'. Warn about the
|
|
|
|
// redeclaration, then ignore it.
|
|
|
|
Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New;
|
|
|
|
Diag(Old->getLocation(), diag::note_previous_builtin_declaration)
|
|
|
|
<< Old << Old->getType();
|
2009-02-19 01:00:45 +03:00
|
|
|
return true;
|
2009-02-16 20:45:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
PrevDiag = diag::note_previous_builtin_declaration;
|
|
|
|
}
|
2008-01-16 18:01:34 +03:00
|
|
|
|
2008-11-24 08:29:24 +03:00
|
|
|
Diag(New->getLocation(), diag::err_conflicting_types) << New->getDeclName();
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2009-01-07 19:34:42 +03:00
|
|
|
// FIXME: I don't think this will actually see all of the
|
2008-12-24 00:05:05 +03:00
|
|
|
// redefinitions. Can't we check this property on-the-fly?
|
Eliminated LookupCriteria, whose creation was causing a bottleneck for
LookupName et al. Instead, use an enum and a bool to describe its
contents.
Optimized the C/Objective-C path through LookupName, eliminating any
unnecessarily C++isms. Simplify IdentifierResolver::iterator, removing
some code and arguments that are no longer used.
Eliminated LookupDeclInScope/LookupDeclInContext, moving all callers
over to LookupName, LookupQualifiedName, or LookupParsedName, as
appropriate.
All together, I'm seeing a 0.2% speedup on Cocoa.h with PTH and
-disable-free. Plus, we're down to three name-lookup routines.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63354 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-30 04:04:22 +03:00
|
|
|
for (IdentifierResolver::iterator I = IdResolver.begin(VD->getIdentifier()),
|
|
|
|
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) {
|
2008-11-24 00:45:46 +03:00
|
|
|
Diag(VD->getLocation(), diag::err_redefinition) << VD->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(OldDecl->getLocation(), diag::note_previous_definition);
|
2009-02-08 13:49:44 +03:00
|
|
|
// One redefinition error is enough.
|
|
|
|
break;
|
2008-08-08 21:50:35 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
///
|
2009-02-16 20:45:42 +03:00
|
|
|
bool 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) {
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_kind)
|
2008-11-24 00:45:46 +03:00
|
|
|
<< New->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(OldD->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-03-03 06:28:21 +03:00
|
|
|
|
|
|
|
MergeAttributes(New, Old);
|
|
|
|
|
2009-01-25 02:49:55 +03:00
|
|
|
// Merge the types
|
|
|
|
QualType MergedT = Context.mergeTypes(New->getType(), Old->getType());
|
|
|
|
if (MergedT.isNull()) {
|
2009-01-09 22:42:16 +03:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition_different_type)
|
|
|
|
<< New->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(Old->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2008-01-30 03:44:01 +03:00
|
|
|
}
|
2009-01-25 02:49:55 +03:00
|
|
|
New->setType(MergedT);
|
2008-01-30 03:44:01 +03:00
|
|
|
// 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)) {
|
2008-11-24 08:29:24 +03:00
|
|
|
Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(Old->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2008-01-30 03:44:01 +03:00
|
|
|
}
|
|
|
|
// 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) {
|
2008-11-24 08:29:24 +03:00
|
|
|
Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(Old->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2008-01-30 03:44:01 +03:00
|
|
|
}
|
2008-09-17 18:05:40 +04:00
|
|
|
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
|
|
|
|
if (New->getStorageClass() != VarDecl::Extern && !New->isFileVarDecl()) {
|
2008-11-24 00:45:46 +03:00
|
|
|
Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(Old->getLocation(), diag::note_previous_definition);
|
2009-02-16 20:45:42 +03:00
|
|
|
return true;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2009-02-16 20:45:42 +03:00
|
|
|
return false;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
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.
|
2009-01-19 22:26:10 +03:00
|
|
|
if (!Param->isInvalidDecl() &&
|
|
|
|
DiagnoseIncompleteType(Param->getLocation(), Param->getType(),
|
|
|
|
diag::err_typecheck_decl_incomplete_type)) {
|
2008-04-08 08:40:51 +04:00
|
|
|
Param->setInvalidDecl();
|
|
|
|
HasInvalidParm = true;
|
|
|
|
}
|
2008-12-17 10:32:46 +03:00
|
|
|
|
|
|
|
// C99 6.9.1p5: If the declarator includes a parameter type list, the
|
|
|
|
// declaration of each parameter shall include an identifier.
|
2009-02-16 23:58:07 +03:00
|
|
|
if (Param->getIdentifier() == 0 &&
|
|
|
|
!Param->isImplicit() &&
|
|
|
|
!getLangOptions().CPlusPlus)
|
2008-12-17 10:32:46 +03:00
|
|
|
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
|
2008-04-08 08:40:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2009-02-09 18:09:02 +03:00
|
|
|
TagDecl *Tag = 0;
|
|
|
|
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
|
|
|
|
DS.getTypeSpecType() == DeclSpec::TST_struct ||
|
|
|
|
DS.getTypeSpecType() == DeclSpec::TST_union ||
|
|
|
|
DS.getTypeSpecType() == DeclSpec::TST_enum)
|
|
|
|
Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
|
|
|
|
|
2009-01-13 01:49:06 +03:00
|
|
|
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
|
|
|
|
if (!Record->getDeclName() && Record->isDefinition() &&
|
|
|
|
DS.getStorageClassSpec() != DeclSpec::SCS_typedef)
|
|
|
|
return BuildAnonymousStructOrUnion(S, DS, Record);
|
|
|
|
|
|
|
|
// Microsoft allows unnamed struct/union fields. Don't complain
|
|
|
|
// about them.
|
|
|
|
// FIXME: Should we support Microsoft's extensions in this area?
|
|
|
|
if (Record->getDeclName() && getLangOptions().Microsoft)
|
|
|
|
return Tag;
|
|
|
|
}
|
|
|
|
|
2009-02-07 01:42:48 +03:00
|
|
|
if (!DS.isMissingDeclaratorOk() &&
|
|
|
|
DS.getTypeSpecType() != DeclSpec::TST_error) {
|
2009-01-22 19:23:54 +03:00
|
|
|
// Warn about typedefs of enums without names, since this is an
|
|
|
|
// extension in both Microsoft an GNU.
|
2009-01-17 05:55:50 +03:00
|
|
|
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef &&
|
|
|
|
Tag && isa<EnumDecl>(Tag)) {
|
2009-01-22 19:23:54 +03:00
|
|
|
Diag(DS.getSourceRange().getBegin(), diag::ext_typedef_without_a_name)
|
2009-01-14 02:10:51 +03:00
|
|
|
<< DS.getSourceRange();
|
|
|
|
return Tag;
|
|
|
|
}
|
|
|
|
|
2008-12-28 18:28:59 +03:00
|
|
|
Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators)
|
|
|
|
<< DS.getSourceRange();
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-07 03:43:41 +03:00
|
|
|
|
|
|
|
return Tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// InjectAnonymousStructOrUnionMembers - Inject the members of the
|
|
|
|
/// anonymous struct or union AnonRecord into the owning context Owner
|
|
|
|
/// and scope S. This routine will be invoked just after we realize
|
|
|
|
/// that an unnamed union or struct is actually an anonymous union or
|
|
|
|
/// struct, e.g.,
|
|
|
|
///
|
|
|
|
/// @code
|
|
|
|
/// union {
|
|
|
|
/// int i;
|
|
|
|
/// float f;
|
|
|
|
/// }; // InjectAnonymousStructOrUnionMembers called here to inject i and
|
|
|
|
/// // f into the surrounding scope.x
|
|
|
|
/// @endcode
|
|
|
|
///
|
|
|
|
/// This routine is recursive, injecting the names of nested anonymous
|
|
|
|
/// structs/unions into the owning context and scope as well.
|
|
|
|
bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
|
|
|
|
RecordDecl *AnonRecord) {
|
|
|
|
bool Invalid = false;
|
|
|
|
for (RecordDecl::field_iterator F = AnonRecord->field_begin(),
|
|
|
|
FEnd = AnonRecord->field_end();
|
|
|
|
F != FEnd; ++F) {
|
|
|
|
if ((*F)->getDeclName()) {
|
2009-02-04 20:27:36 +03:00
|
|
|
NamedDecl *PrevDecl = LookupQualifiedName(Owner, (*F)->getDeclName(),
|
|
|
|
LookupOrdinaryName, true);
|
2009-01-07 03:43:41 +03:00
|
|
|
if (PrevDecl && !isa<TagDecl>(PrevDecl)) {
|
|
|
|
// C++ [class.union]p2:
|
|
|
|
// The names of the members of an anonymous union shall be
|
|
|
|
// distinct from the names of any other entity in the
|
|
|
|
// scope in which the anonymous union is declared.
|
|
|
|
unsigned diagKind
|
|
|
|
= AnonRecord->isUnion()? diag::err_anonymous_union_member_redecl
|
|
|
|
: diag::err_anonymous_struct_member_redecl;
|
|
|
|
Diag((*F)->getLocation(), diagKind)
|
|
|
|
<< (*F)->getDeclName();
|
|
|
|
Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
|
|
|
|
Invalid = true;
|
|
|
|
} else {
|
|
|
|
// C++ [class.union]p2:
|
|
|
|
// For the purpose of name lookup, after the anonymous union
|
|
|
|
// definition, the members of the anonymous union are
|
|
|
|
// considered to have been defined in the scope in which the
|
|
|
|
// anonymous union is declared.
|
2009-01-20 19:54:50 +03:00
|
|
|
Owner->makeDeclVisibleInContext(*F);
|
2009-01-07 03:43:41 +03:00
|
|
|
S->AddDecl(*F);
|
|
|
|
IdResolver.AddDecl(*F);
|
|
|
|
}
|
|
|
|
} else if (const RecordType *InnerRecordType
|
|
|
|
= (*F)->getType()->getAsRecordType()) {
|
|
|
|
RecordDecl *InnerRecord = InnerRecordType->getDecl();
|
|
|
|
if (InnerRecord->isAnonymousStructOrUnion())
|
|
|
|
Invalid = Invalid ||
|
|
|
|
InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ActOnAnonymousStructOrUnion - Handle the declaration of an
|
|
|
|
/// anonymous structure or union. Anonymous unions are a C++ feature
|
|
|
|
/// (C++ [class.union]) and a GNU C extension; anonymous structures
|
|
|
|
/// are a GNU C and GNU C++ extension.
|
|
|
|
Sema::DeclTy *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
|
|
|
RecordDecl *Record) {
|
|
|
|
DeclContext *Owner = Record->getDeclContext();
|
|
|
|
|
|
|
|
// Diagnose whether this anonymous struct/union is an extension.
|
|
|
|
if (Record->isUnion() && !getLangOptions().CPlusPlus)
|
|
|
|
Diag(Record->getLocation(), diag::ext_anonymous_union);
|
|
|
|
else if (!Record->isUnion())
|
|
|
|
Diag(Record->getLocation(), diag::ext_anonymous_struct);
|
|
|
|
|
|
|
|
// C and C++ require different kinds of checks for anonymous
|
|
|
|
// structs/unions.
|
|
|
|
bool Invalid = false;
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
const char* PrevSpec = 0;
|
|
|
|
// C++ [class.union]p3:
|
|
|
|
// Anonymous unions declared in a named namespace or in the
|
|
|
|
// global namespace shall be declared static.
|
|
|
|
if (DS.getStorageClassSpec() != DeclSpec::SCS_static &&
|
|
|
|
(isa<TranslationUnitDecl>(Owner) ||
|
|
|
|
(isa<NamespaceDecl>(Owner) &&
|
|
|
|
cast<NamespaceDecl>(Owner)->getDeclName()))) {
|
|
|
|
Diag(Record->getLocation(), diag::err_anonymous_union_not_static);
|
|
|
|
Invalid = true;
|
|
|
|
|
|
|
|
// Recover by adding 'static'.
|
|
|
|
DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), PrevSpec);
|
|
|
|
}
|
|
|
|
// C++ [class.union]p3:
|
|
|
|
// A storage class is not allowed in a declaration of an
|
|
|
|
// anonymous union in a class scope.
|
|
|
|
else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
|
|
|
|
isa<RecordDecl>(Owner)) {
|
|
|
|
Diag(DS.getStorageClassSpecLoc(),
|
|
|
|
diag::err_anonymous_union_with_storage_spec);
|
|
|
|
Invalid = true;
|
|
|
|
|
|
|
|
// Recover by removing the storage specifier.
|
|
|
|
DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(),
|
|
|
|
PrevSpec);
|
|
|
|
}
|
2009-01-07 22:46:03 +03:00
|
|
|
|
|
|
|
// C++ [class.union]p2:
|
|
|
|
// The member-specification of an anonymous union shall only
|
|
|
|
// define non-static data members. [Note: nested types and
|
|
|
|
// functions cannot be declared within an anonymous union. ]
|
|
|
|
for (DeclContext::decl_iterator Mem = Record->decls_begin(),
|
|
|
|
MemEnd = Record->decls_end();
|
|
|
|
Mem != MemEnd; ++Mem) {
|
|
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(*Mem)) {
|
|
|
|
// C++ [class.union]p3:
|
|
|
|
// An anonymous union shall not have private or protected
|
|
|
|
// members (clause 11).
|
|
|
|
if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) {
|
|
|
|
Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member)
|
|
|
|
<< (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected);
|
|
|
|
Invalid = true;
|
|
|
|
}
|
|
|
|
} else if ((*Mem)->isImplicit()) {
|
|
|
|
// Any implicit members are fine.
|
2009-02-03 03:34:39 +03:00
|
|
|
} else if (isa<TagDecl>(*Mem) && (*Mem)->getDeclContext() != Record) {
|
|
|
|
// This is a type that showed up in an
|
|
|
|
// elaborated-type-specifier inside the anonymous struct or
|
|
|
|
// union, but which actually declares a type outside of the
|
|
|
|
// anonymous struct or union. It's okay.
|
2009-01-07 22:46:03 +03:00
|
|
|
} else if (RecordDecl *MemRecord = dyn_cast<RecordDecl>(*Mem)) {
|
|
|
|
if (!MemRecord->isAnonymousStructOrUnion() &&
|
|
|
|
MemRecord->getDeclName()) {
|
|
|
|
// This is a nested type declaration.
|
|
|
|
Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type)
|
|
|
|
<< (int)Record->isUnion();
|
|
|
|
Invalid = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We have something that isn't a non-static data
|
|
|
|
// member. Complain about it.
|
|
|
|
unsigned DK = diag::err_anonymous_record_bad_member;
|
|
|
|
if (isa<TypeDecl>(*Mem))
|
|
|
|
DK = diag::err_anonymous_record_with_type;
|
|
|
|
else if (isa<FunctionDecl>(*Mem))
|
|
|
|
DK = diag::err_anonymous_record_with_function;
|
|
|
|
else if (isa<VarDecl>(*Mem))
|
|
|
|
DK = diag::err_anonymous_record_with_static;
|
|
|
|
Diag((*Mem)->getLocation(), DK)
|
|
|
|
<< (int)Record->isUnion();
|
|
|
|
Invalid = true;
|
|
|
|
}
|
|
|
|
}
|
2009-01-07 03:43:41 +03:00
|
|
|
} else {
|
|
|
|
// FIXME: Check GNU C semantics
|
2009-01-13 01:49:06 +03:00
|
|
|
if (Record->isUnion() && !Owner->isRecord()) {
|
|
|
|
Diag(Record->getLocation(), diag::err_anonymous_union_not_member)
|
|
|
|
<< (int)getLangOptions().CPlusPlus;
|
|
|
|
Invalid = true;
|
|
|
|
}
|
2009-01-07 03:43:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Record->isUnion() && !Owner->isRecord()) {
|
2009-01-13 01:49:06 +03:00
|
|
|
Diag(Record->getLocation(), diag::err_anonymous_struct_not_member)
|
|
|
|
<< (int)getLangOptions().CPlusPlus;
|
2009-01-07 03:43:41 +03:00
|
|
|
Invalid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a declaration for this anonymous struct/union.
|
2009-01-20 04:17:11 +03:00
|
|
|
NamedDecl *Anon = 0;
|
2009-01-07 03:43:41 +03:00
|
|
|
if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) {
|
|
|
|
Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(),
|
|
|
|
/*IdentifierInfo=*/0,
|
|
|
|
Context.getTypeDeclType(Record),
|
2009-01-20 04:17:11 +03:00
|
|
|
/*BitWidth=*/0, /*Mutable=*/false);
|
2009-01-07 22:46:03 +03:00
|
|
|
Anon->setAccess(AS_public);
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
FieldCollector->Add(cast<FieldDecl>(Anon));
|
2009-01-07 03:43:41 +03:00
|
|
|
} else {
|
|
|
|
VarDecl::StorageClass SC;
|
|
|
|
switch (DS.getStorageClassSpec()) {
|
|
|
|
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;
|
|
|
|
case DeclSpec::SCS_mutable:
|
|
|
|
// mutable can only appear on non-static class members, so it's always
|
|
|
|
// an error here
|
|
|
|
Diag(Record->getLocation(), diag::err_mutable_nonmember);
|
|
|
|
Invalid = true;
|
|
|
|
SC = VarDecl::None;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
|
|
|
|
/*IdentifierInfo=*/0,
|
|
|
|
Context.getTypeDeclType(Record),
|
2009-01-20 04:17:11 +03:00
|
|
|
SC, DS.getSourceRange().getBegin());
|
2009-01-07 03:43:41 +03:00
|
|
|
}
|
2009-01-07 22:46:03 +03:00
|
|
|
Anon->setImplicit();
|
2009-01-07 03:43:41 +03:00
|
|
|
|
|
|
|
// Add the anonymous struct/union object to the current
|
|
|
|
// context. We'll be referencing this object when we refer to one of
|
|
|
|
// its members.
|
2009-01-13 02:27:07 +03:00
|
|
|
Owner->addDecl(Anon);
|
2008-12-28 18:28:59 +03:00
|
|
|
|
2009-01-07 03:43:41 +03:00
|
|
|
// Inject the members of the anonymous struct/union into the owning
|
|
|
|
// context and into the identifier resolver chain for name lookup
|
|
|
|
// purposes.
|
2009-01-13 01:49:06 +03:00
|
|
|
if (InjectAnonymousStructOrUnionMembers(S, Owner, Record))
|
|
|
|
Invalid = true;
|
2009-01-07 03:43:41 +03:00
|
|
|
|
|
|
|
// Mark this as an anonymous struct/union type. Note that we do not
|
|
|
|
// do this until after we have already checked and injected the
|
|
|
|
// members of this anonymous struct/union type, because otherwise
|
|
|
|
// the members could be injected twice: once by DeclContext when it
|
|
|
|
// builds its lookup table, and once by
|
|
|
|
// InjectAnonymousStructOrUnionMembers.
|
|
|
|
Record->setAnonymousStructOrUnion(true);
|
|
|
|
|
|
|
|
if (Invalid)
|
|
|
|
Anon->setInvalidDecl();
|
|
|
|
|
|
|
|
return Anon;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2009-01-14 18:45:31 +03:00
|
|
|
bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType,
|
|
|
|
bool DirectInit) {
|
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();
|
2008-12-19 20:40:08 +03:00
|
|
|
|
2009-01-14 18:45:31 +03:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
// FIXME: I dislike this error message. A lot.
|
|
|
|
if (PerformImplicitConversion(Init, DeclType, "initializing", DirectInit))
|
|
|
|
return Diag(Init->getSourceRange().getBegin(),
|
|
|
|
diag::err_typecheck_convert_incompatible)
|
|
|
|
<< DeclType << Init->getType() << "initializing"
|
|
|
|
<< Init->getSourceRange();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2008-12-19 20:40:08 +03: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(),
|
2008-11-19 08:27:50 +03:00
|
|
|
diag::warn_initializer_string_for_char_array_too_long)
|
|
|
|
<< strLiteral->getSourceRange();
|
2008-01-22 03:55:40 +03:00
|
|
|
}
|
|
|
|
// 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()) {
|
2009-01-24 20:47:50 +03:00
|
|
|
return dyn_cast<StringLiteral>(Init->IgnoreParens());
|
2008-01-25 03:51:06 +03:00
|
|
|
}
|
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,
|
2009-01-14 18:45:31 +03:00
|
|
|
DeclarationName InitEntity,
|
|
|
|
bool DirectInit) {
|
2008-12-19 00:49:58 +03:00
|
|
|
if (DeclType->isDependentType() || Init->isTypeDependent())
|
|
|
|
return false;
|
|
|
|
|
2008-10-29 03:13:59 +03:00
|
|
|
// C++ [dcl.init.ref]p1:
|
2008-11-24 23:06:50 +03:00
|
|
|
// A variable declared to be a T&, that is "reference to type T"
|
2008-10-29 03:13:59 +03:00
|
|
|
// (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())
|
2009-01-14 18:45:31 +03:00
|
|
|
return CheckReferenceInit(Init, DeclType, 0, false, DirectInit);
|
2008-10-29 03:13:59 +03:00
|
|
|
|
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-19 08:27:50 +03:00
|
|
|
return Diag(InitLoc, diag::err_variable_object_no_init)
|
|
|
|
<< VAT->getSizeExpr()->getSourceRange();
|
2008-01-22 02:53:58 +03:00
|
|
|
|
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(),
|
2009-01-14 18:45:31 +03:00
|
|
|
InitEntity,
|
|
|
|
DirectInit? IK_Direct : IK_Copy);
|
2008-11-05 18:29:30 +03:00
|
|
|
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.
|
2008-12-19 20:40:08 +03:00
|
|
|
if (!PerformImplicitConversion(Init, DeclType, "initializing"))
|
2008-11-05 18:29:30 +03:00
|
|
|
return false;
|
2008-11-19 01:52:51 +03:00
|
|
|
|
2008-12-24 03:01:03 +03:00
|
|
|
if (InitEntity)
|
|
|
|
return Diag(InitLoc, diag::err_cannot_initialize_decl)
|
|
|
|
<< InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
|
|
|
|
<< Init->getType() << Init->getSourceRange();
|
|
|
|
else
|
|
|
|
return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
|
|
|
|
<< DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
|
|
|
|
<< Init->getType() << Init->getSourceRange();
|
2008-11-05 18:29:30 +03:00
|
|
|
}
|
|
|
|
|
2008-09-30 00:07:05 +04:00
|
|
|
// C99 6.7.8p16.
|
2008-02-08 03:48:24 +03:00
|
|
|
if (DeclType->isArrayType())
|
2008-11-19 08:27:50 +03:00
|
|
|
return Diag(Init->getLocStart(), diag::err_array_init_list_required)
|
|
|
|
<< Init->getSourceRange();
|
2008-02-08 03:48:24 +03:00
|
|
|
|
2009-01-14 18:45:31 +03:00
|
|
|
return CheckSingleInitializer(Init, DeclType, DirectInit);
|
2009-01-31 01:09:00 +03:00
|
|
|
}
|
2008-06-06 23:40:52 +04:00
|
|
|
|
2009-01-29 03:45:39 +03:00
|
|
|
bool hadError = CheckInitList(InitList, DeclType);
|
|
|
|
Init = InitList;
|
|
|
|
return hadError;
|
2007-09-02 06:04:30 +04:00
|
|
|
}
|
|
|
|
|
2008-11-18 01:58:34 +03:00
|
|
|
/// GetNameForDeclarator - Determine the full declaration name for the
|
|
|
|
/// given Declarator.
|
|
|
|
DeclarationName Sema::GetNameForDeclarator(Declarator &D) {
|
|
|
|
switch (D.getKind()) {
|
|
|
|
case Declarator::DK_Abstract:
|
|
|
|
assert(D.getIdentifier() == 0 && "abstract declarators have no name");
|
|
|
|
return DeclarationName();
|
|
|
|
|
|
|
|
case Declarator::DK_Normal:
|
|
|
|
assert (D.getIdentifier() != 0 && "normal declarators have an identifier");
|
|
|
|
return DeclarationName(D.getIdentifier());
|
|
|
|
|
|
|
|
case Declarator::DK_Constructor: {
|
2009-02-09 18:09:02 +03:00
|
|
|
QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
|
2008-11-18 01:58:34 +03:00
|
|
|
Ty = Context.getCanonicalType(Ty);
|
|
|
|
return Context.DeclarationNames.getCXXConstructorName(Ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
case Declarator::DK_Destructor: {
|
2009-02-09 18:09:02 +03:00
|
|
|
QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
|
2008-11-18 01:58:34 +03:00
|
|
|
Ty = Context.getCanonicalType(Ty);
|
|
|
|
return Context.DeclarationNames.getCXXDestructorName(Ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
case Declarator::DK_Conversion: {
|
2009-02-09 18:09:02 +03:00
|
|
|
// FIXME: We'd like to keep the non-canonical type for diagnostics!
|
2008-11-18 01:58:34 +03:00
|
|
|
QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType());
|
|
|
|
Ty = Context.getCanonicalType(Ty);
|
|
|
|
return Context.DeclarationNames.getCXXConversionFunctionName(Ty);
|
|
|
|
}
|
Extend DeclarationName to support C++ overloaded operators, e.g.,
operator+, directly, using the same mechanism as all other special
names.
Removed the "special" identifiers for the overloaded operators from
the identifier table and IdentifierInfo data structure. IdentifierInfo
is back to representing only real identifiers.
Added a new Action, ActOnOperatorFunctionIdExpr, that builds an
expression from an parsed operator-function-id (e.g., "operator
+"). ActOnIdentifierExpr used to do this job, but
operator-function-ids are no longer represented by IdentifierInfo's.
Extended Declarator to store overloaded operator names.
Sema::GetNameForDeclarator now knows how to turn the operator
name into a DeclarationName for the overloaded operator.
Except for (perhaps) consolidating the functionality of
ActOnIdentifier, ActOnOperatorFunctionIdExpr, and
ActOnConversionFunctionExpr into a common routine that builds an
appropriate DeclRefExpr by looking up a DeclarationName, all of the
work on normalizing declaration names should be complete with this
commit.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59526 91177308-0d34-0410-b5e6-96231b3b80d8
2008-11-18 17:39:36 +03:00
|
|
|
|
|
|
|
case Declarator::DK_Operator:
|
|
|
|
assert(D.getIdentifier() == 0 && "operator names have no identifier");
|
|
|
|
return Context.DeclarationNames.getCXXOperatorName(
|
|
|
|
D.getOverloadedOperator());
|
2008-11-18 01:58:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(false && "Unknown name kind");
|
|
|
|
return DeclarationName();
|
|
|
|
}
|
|
|
|
|
2009-02-06 20:46:57 +03:00
|
|
|
/// isNearlyMatchingFunction - Determine whether the C++ functions
|
|
|
|
/// Declaration and Definition are "nearly" matching. This heuristic
|
|
|
|
/// is used to improve diagnostics in the case where an out-of-line
|
|
|
|
/// function definition doesn't match any declaration within
|
|
|
|
/// the class or namespace.
|
|
|
|
static bool isNearlyMatchingFunction(ASTContext &Context,
|
|
|
|
FunctionDecl *Declaration,
|
|
|
|
FunctionDecl *Definition) {
|
2008-12-16 02:53:10 +03:00
|
|
|
if (Declaration->param_size() != Definition->param_size())
|
|
|
|
return false;
|
|
|
|
for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) {
|
|
|
|
QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType();
|
|
|
|
QualType DefParamTy = Definition->getParamDecl(Idx)->getType();
|
|
|
|
|
|
|
|
DeclParamTy = Context.getCanonicalType(DeclParamTy.getNonReferenceType());
|
|
|
|
DefParamTy = Context.getCanonicalType(DefParamTy.getNonReferenceType());
|
|
|
|
if (DeclParamTy.getUnqualifiedType() != DefParamTy.getUnqualifiedType())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
Sema::DeclTy *
|
2008-12-16 02:53:10 +03:00
|
|
|
Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
|
|
|
|
bool IsFunctionDefinition) {
|
2009-01-20 04:17:11 +03:00
|
|
|
NamedDecl *LastDeclarator = dyn_cast_or_null<NamedDecl>((Decl *)lastDecl);
|
2008-11-18 01:58:34 +03:00
|
|
|
DeclarationName Name = GetNameForDeclarator(D);
|
|
|
|
|
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.
|
2008-11-18 01:58:34 +03:00
|
|
|
if (!Name) {
|
2008-11-11 09:13:16 +03:00
|
|
|
if (!D.getInvalidType()) // Reject this if we think it is valid.
|
|
|
|
Diag(D.getDeclSpec().getSourceRange().getBegin(),
|
2008-11-19 08:08:23 +03:00
|
|
|
diag::err_declarator_need_ident)
|
|
|
|
<< D.getDeclSpec().getSourceRange() << D.getSourceRange();
|
2007-07-25 04:24:17 +04:00
|
|
|
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.
|
2008-12-11 19:49:14 +03:00
|
|
|
while ((S->getFlags() & Scope::DeclScope) == 0 ||
|
2009-02-04 22:02:06 +03:00
|
|
|
(S->getFlags() & Scope::TemplateParamScope) != 0)
|
2007-08-26 10:24:45 +04:00
|
|
|
S = S->getParent();
|
|
|
|
|
2008-11-08 20:17:31 +03:00
|
|
|
DeclContext *DC;
|
2009-02-04 20:27:36 +03:00
|
|
|
NamedDecl *PrevDecl;
|
2009-01-20 04:17:11 +03:00
|
|
|
NamedDecl *New;
|
2007-08-29 00:14:24 +04:00
|
|
|
bool InvalidDecl = false;
|
2009-02-16 20:45:42 +03:00
|
|
|
|
2008-11-08 20:17:31 +03:00
|
|
|
// See if this is a redefinition of a variable in the same scope.
|
Eliminated LookupCriteria, whose creation was causing a bottleneck for
LookupName et al. Instead, use an enum and a bool to describe its
contents.
Optimized the C/Objective-C path through LookupName, eliminating any
unnecessarily C++isms. Simplify IdentifierResolver::iterator, removing
some code and arguments that are no longer used.
Eliminated LookupDeclInScope/LookupDeclInContext, moving all callers
over to LookupName, LookupQualifiedName, or LookupParsedName, as
appropriate.
All together, I'm seeing a 0.2% speedup on Cocoa.h with PTH and
-disable-free. Plus, we're down to three name-lookup routines.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63354 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-30 04:04:22 +03:00
|
|
|
if (!D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid()) {
|
2008-11-08 20:17:31 +03:00
|
|
|
DC = CurContext;
|
2009-02-17 06:23:10 +03:00
|
|
|
PrevDecl = LookupName(S, Name, LookupOrdinaryName, true,
|
|
|
|
D.getDeclSpec().getStorageClassSpec() !=
|
|
|
|
DeclSpec::SCS_static,
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
D.getIdentifierLoc());
|
2008-11-08 20:17:31 +03:00
|
|
|
} else { // Something like "int foo::x;"
|
|
|
|
DC = static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep());
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-14 02:20:09 +03:00
|
|
|
PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
|
2008-11-08 20:17:31 +03:00
|
|
|
|
|
|
|
// C++ 7.3.1.2p2:
|
|
|
|
// Members (including explicit specializations of templates) of a named
|
|
|
|
// namespace can also be defined outside that namespace by explicit
|
|
|
|
// qualification of the name being defined, provided that the entity being
|
|
|
|
// defined was already declared in the namespace and the definition appears
|
|
|
|
// after the point of declaration in a namespace that encloses the
|
|
|
|
// declarations namespace.
|
|
|
|
//
|
2008-12-16 02:53:10 +03:00
|
|
|
// Note that we only check the context at this point. We don't yet
|
|
|
|
// have enough information to make sure that PrevDecl is actually
|
|
|
|
// the declaration we want to match. For example, given:
|
|
|
|
//
|
2008-12-12 11:25:50 +03:00
|
|
|
// class X {
|
|
|
|
// void f();
|
2008-12-16 02:53:10 +03:00
|
|
|
// void f(float);
|
2008-12-12 11:25:50 +03:00
|
|
|
// };
|
|
|
|
//
|
2008-12-16 02:53:10 +03:00
|
|
|
// void X::f(int) { } // ill-formed
|
|
|
|
//
|
|
|
|
// In this case, PrevDecl will point to the overload set
|
|
|
|
// containing the two f's declared in X, but neither of them
|
|
|
|
// matches.
|
2009-02-06 20:46:57 +03:00
|
|
|
|
|
|
|
// First check whether we named the global scope.
|
|
|
|
if (isa<TranslationUnitDecl>(DC)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope)
|
|
|
|
<< Name << D.getCXXScopeSpec().getRange();
|
|
|
|
} else if (!CurContext->Encloses(DC)) {
|
2008-11-08 20:17:31 +03:00
|
|
|
// The qualifying scope doesn't enclose the original declaration.
|
|
|
|
// Emit diagnostic based on current scope.
|
|
|
|
SourceLocation L = D.getIdentifierLoc();
|
|
|
|
SourceRange R = D.getCXXScopeSpec().getRange();
|
2009-02-06 20:46:57 +03:00
|
|
|
if (isa<FunctionDecl>(CurContext))
|
2008-11-23 23:28:15 +03:00
|
|
|
Diag(L, diag::err_invalid_declarator_in_function) << Name << R;
|
2009-02-06 20:46:57 +03:00
|
|
|
else
|
2008-11-23 23:28:15 +03:00
|
|
|
Diag(L, diag::err_invalid_declarator_scope)
|
2009-02-06 20:46:57 +03:00
|
|
|
<< Name << cast<NamedDecl>(DC) << R;
|
2008-12-11 19:49:14 +03:00
|
|
|
InvalidDecl = true;
|
2008-11-08 20:17:31 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-08 21:40:42 +03:00
|
|
|
if (PrevDecl && PrevDecl->isTemplateParameter()) {
|
2008-12-05 21:15:24 +03:00
|
|
|
// Maybe we will complain about the shadowed template parameter.
|
2008-12-06 02:32:09 +03:00
|
|
|
InvalidDecl = InvalidDecl
|
|
|
|
|| DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
|
2008-12-05 21:15:24 +03:00
|
|
|
// Just pretend that we didn't see the previous declaration.
|
|
|
|
PrevDecl = 0;
|
|
|
|
}
|
|
|
|
|
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
|
2009-01-28 20:15:10 +03:00
|
|
|
// tag type. Note that this does does not apply if we're declaring a
|
|
|
|
// typedef (C++ [dcl.typedef]p4).
|
|
|
|
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag &&
|
|
|
|
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
|
2008-04-14 01:07:44 +04:00
|
|
|
PrevDecl = 0;
|
|
|
|
|
2007-11-14 09:34:38 +03:00
|
|
|
QualType R = GetTypeForDeclarator(D, S);
|
2009-02-20 02:13:55 +03:00
|
|
|
if (R.isNull()) {
|
|
|
|
InvalidDecl = true;
|
|
|
|
R = Context.IntTy;
|
|
|
|
}
|
2007-11-14 09:34:38 +03:00
|
|
|
|
2009-02-16 20:45:42 +03:00
|
|
|
bool Redeclaration = false;
|
2007-07-11 21:01:13 +04:00
|
|
|
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
2009-01-16 06:34:13 +03:00
|
|
|
New = ActOnTypedefDeclarator(S, D, DC, R, LastDeclarator, PrevDecl,
|
2009-02-16 20:45:42 +03:00
|
|
|
InvalidDecl, Redeclaration);
|
2007-11-14 09:34:38 +03:00
|
|
|
} else if (R.getTypePtr()->isFunctionType()) {
|
2009-01-16 04:13:29 +03:00
|
|
|
New = ActOnFunctionDeclarator(S, D, DC, R, LastDeclarator, PrevDecl,
|
2009-02-16 20:45:42 +03:00
|
|
|
IsFunctionDefinition, InvalidDecl,
|
|
|
|
Redeclaration);
|
2007-07-11 21:01:13 +04:00
|
|
|
} else {
|
2009-01-16 05:36:34 +03:00
|
|
|
New = ActOnVariableDeclarator(S, D, DC, R, LastDeclarator, PrevDecl,
|
2009-02-16 20:45:42 +03:00
|
|
|
InvalidDecl, Redeclaration);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2009-01-16 04:13:29 +03:00
|
|
|
|
|
|
|
if (New == 0)
|
|
|
|
return 0;
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2008-11-10 02:41:00 +03:00
|
|
|
// Set the lexical context. If the declarator has a C++ scope specifier, the
|
|
|
|
// lexical context will be different from the semantic context.
|
|
|
|
New->setLexicalDeclContext(CurContext);
|
|
|
|
|
2009-02-16 20:45:42 +03:00
|
|
|
// If this has an identifier and is not an invalid redeclaration,
|
|
|
|
// add it to the scope stack.
|
|
|
|
if (Name && !(Redeclaration && InvalidDecl))
|
2008-04-12 04:47:19 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-01-20 04:17:11 +03:00
|
|
|
NamedDecl*
|
2009-01-16 06:34:13 +03:00
|
|
|
Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
2009-01-20 04:17:11 +03:00
|
|
|
QualType R, Decl* LastDeclarator,
|
2009-02-16 20:45:42 +03:00
|
|
|
Decl* PrevDecl, bool& InvalidDecl,
|
|
|
|
bool &Redeclaration) {
|
2009-01-16 06:34:13 +03:00
|
|
|
// Typedef declarators cannot be qualified (C++ [dcl.meaning]p1).
|
|
|
|
if (D.getCXXScopeSpec().isSet()) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator)
|
|
|
|
<< D.getCXXScopeSpec().getRange();
|
|
|
|
InvalidDecl = true;
|
|
|
|
// Pretend we didn't see the scope specifier.
|
|
|
|
DC = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that there are no default arguments (C++ only).
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
CheckExtraCXXDefaultArguments(D);
|
|
|
|
|
|
|
|
TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator);
|
|
|
|
if (!NewTD) return 0;
|
|
|
|
|
|
|
|
// Handle attributes prior to checking for duplicates in MergeVarDecl
|
|
|
|
ProcessDeclAttributes(NewTD, D);
|
|
|
|
// Merge the decl with the existing one if appropriate. If the decl is
|
|
|
|
// in an outer scope, it isn't the same thing.
|
|
|
|
if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
|
2009-02-16 20:45:42 +03:00
|
|
|
Redeclaration = true;
|
|
|
|
if (MergeTypeDefDecl(NewTD, PrevDecl))
|
|
|
|
InvalidDecl = true;
|
2009-01-16 06:34:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (S->getFnParent() == 0) {
|
|
|
|
// C99 6.7.7p2: If a typedef name specifies a variably modified type
|
|
|
|
// then it shall have block scope.
|
|
|
|
if (NewTD->getUnderlyingType()->isVariablyModifiedType()) {
|
|
|
|
if (NewTD->getUnderlyingType()->isVariableArrayType())
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope);
|
|
|
|
else
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope);
|
|
|
|
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NewTD;
|
|
|
|
}
|
|
|
|
|
2009-01-20 04:17:11 +03:00
|
|
|
NamedDecl*
|
2009-01-16 05:36:34 +03:00
|
|
|
Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
2009-01-20 04:17:11 +03:00
|
|
|
QualType R, Decl* LastDeclarator,
|
2009-02-16 20:45:42 +03:00
|
|
|
Decl* PrevDecl, bool& InvalidDecl,
|
|
|
|
bool &Redeclaration) {
|
2009-01-16 05:36:34 +03:00
|
|
|
DeclarationName Name = GetNameForDeclarator(D);
|
|
|
|
|
|
|
|
// Check that there are no default arguments (C++ only).
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
CheckExtraCXXDefaultArguments(D);
|
|
|
|
|
|
|
|
if (R.getTypePtr()->isObjCInterfaceType()) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object)
|
|
|
|
<< D.getIdentifier();
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl *NewVD;
|
|
|
|
VarDecl::StorageClass SC;
|
|
|
|
switch (D.getDeclSpec().getStorageClassSpec()) {
|
|
|
|
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;
|
|
|
|
case DeclSpec::SCS_mutable:
|
|
|
|
// mutable can only appear on non-static class members, so it's always
|
|
|
|
// an error here
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember);
|
|
|
|
InvalidDecl = true;
|
|
|
|
SC = VarDecl::None;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo *II = Name.getAsIdentifierInfo();
|
|
|
|
if (!II) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_bad_variable_name)
|
|
|
|
<< Name.getAsString();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DC->isRecord()) {
|
|
|
|
// This is a static data member for a C++ class.
|
|
|
|
NewVD = CXXClassVarDecl::Create(Context, cast<CXXRecordDecl>(DC),
|
|
|
|
D.getIdentifierLoc(), II,
|
2009-01-20 04:17:11 +03:00
|
|
|
R);
|
2009-01-16 05:36:34 +03:00
|
|
|
} else {
|
|
|
|
bool ThreadSpecified = D.getDeclSpec().isThreadSpecified();
|
|
|
|
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);
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
|
2009-01-20 04:17:11 +03:00
|
|
|
II, R, SC,
|
2009-01-16 05:36:34 +03:00
|
|
|
// FIXME: Move to DeclGroup...
|
|
|
|
D.getDeclSpec().getSourceRange().getBegin());
|
|
|
|
NewVD->setThreadSpecified(ThreadSpecified);
|
|
|
|
}
|
2009-01-20 04:17:11 +03:00
|
|
|
NewVD->setNextDeclarator(LastDeclarator);
|
|
|
|
|
2009-01-16 05:36:34 +03:00
|
|
|
// Handle attributes prior to checking for duplicates in MergeVarDecl
|
|
|
|
ProcessDeclAttributes(NewVD, D);
|
|
|
|
|
|
|
|
// 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())));
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
if (NewVD->hasLocalStorage() && (NewVD->getType().getAddressSpace() != 0)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_as_qualified_auto_decl);
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
|
|
|
// Merge the decl with the existing one if appropriate. If the decl is
|
|
|
|
// in an outer scope, it isn't the same thing.
|
|
|
|
if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
|
|
|
|
if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
|
|
|
|
// The user tried to define a non-static data member
|
|
|
|
// out-of-line (C++ [dcl.meaning]p1).
|
|
|
|
Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line)
|
|
|
|
<< D.getCXXScopeSpec().getRange();
|
|
|
|
NewVD->Destroy(Context);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-16 20:45:42 +03:00
|
|
|
Redeclaration = true;
|
|
|
|
if (MergeVarDecl(NewVD, PrevDecl))
|
|
|
|
InvalidDecl = true;
|
2009-01-16 05:36:34 +03:00
|
|
|
|
|
|
|
if (D.getCXXScopeSpec().isSet()) {
|
|
|
|
// No previous declaration in the qualifying scope.
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member)
|
|
|
|
<< Name << D.getCXXScopeSpec().getRange();
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NewVD;
|
|
|
|
}
|
|
|
|
|
2009-01-20 04:17:11 +03:00
|
|
|
NamedDecl*
|
2009-01-16 04:13:29 +03:00
|
|
|
Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
2009-01-20 04:17:11 +03:00
|
|
|
QualType R, Decl *LastDeclarator,
|
2009-01-16 04:13:29 +03:00
|
|
|
Decl* PrevDecl, bool IsFunctionDefinition,
|
2009-02-16 20:45:42 +03:00
|
|
|
bool& InvalidDecl, bool &Redeclaration) {
|
2009-01-16 04:13:29 +03:00
|
|
|
assert(R.getTypePtr()->isFunctionType());
|
|
|
|
|
|
|
|
DeclarationName Name = GetNameForDeclarator(D);
|
|
|
|
FunctionDecl::StorageClass SC = FunctionDecl::None;
|
|
|
|
switch (D.getDeclSpec().getStorageClassSpec()) {
|
|
|
|
default: assert(0 && "Unknown storage class!");
|
|
|
|
case DeclSpec::SCS_auto:
|
|
|
|
case DeclSpec::SCS_register:
|
|
|
|
case DeclSpec::SCS_mutable:
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func);
|
|
|
|
InvalidDecl = true;
|
|
|
|
break;
|
|
|
|
case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
|
|
|
|
case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break;
|
|
|
|
case DeclSpec::SCS_static: SC = FunctionDecl::Static; break;
|
|
|
|
case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isInline = D.getDeclSpec().isInlineSpecified();
|
|
|
|
// bool isVirtual = D.getDeclSpec().isVirtualSpecified();
|
|
|
|
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
|
|
|
|
|
|
|
|
FunctionDecl *NewFD;
|
|
|
|
if (D.getKind() == Declarator::DK_Constructor) {
|
|
|
|
// This is a C++ constructor declaration.
|
|
|
|
assert(DC->isRecord() &&
|
|
|
|
"Constructors can only be declared in a member context");
|
|
|
|
|
|
|
|
InvalidDecl = InvalidDecl || CheckConstructorDeclarator(D, R, SC);
|
|
|
|
|
|
|
|
// Create the new declaration
|
|
|
|
NewFD = CXXConstructorDecl::Create(Context,
|
|
|
|
cast<CXXRecordDecl>(DC),
|
|
|
|
D.getIdentifierLoc(), Name, R,
|
|
|
|
isExplicit, isInline,
|
|
|
|
/*isImplicitlyDeclared=*/false);
|
|
|
|
|
|
|
|
if (InvalidDecl)
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
} else if (D.getKind() == Declarator::DK_Destructor) {
|
|
|
|
// This is a C++ destructor declaration.
|
|
|
|
if (DC->isRecord()) {
|
|
|
|
InvalidDecl = InvalidDecl || CheckDestructorDeclarator(D, R, SC);
|
|
|
|
|
|
|
|
NewFD = CXXDestructorDecl::Create(Context,
|
|
|
|
cast<CXXRecordDecl>(DC),
|
|
|
|
D.getIdentifierLoc(), Name, R,
|
|
|
|
isInline,
|
|
|
|
/*isImplicitlyDeclared=*/false);
|
|
|
|
|
|
|
|
if (InvalidDecl)
|
|
|
|
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, DC, D.getIdentifierLoc(),
|
2009-01-20 04:17:11 +03:00
|
|
|
Name, R, SC, isInline,
|
2009-01-16 04:13:29 +03:00
|
|
|
// FIXME: Move to DeclGroup...
|
|
|
|
D.getDeclSpec().getSourceRange().getBegin());
|
|
|
|
InvalidDecl = true;
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
}
|
|
|
|
} else if (D.getKind() == Declarator::DK_Conversion) {
|
|
|
|
if (!DC->isRecord()) {
|
|
|
|
Diag(D.getIdentifierLoc(),
|
|
|
|
diag::err_conv_function_not_member);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC);
|
|
|
|
|
|
|
|
NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
|
|
|
|
D.getIdentifierLoc(), Name, R,
|
|
|
|
isInline, isExplicit);
|
|
|
|
|
|
|
|
if (InvalidDecl)
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
}
|
|
|
|
} else if (DC->isRecord()) {
|
|
|
|
// This is a C++ method declaration.
|
|
|
|
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
|
|
|
|
D.getIdentifierLoc(), Name, R,
|
2009-01-20 04:17:11 +03:00
|
|
|
(SC == FunctionDecl::Static), isInline);
|
2009-01-16 04:13:29 +03:00
|
|
|
} else {
|
|
|
|
NewFD = FunctionDecl::Create(Context, DC,
|
|
|
|
D.getIdentifierLoc(),
|
2009-01-20 04:17:11 +03:00
|
|
|
Name, R, SC, isInline,
|
2009-01-16 04:13:29 +03:00
|
|
|
// FIXME: Move to DeclGroup...
|
|
|
|
D.getDeclSpec().getSourceRange().getBegin());
|
|
|
|
}
|
2009-01-20 04:17:11 +03:00
|
|
|
NewFD->setNextDeclarator(LastDeclarator);
|
2009-01-16 04:13:29 +03:00
|
|
|
|
|
|
|
// Set the lexical context. If the declarator has a C++
|
|
|
|
// scope specifier, the lexical context will be different
|
|
|
|
// from the semantic context.
|
|
|
|
NewFD->setLexicalDeclContext(CurContext);
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
NewFD->addAttr(new AsmLabelAttr(std::string(SE->getStrData(),
|
|
|
|
SE->getByteLength())));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the parameter declarations from the declarator D to
|
|
|
|
// the function declaration NewFD, if they are available.
|
|
|
|
if (D.getNumTypeObjects() > 0) {
|
|
|
|
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
|
|
|
|
// single void argument.
|
|
|
|
// We let through "const void" here because Sema::GetTypeForDeclarator
|
|
|
|
// already checks for that case.
|
|
|
|
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.
|
|
|
|
ParmVarDecl *Param = (ParmVarDecl*)FTI.ArgInfo[0].Param;
|
|
|
|
|
|
|
|
// In C++, the empty parameter-type-list must be spelled "void"; a
|
|
|
|
// typedef of void is not permitted.
|
|
|
|
if (getLangOptions().CPlusPlus &&
|
|
|
|
Param->getType().getUnqualifiedType() != Context.VoidTy) {
|
|
|
|
Diag(Param->getLocation(), diag::ext_param_typedef_of_void);
|
|
|
|
}
|
|
|
|
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
|
|
|
|
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
|
|
|
|
Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
|
|
|
|
}
|
|
|
|
|
|
|
|
NewFD->setParams(Context, &Params[0], Params.size());
|
|
|
|
} 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) {
|
2009-02-16 23:58:07 +03:00
|
|
|
ParmVarDecl *Param = ParmVarDecl::Create(Context, DC,
|
|
|
|
SourceLocation(), 0,
|
|
|
|
*ArgType, VarDecl::None,
|
|
|
|
0);
|
|
|
|
Param->setImplicit();
|
|
|
|
Params.push_back(Param);
|
2009-01-16 04:13:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
NewFD->setParams(Context, &Params[0], Params.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
|
|
|
|
InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
|
|
|
|
else if (isa<CXXDestructorDecl>(NewFD)) {
|
|
|
|
CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
|
|
|
|
Record->setUserDeclaredDestructor(true);
|
|
|
|
// C++ [class]p4: A POD-struct is an aggregate class that has [...] no
|
|
|
|
// user-defined destructor.
|
|
|
|
Record->setPOD(false);
|
|
|
|
} else if (CXXConversionDecl *Conversion =
|
|
|
|
dyn_cast<CXXConversionDecl>(NewFD))
|
|
|
|
ActOnConversionDeclarator(Conversion);
|
|
|
|
|
|
|
|
// Extra checking for C++ overloaded operators (C++ [over.oper]).
|
|
|
|
if (NewFD->isOverloadedOperator() &&
|
|
|
|
CheckOverloadedOperatorDeclaration(NewFD))
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
|
|
|
|
// 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.
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64336 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-12 02:02:49 +03:00
|
|
|
bool OverloadableAttrRequired = false;
|
2009-01-16 04:13:29 +03:00
|
|
|
if (PrevDecl &&
|
|
|
|
(!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64336 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-12 02:02:49 +03:00
|
|
|
// Determine whether NewFD is an overload of PrevDecl or
|
2009-01-16 04:13:29 +03:00
|
|
|
// 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;
|
2009-02-13 03:26:38 +03:00
|
|
|
|
|
|
|
if (!getLangOptions().CPlusPlus &&
|
2009-02-18 09:34:51 +03:00
|
|
|
AllowOverloadingOfFunction(PrevDecl, Context)) {
|
2009-02-13 03:26:38 +03:00
|
|
|
OverloadableAttrRequired = true;
|
|
|
|
|
2009-02-18 09:34:51 +03:00
|
|
|
// Functions marked "overloadable" must have a prototype (that
|
|
|
|
// we can't get through declaration merging).
|
|
|
|
if (!R->getAsFunctionTypeProto()) {
|
|
|
|
Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype)
|
|
|
|
<< NewFD;
|
|
|
|
InvalidDecl = true;
|
|
|
|
Redeclaration = true;
|
|
|
|
|
|
|
|
// Turn this into a variadic function with no parameters.
|
|
|
|
R = Context.getFunctionType(R->getAsFunctionType()->getResultType(),
|
|
|
|
0, 0, true, 0);
|
|
|
|
NewFD->setType(R);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PrevDecl &&
|
|
|
|
(!AllowOverloadingOfFunction(PrevDecl, Context) ||
|
|
|
|
!IsOverload(NewFD, PrevDecl, MatchedDecl))) {
|
2009-02-16 20:45:42 +03:00
|
|
|
Redeclaration = true;
|
2009-01-16 04:13:29 +03:00
|
|
|
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.
|
2009-02-16 20:45:42 +03:00
|
|
|
if (MergeFunctionDecl(NewFD, OldDecl))
|
|
|
|
InvalidDecl = true;
|
2009-01-16 04:13:29 +03:00
|
|
|
|
2009-02-16 20:45:42 +03:00
|
|
|
if (!InvalidDecl) {
|
2009-01-16 04:13:29 +03:00
|
|
|
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
|
|
|
|
|
|
|
|
// An out-of-line member function declaration must also be a
|
|
|
|
// definition (C++ [dcl.meaning]p1).
|
|
|
|
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
|
|
|
|
!InvalidDecl) {
|
|
|
|
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
|
|
|
|
<< D.getCXXScopeSpec().getRange();
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-02-06 20:46:57 +03:00
|
|
|
}
|
2009-01-16 04:13:29 +03:00
|
|
|
|
2009-02-06 20:46:57 +03:00
|
|
|
if (D.getCXXScopeSpec().isSet() &&
|
|
|
|
(!PrevDecl || !Redeclaration)) {
|
|
|
|
// The user tried to provide an out-of-line definition for a
|
|
|
|
// function that is a member of a class or namespace, but there
|
|
|
|
// was no such member function declared (C++ [class.mfct]p2,
|
|
|
|
// C++ [namespace.memdef]p2). For example:
|
|
|
|
//
|
|
|
|
// class X {
|
|
|
|
// void f() const;
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// void X::f() { } // ill-formed
|
|
|
|
//
|
|
|
|
// Complain about this problem, and attempt to suggest close
|
|
|
|
// matches (e.g., those that differ only in cv-qualifiers and
|
|
|
|
// whether the parameter types are references).
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
|
2009-02-07 01:58:38 +03:00
|
|
|
<< cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange();
|
2009-02-06 20:46:57 +03:00
|
|
|
InvalidDecl = true;
|
|
|
|
|
|
|
|
LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName,
|
|
|
|
true);
|
|
|
|
assert(!Prev.isAmbiguous() &&
|
|
|
|
"Cannot have an ambiguity in previous-declaration lookup");
|
|
|
|
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
|
|
|
|
Func != FuncEnd; ++Func) {
|
|
|
|
if (isa<FunctionDecl>(*Func) &&
|
|
|
|
isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD))
|
|
|
|
Diag((*Func)->getLocation(), diag::note_member_def_close_match);
|
2009-01-16 04:13:29 +03:00
|
|
|
}
|
2009-02-06 20:46:57 +03:00
|
|
|
|
|
|
|
PrevDecl = 0;
|
2009-01-16 04:13:29 +03:00
|
|
|
}
|
2009-02-03 00:35:47 +03:00
|
|
|
|
2009-01-16 04:13:29 +03:00
|
|
|
// Handle attributes. We need to have merged decls when handling attributes
|
|
|
|
// (for example to check for conflicts, etc).
|
|
|
|
ProcessDeclAttributes(NewFD, D);
|
2009-02-14 21:57:46 +03:00
|
|
|
AddKnownFunctionAttributes(NewFD);
|
2009-01-16 04:13:29 +03:00
|
|
|
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64336 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-12 02:02:49 +03:00
|
|
|
if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
|
|
|
|
// If a function name is overloadable in C, then every function
|
|
|
|
// with that name must be marked "overloadable".
|
|
|
|
Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
|
2009-02-13 03:26:38 +03:00
|
|
|
<< Redeclaration << NewFD;
|
Initial implementation of function overloading in C.
This commit adds a new attribute, "overloadable", that enables C++
function overloading in C. The attribute can only be added to function
declarations, e.g.,
int *f(int) __attribute__((overloadable));
If the "overloadable" attribute exists on a function with a given
name, *all* functions with that name (and in that scope) must have the
"overloadable" attribute. Sets of overloaded functions with the
"overloadable" attribute then follow the normal C++ rules for
overloaded functions, e.g., overloads must have different
parameter-type-lists from each other.
When calling an overloaded function in C, we follow the same
overloading rules as C++, with three extensions to the set of standard
conversions:
- A value of a given struct or union type T can be converted to the
type T. This is just the identity conversion. (In C++, this would
go through a copy constructor).
- A value of pointer type T* can be converted to a value of type U*
if T and U are compatible types. This conversion has Conversion
rank (it's considered a pointer conversion in C).
- A value of type T can be converted to a value of type U if T and U
are compatible (and are not both pointer types). This conversion
has Conversion rank (it's considered to be a new kind of
conversion unique to C, a "compatible" conversion).
Known defects (and, therefore, next steps):
1) The standard-conversion handling does not understand conversions
involving _Complex or vector extensions, so it is likely to get
these wrong. We need to add these conversions.
2) All overloadable functions with the same name will have the same
linkage name, which means we'll get a collision in the linker (if
not sooner). We'll need to mangle the names of these functions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64336 91177308-0d34-0410-b5e6-96231b3b80d8
2009-02-12 02:02:49 +03:00
|
|
|
if (PrevDecl)
|
|
|
|
Diag(PrevDecl->getLocation(),
|
|
|
|
diag::note_attribute_overloadable_prev_overload);
|
|
|
|
NewFD->addAttr(new OverloadableAttr);
|
|
|
|
}
|
|
|
|
|
2009-01-16 04:13:29 +03:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
2009-02-08 17:56:26 +03:00
|
|
|
// In C++, check default arguments now that we have merged decls. Unless
|
|
|
|
// the lexical context is the class, because in this case this is done
|
|
|
|
// during delayed parsing anyway.
|
|
|
|
if (!CurContext->isRecord())
|
|
|
|
CheckCXXDefaultArguments(NewFD);
|
2009-01-16 04:13:29 +03:00
|
|
|
|
|
|
|
// An out-of-line member function declaration must also be a
|
|
|
|
// definition (C++ [dcl.meaning]p1).
|
|
|
|
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
|
|
|
|
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
|
|
|
|
<< D.getCXXScopeSpec().getRange();
|
|
|
|
InvalidDecl = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NewFD;
|
|
|
|
}
|
|
|
|
|
2008-10-27 14:34:16 +03:00
|
|
|
void Sema::InitializerElementNotConstant(const Expr *Init) {
|
2008-11-19 08:27:50 +03:00
|
|
|
Diag(Init->getExprLoc(), diag::err_init_element_not_constant)
|
|
|
|
<< Init->getSourceRange();
|
2008-10-27 14:34:16 +03:00
|
|
|
}
|
|
|
|
|
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();
|
2009-01-06 08:10:23 +03:00
|
|
|
case Expr::DeclRefExprClass:
|
|
|
|
case Expr::QualifiedDeclRefExprClass: {
|
2008-05-20 17:48:25 +04:00
|
|
|
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:
|
2008-11-14 19:09:21 +03:00
|
|
|
case Expr::CXXOperatorCallExprClass:
|
2008-10-06 11:26:43 +04:00
|
|
|
// __builtin___CFStringMakeConstantString is a valid constant l-value.
|
2009-02-14 21:57:46 +03:00
|
|
|
if (cast<CallExpr>(Init)->isBuiltinCall(Context) ==
|
2008-10-06 11:26:43 +04:00
|
|
|
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-11-23 00:04:56 +03:00
|
|
|
bool Sema::CheckArithmeticConstantExpression(const Expr* Init) {
|
2008-05-20 17:48:25 +04:00
|
|
|
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;
|
2008-11-14 19:09:21 +03:00
|
|
|
case Expr::CallExprClass:
|
|
|
|
case Expr::CXXOperatorCallExprClass: {
|
2008-05-20 17:48:25 +04:00
|
|
|
const CallExpr *CE = cast<CallExpr>(Init);
|
2008-10-06 10:49:02 +04:00
|
|
|
|
|
|
|
// Allow any constant foldable calls to builtins.
|
2009-02-14 21:57:46 +03:00
|
|
|
if (CE->isBuiltinCall(Context) && 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;
|
|
|
|
}
|
2009-01-06 08:10:23 +03:00
|
|
|
case Expr::DeclRefExprClass:
|
|
|
|
case Expr::QualifiedDeclRefExprClass: {
|
2008-05-20 17:48:25 +04:00
|
|
|
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::OffsetOf:
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
2008-11-11 20:56:53 +03:00
|
|
|
case Expr::SizeOfAlignOfExprClass: {
|
|
|
|
const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(Init);
|
2008-05-20 17:48:25 +04:00
|
|
|
// Special check for void types, which are allowed as an extension
|
2008-11-11 20:56:53 +03:00
|
|
|
if (Exp->getTypeOfArgument()->isVoidType())
|
2008-05-20 17:48:25 +04:00
|
|
|
return false;
|
|
|
|
// alignof always evaluates to a constant.
|
|
|
|
// FIXME: is sizeof(int[3.0]) a constant expression?
|
2008-11-11 20:56:53 +03:00
|
|
|
if (Exp->isSizeOf() && !Exp->getTypeOfArgument()->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: {
|
2009-02-03 01:57:15 +03:00
|
|
|
const CastExpr *CE = cast<CastExpr>(Init);
|
|
|
|
const Expr *SubExpr = CE->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);
|
2009-02-03 01:57:15 +03:00
|
|
|
if (Base) {
|
|
|
|
// the cast is only valid if done to a wide enough type
|
|
|
|
if (Context.getTypeSize(CE->getType()) >=
|
|
|
|
Context.getTypeSize(SubExpr->getType()))
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
// If the pointer has a null base, this is an offsetof-like construct
|
|
|
|
return CheckAddressConstantExpression(SubExpr);
|
|
|
|
}
|
2008-09-02 13:37:00 +04:00
|
|
|
}
|
|
|
|
|
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.
|
2008-12-19 23:58:05 +03:00
|
|
|
Expr::EvalResult EvalResult;
|
|
|
|
if (!Exp->getCond()->Evaluate(EvalResult, Context) ||
|
|
|
|
EvalResult.HasSideEffects) {
|
2008-11-17 00:24:15 +03:00
|
|
|
// If Evaluate couldn't fold it, CheckArithmeticConstantExpression
|
2008-10-06 09:42:39 +04:00
|
|
|
// won't be able to either. Use it to emit the diagnostic though.
|
|
|
|
bool Res = CheckArithmeticConstantExpression(Exp->getCond());
|
2008-11-17 00:24:15 +03:00
|
|
|
assert(Res && "Evaluate couldn't evaluate this constant?");
|
2008-10-06 09:42:39 +04:00
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that the side following the condition is also a constant.
|
|
|
|
const Expr *TrueSide = Exp->getLHS(), *FalseSide = Exp->getRHS();
|
2008-12-19 23:58:05 +03:00
|
|
|
if (EvalResult.Val.getInt() == 0)
|
2008-10-06 09:42:39 +04:00
|
|
|
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(),
|
2008-11-19 08:27:50 +03:00
|
|
|
diag::ext_typecheck_expression_not_constant_but_accepted)
|
|
|
|
<< FalseSide->getSourceRange();
|
2008-10-06 09:42:39 +04:00
|
|
|
return false;
|
2008-05-20 17:48:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
|
2009-01-22 03:58:24 +03:00
|
|
|
if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init))
|
|
|
|
Init = DIE->getInit();
|
|
|
|
|
2008-07-07 20:46:50 +04:00
|
|
|
Init = Init->IgnoreParens();
|
|
|
|
|
2009-01-18 06:20:47 +03:00
|
|
|
if (Init->isEvaluatable(Context))
|
2008-12-05 08:09:56 +03:00
|
|
|
return false;
|
|
|
|
|
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);
|
|
|
|
|
2009-01-29 20:44:32 +03:00
|
|
|
if (isa<ImplicitValueInitExpr>(Init)) {
|
|
|
|
// FIXME: In C++, check for non-POD types.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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?
|
2009-01-29 00:54:33 +03:00
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
if (CheckForConstantInitializer(Exp->getInit(i),
|
|
|
|
Exp->getInit(i)->getType()))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-12-05 08:09:56 +03:00
|
|
|
// FIXME: We can probably remove some of this code below, now that
|
|
|
|
// Expr::Evaluate is doing the heavy lifting for scalars.
|
|
|
|
|
2008-05-20 17:48:25 +04:00
|
|
|
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;
|
2009-01-15 19:44:45 +03:00
|
|
|
|
|
|
|
// GCC cast to union extension
|
|
|
|
// note: the validity of the cast expr is checked by CheckCastTypes()
|
|
|
|
if (CastExpr *C = dyn_cast<CastExpr>(Init)) {
|
|
|
|
QualType T = C->getType();
|
|
|
|
return T->isUnionType() && CheckForConstantInitializer(C->getSubExpr(), T);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2008-12-13 19:23:55 +03:00
|
|
|
void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init) {
|
2009-01-14 18:45:31 +03:00
|
|
|
AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// AddInitializerToDecl - Adds the initializer Init to the
|
|
|
|
/// declaration dcl. If DirectInit is true, this is C++ direct
|
|
|
|
/// initialization rather than copy initialization.
|
|
|
|
void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit) {
|
2007-09-13 00:13:48 +04:00
|
|
|
Decl *RealDecl = static_cast<Decl *>(dcl);
|
2008-12-13 19:23:55 +03:00
|
|
|
Expr *Init = static_cast<Expr *>(init.release());
|
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) {
|
2009-02-07 04:47:29 +03:00
|
|
|
Init->Destroy(Context);
|
2007-10-20 00:10:30 +04:00
|
|
|
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) {
|
2009-01-20 04:17:11 +03:00
|
|
|
Diag(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(),
|
2009-01-14 18:45:31 +03:00
|
|
|
VDecl->getDeclName(), DirectInit))
|
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.
|
2009-02-20 04:34:21 +03:00
|
|
|
// Don't check invalid declarations to avoid emitting useless diagnostics.
|
|
|
|
if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) {
|
2008-08-22 09:00:02 +04:00
|
|
|
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(),
|
2009-01-14 18:45:31 +03:00
|
|
|
VDecl->getDeclName(), DirectInit))
|
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.
|
2009-02-20 04:34:21 +03:00
|
|
|
// Don't check invalid declarations to avoid emitting useless diagnostics.
|
|
|
|
if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) {
|
2008-08-22 09:00:02 +04:00
|
|
|
// 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-12-16 00:24:18 +03:00
|
|
|
if (Type->isReferenceType() &&
|
|
|
|
Var->getStorageClass() != VarDecl::Extern &&
|
|
|
|
Var->getStorageClass() != VarDecl::PrivateExtern) {
|
2008-11-20 09:06:08 +03:00
|
|
|
Diag(Var->getLocation(), diag::err_reference_var_requires_init)
|
2008-11-24 08:29:24 +03:00
|
|
|
<< Var->getDeclName()
|
|
|
|
<< 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();
|
2008-12-16 00:24:18 +03:00
|
|
|
if (Var->getStorageClass() != VarDecl::Extern &&
|
|
|
|
Var->getStorageClass() != VarDecl::PrivateExtern &&
|
|
|
|
InitType->isRecordType()) {
|
2008-11-05 18:29:30 +03:00
|
|
|
const CXXConstructorDecl *Constructor
|
|
|
|
= PerformInitializationByConstructor(InitType, 0, 0,
|
|
|
|
Var->getLocation(),
|
|
|
|
SourceRange(Var->getLocation(),
|
|
|
|
Var->getLocation()),
|
2008-11-24 08:29:24 +03:00
|
|
|
Var->getDeclName(),
|
2008-11-05 18:29:30 +03:00
|
|
|
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-11-20 09:38:18 +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.
|
2009-02-17 23:23:54 +03:00
|
|
|
Decl *Group = static_cast<Decl*>(group);
|
|
|
|
if (Group == 0)
|
2007-09-12 18:07:44 +04:00
|
|
|
return 0;
|
2007-09-14 03:52:58 +04:00
|
|
|
|
2009-01-20 04:17:11 +03:00
|
|
|
Decl *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) {
|
2009-01-20 04:17:11 +03:00
|
|
|
Decl *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.
|
2009-01-20 04:17:11 +03:00
|
|
|
for (Decl *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();
|
|
|
|
|
2008-12-07 03:20:55 +03:00
|
|
|
if (T->isVariableArrayType()) {
|
2008-12-21 00:51:53 +03:00
|
|
|
const VariableArrayType *VAT = Context.getAsVariableArrayType(T);
|
2008-12-07 03:49:48 +03:00
|
|
|
|
|
|
|
// FIXME: This won't give the correct result for
|
|
|
|
// int a[10][n];
|
|
|
|
SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange();
|
2008-12-07 03:20:55 +03:00
|
|
|
if (IDecl->isFileVarDecl()) {
|
2008-12-07 03:49:48 +03:00
|
|
|
Diag(IDecl->getLocation(), diag::err_vla_decl_in_file_scope) <<
|
|
|
|
SizeRange;
|
|
|
|
|
2008-02-15 21:16:39 +03:00
|
|
|
IDecl->setInvalidDecl();
|
2008-12-07 03:20:55 +03:00
|
|
|
} else {
|
|
|
|
// C99 6.7.5.2p2: If an identifier is declared to be an object with
|
|
|
|
// static storage duration, it shall not have a variable length array.
|
|
|
|
if (IDecl->getStorageClass() == VarDecl::Static) {
|
2008-12-07 03:49:48 +03:00
|
|
|
Diag(IDecl->getLocation(), diag::err_vla_decl_has_static_storage)
|
|
|
|
<< SizeRange;
|
2008-12-07 03:20:55 +03:00
|
|
|
IDecl->setInvalidDecl();
|
|
|
|
} else if (IDecl->getStorageClass() == VarDecl::Extern) {
|
2008-12-07 03:49:48 +03:00
|
|
|
Diag(IDecl->getLocation(), diag::err_vla_decl_has_extern_linkage)
|
|
|
|
<< SizeRange;
|
2008-12-07 03:20:55 +03:00
|
|
|
IDecl->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (T->isVariablyModifiedType()) {
|
|
|
|
if (IDecl->isFileVarDecl()) {
|
|
|
|
Diag(IDecl->getLocation(), diag::err_vm_decl_in_file_scope);
|
|
|
|
IDecl->setInvalidDecl();
|
|
|
|
} else {
|
|
|
|
if (IDecl->getStorageClass() == VarDecl::Extern) {
|
|
|
|
Diag(IDecl->getLocation(), diag::err_vm_decl_has_extern_linkage);
|
|
|
|
IDecl->setInvalidDecl();
|
|
|
|
}
|
2007-09-12 18:07:44 +04:00
|
|
|
}
|
|
|
|
}
|
2008-12-07 03:20:55 +03:00
|
|
|
|
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) {
|
2009-01-19 22:26:10 +03:00
|
|
|
if (!IDecl->isInvalidDecl() &&
|
|
|
|
DiagnoseIncompleteType(IDecl->getLocation(), T,
|
|
|
|
diag::err_typecheck_decl_incomplete_type))
|
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.
|
2009-01-19 22:26:10 +03:00
|
|
|
} else if (!IDecl->isInvalidDecl() &&
|
|
|
|
DiagnoseIncompleteType(IDecl->getLocation(), T,
|
|
|
|
diag::err_typecheck_decl_incomplete_type))
|
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-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-12-16 02:53:10 +03:00
|
|
|
|
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();
|
2009-01-21 05:38:50 +03:00
|
|
|
if (II) {
|
2009-02-04 20:27:36 +03:00
|
|
|
if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) {
|
2009-01-21 05:38:50 +03:00
|
|
|
if (PrevDecl->isTemplateParameter()) {
|
|
|
|
// Maybe we will complain about the shadowed template parameter.
|
|
|
|
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
|
|
|
|
// Just pretend that we didn't see the previous declaration.
|
|
|
|
PrevDecl = 0;
|
|
|
|
} else if (S->isDeclScope(PrevDecl)) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II;
|
|
|
|
|
|
|
|
// Recover by removing the name
|
|
|
|
II = 0;
|
|
|
|
D.SetIdentifier(0, D.getIdentifierLoc());
|
|
|
|
}
|
2008-04-08 08:40:51 +04:00
|
|
|
}
|
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-12-11 19:49:14 +03:00
|
|
|
|
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,
|
2009-01-20 04:17:11 +03:00
|
|
|
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-12-11 19:49:14 +03:00
|
|
|
|
2008-12-16 02:53:10 +03:00
|
|
|
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
|
|
|
|
if (D.getCXXScopeSpec().isSet()) {
|
|
|
|
Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
|
|
|
|
<< D.getCXXScopeSpec().getRange();
|
|
|
|
New->setInvalidDecl();
|
|
|
|
}
|
|
|
|
|
2008-12-11 19:49:14 +03:00
|
|
|
// Add the parameter declaration into this scope.
|
|
|
|
S->AddDecl(New);
|
2008-04-12 04:47:19 +04:00
|
|
|
if (II)
|
2008-12-11 19:49:14 +03:00
|
|
|
IdResolver.AddDecl(New);
|
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
|
|
|
|
2009-01-23 19:23:13 +03:00
|
|
|
void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D) {
|
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) {
|
2008-11-19 11:23:25 +03:00
|
|
|
Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared)
|
|
|
|
<< FTI.ArgInfo[i].Ident;
|
2007-07-11 21:01:13 +04:00
|
|
|
// 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);
|
2009-01-23 19:23:13 +03:00
|
|
|
FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
2009-01-23 19:23:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
|
|
|
|
assert(getCurFunctionDecl() == 0 && "Function parsing confused");
|
|
|
|
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
|
|
|
|
"Not a function declarator!");
|
|
|
|
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
|
|
|
|
|
|
|
|
if (FTI.hasPrototype) {
|
2008-04-08 08:40:51 +04:00
|
|
|
// FIXME: Diagnose arguments without names in C.
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-12-16 02:53:10 +03:00
|
|
|
Scope *ParentScope = FnBodyScope->getParent();
|
2008-01-14 23:51:29 +03:00
|
|
|
|
2008-07-01 14:37:29 +04:00
|
|
|
return ActOnStartOfFunctionDef(FnBodyScope,
|
2008-12-16 02:53:10 +03:00
|
|
|
ActOnDeclarator(ParentScope, D, 0,
|
|
|
|
/*IsFunctionDefinition=*/true));
|
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)) {
|
2008-11-24 00:45:46 +03:00
|
|
|
Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(Definition->getLocation(), diag::note_previous_definition);
|
2008-10-29 18:10:40 +03:00
|
|
|
}
|
|
|
|
|
2009-02-16 20:45:42 +03:00
|
|
|
// Builtin functions cannot be defined.
|
|
|
|
if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
|
2009-02-17 19:03:01 +03:00
|
|
|
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
|
2009-02-16 20:45:42 +03:00
|
|
|
Diag(FD->getLocation(), diag::err_builtin_definition) << FD;
|
2009-02-17 19:03:01 +03:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
}
|
2009-02-16 20:45:42 +03:00
|
|
|
}
|
|
|
|
|
2008-12-11 19:49:14 +03:00
|
|
|
PushDeclContext(FnBodyScope, FD);
|
2008-12-26 03:52:02 +03:00
|
|
|
|
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);
|
2009-01-09 21:51:29 +03:00
|
|
|
Param->setOwningFunction(FD);
|
|
|
|
|
2008-04-08 08:40:51 +04:00
|
|
|
// 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
|
|
|
|
2008-12-26 03:52:02 +03:00
|
|
|
// Checking attributes of current function definition
|
|
|
|
// dllimport attribute.
|
|
|
|
if (FD->getAttr<DLLImportAttr>() && (!FD->getAttr<DLLExportAttr>())) {
|
|
|
|
// dllimport attribute cannot be applied to definition.
|
|
|
|
if (!(FD->getAttr<DLLImportAttr>())->isInherited()) {
|
|
|
|
Diag(FD->getLocation(),
|
|
|
|
diag::err_attribute_can_be_applied_only_to_symbol_declaration)
|
|
|
|
<< "dllimport";
|
|
|
|
FD->setInvalidDecl();
|
|
|
|
return FD;
|
|
|
|
} else {
|
|
|
|
// If a symbol previously declared dllimport is later defined, the
|
|
|
|
// attribute is ignored in subsequent references, and a warning is
|
|
|
|
// emitted.
|
|
|
|
Diag(FD->getLocation(),
|
|
|
|
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
|
|
|
|
<< FD->getNameAsCString() << "dllimport";
|
|
|
|
}
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
return FD;
|
|
|
|
}
|
|
|
|
|
2008-12-13 19:23:55 +03:00
|
|
|
Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
|
2007-11-12 02:20:51 +03:00
|
|
|
Decl *dcl = static_cast<Decl *>(D);
|
2008-12-13 19:23:55 +03:00
|
|
|
Stmt *Body = static_cast<Stmt*>(BodyArg.release());
|
2008-07-25 21:57:26 +04:00
|
|
|
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) {
|
2008-12-13 19:23:55 +03:00
|
|
|
FD->setBody(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)) {
|
2009-02-16 22:27:54 +03:00
|
|
|
assert(MD == getCurMethodDecl() && "Method parsing confused");
|
2007-11-12 02:20:51 +03:00
|
|
|
MD->setBody((Stmt*)Body);
|
2009-02-07 04:47:29 +03:00
|
|
|
} else {
|
|
|
|
Body->Destroy(Context);
|
2008-07-25 21:57:26 +04:00
|
|
|
return 0;
|
2009-02-07 04:47:29 +03:00
|
|
|
}
|
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.
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
|
2007-11-10 19:31:34 +03:00
|
|
|
|
|
|
|
// At this point, we have gotos that use the bogus label. Stitch it into
|
|
|
|
// the function body so that they aren't leaked and that the AST is well
|
|
|
|
// formed.
|
2008-01-25 03:01:10 +03:00
|
|
|
if (Body) {
|
2009-02-07 04:47:29 +03:00
|
|
|
#if 0
|
|
|
|
// FIXME: Why do this? Having a 'push_back' in CompoundStmt is ugly,
|
|
|
|
// and the AST is malformed anyway. We should just blow away 'L'.
|
|
|
|
L->setSubStmt(new (Context) NullStmt(L->getIdentLoc()));
|
|
|
|
cast<CompoundStmt>(Body)->push_back(L);
|
|
|
|
#else
|
|
|
|
L->Destroy(Context);
|
|
|
|
#endif
|
2008-01-25 03:01:10 +03:00
|
|
|
} else {
|
|
|
|
// The whole function wasn't parsed correctly, just delete this.
|
2009-02-07 04:47:29 +03:00
|
|
|
L->Destroy(Context);
|
2008-01-25 03:01:10 +03:00
|
|
|
}
|
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).
|
2009-01-20 04:17:11 +03:00
|
|
|
NamedDecl *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)
|
2008-11-19 11:23:25 +03:00
|
|
|
Diag(Loc, diag::ext_implicit_function_decl) << &II;
|
2008-05-06 01:18:06 +04:00
|
|
|
else
|
2008-11-19 11:23:25 +03:00
|
|
|
Diag(Loc, diag::warn_implicit_function_decl) << &II;
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
// 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);
|
2009-02-18 10:07:28 +03:00
|
|
|
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(),
|
|
|
|
0, 0, 0, Loc, D),
|
2009-02-09 21:23:29 +03:00
|
|
|
SourceLocation());
|
2007-07-11 21:01:13 +04:00
|
|
|
D.SetIdentifier(&II, Loc);
|
2009-02-09 21:23:29 +03:00
|
|
|
|
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;
|
|
|
|
|
2009-02-14 21:57:46 +03:00
|
|
|
AddKnownFunctionAttributes(FD);
|
|
|
|
|
2008-04-04 18:32:09 +04:00
|
|
|
return FD;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2009-02-14 21:57:46 +03:00
|
|
|
/// \brief Adds any function attributes that we know a priori based on
|
|
|
|
/// the declaration of this function.
|
|
|
|
///
|
|
|
|
/// These attributes can apply both to implicitly-declared builtins
|
|
|
|
/// (like __builtin___printf_chk) or to library-declared functions
|
|
|
|
/// like NSLog or printf.
|
|
|
|
void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
|
|
|
|
if (FD->isInvalidDecl())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If this is a built-in function, map its builtin attributes to
|
|
|
|
// actual attributes.
|
|
|
|
if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
|
|
|
|
// Handle printf-formatting attributes.
|
|
|
|
unsigned FormatIdx;
|
|
|
|
bool HasVAListArg;
|
|
|
|
if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) {
|
|
|
|
if (!FD->getAttr<FormatAttr>())
|
|
|
|
FD->addAttr(new FormatAttr("printf", FormatIdx + 1, FormatIdx + 2));
|
|
|
|
}
|
2009-02-17 01:43:43 +03:00
|
|
|
|
|
|
|
// Mark const if we don't care about errno and that is the only
|
|
|
|
// thing preventing the function from being const. This allows
|
|
|
|
// IRgen to use LLVM intrinsics for such functions.
|
|
|
|
if (!getLangOptions().MathErrno &&
|
|
|
|
Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) {
|
|
|
|
if (!FD->getAttr<ConstAttr>())
|
|
|
|
FD->addAttr(new ConstAttr());
|
|
|
|
}
|
2009-02-14 21:57:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo *Name = FD->getIdentifier();
|
|
|
|
if (!Name)
|
|
|
|
return;
|
|
|
|
if ((!getLangOptions().CPlusPlus &&
|
|
|
|
FD->getDeclContext()->isTranslationUnit()) ||
|
|
|
|
(isa<LinkageSpecDecl>(FD->getDeclContext()) &&
|
|
|
|
cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() ==
|
|
|
|
LinkageSpecDecl::lang_c)) {
|
|
|
|
// Okay: this could be a libc/libm/Objective-C function we know
|
|
|
|
// about.
|
|
|
|
} else
|
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned KnownID;
|
|
|
|
for (KnownID = 0; KnownID != id_num_known_functions; ++KnownID)
|
|
|
|
if (KnownFunctionIDs[KnownID] == Name)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (KnownID) {
|
|
|
|
case id_NSLog:
|
|
|
|
case id_NSLogv:
|
|
|
|
if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) {
|
|
|
|
// FIXME: We known better than our headers.
|
|
|
|
const_cast<FormatAttr *>(Format)->setType("printf");
|
|
|
|
} else
|
|
|
|
FD->addAttr(new FormatAttr("printf", 1, 2));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case id_asprintf:
|
|
|
|
case id_vasprintf:
|
|
|
|
if (!FD->getAttr<FormatAttr>())
|
|
|
|
FD->addAttr(new FormatAttr("printf", 2, 3));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Unknown function or known function without any attributes to
|
|
|
|
// add. Do nothing.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
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,
|
2009-01-20 04:17:11 +03:00
|
|
|
Decl *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(),
|
2009-01-20 04:17:11 +03:00
|
|
|
T);
|
|
|
|
NewTD->setNextDeclarator(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.
|
2009-01-17 03:42:38 +03:00
|
|
|
/// TagSpec indicates what kind of tag this is. TK indicates whether this is a
|
2007-07-11 21:01:13 +04:00
|
|
|
/// reference/declaration/definition of a tag.
|
2009-01-17 03:42:38 +03:00
|
|
|
Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
|
2008-11-08 19:45:02 +03:00
|
|
|
SourceLocation KWLoc, const CXXScopeSpec &SS,
|
|
|
|
IdentifierInfo *Name, SourceLocation NameLoc,
|
2009-02-07 01:42:48 +03:00
|
|
|
AttributeList *Attr) {
|
2008-12-15 19:32:14 +03:00
|
|
|
// If this is not a definition, it must have a name.
|
2007-07-11 21:01:13 +04:00
|
|
|
assert((Name != 0 || TK == TK_Definition) &&
|
|
|
|
"Nameless record must be a definition!");
|
2009-02-04 22:02:06 +03:00
|
|
|
|
2008-06-10 03:19:58 +04:00
|
|
|
TagDecl::TagKind Kind;
|
2009-01-17 03:42:38 +03:00
|
|
|
switch (TagSpec) {
|
2007-07-11 21:01:13 +04:00
|
|
|
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
|
|
|
}
|
2008-11-10 01:09:58 +03:00
|
|
|
|
2009-01-13 01:49:06 +03:00
|
|
|
DeclContext *SearchDC = CurContext;
|
2008-11-10 01:53:32 +03:00
|
|
|
DeclContext *DC = CurContext;
|
2009-02-04 20:27:36 +03:00
|
|
|
NamedDecl *PrevDecl = 0;
|
2008-11-08 20:17:31 +03:00
|
|
|
|
2009-01-17 03:42:38 +03:00
|
|
|
bool Invalid = false;
|
|
|
|
|
2008-11-08 20:17:31 +03:00
|
|
|
if (Name && SS.isNotEmpty()) {
|
2008-11-10 01:09:58 +03:00
|
|
|
// We have a nested-name tag ('struct foo::bar').
|
|
|
|
|
|
|
|
// Check for invalid 'foo::'.
|
2008-11-10 01:53:32 +03:00
|
|
|
if (SS.isInvalid()) {
|
2008-11-08 20:17:31 +03:00
|
|
|
Name = 0;
|
|
|
|
goto CreateNewDecl;
|
|
|
|
}
|
|
|
|
|
2008-11-10 01:53:32 +03:00
|
|
|
DC = static_cast<DeclContext*>(SS.getScopeRep());
|
2009-02-03 03:34:39 +03:00
|
|
|
SearchDC = DC;
|
2008-11-10 01:53:32 +03:00
|
|
|
// Look-up name inside 'foo::'.
|
2009-01-29 03:07:50 +03:00
|
|
|
PrevDecl = dyn_cast_or_null<TagDecl>(
|
2009-02-03 22:21:40 +03:00
|
|
|
LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl());
|
2008-11-10 01:09:58 +03:00
|
|
|
|
|
|
|
// A tag 'foo::bar' must already exist.
|
2008-11-08 20:17:31 +03:00
|
|
|
if (PrevDecl == 0) {
|
2008-11-19 11:23:25 +03:00
|
|
|
Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
|
2008-11-08 20:17:31 +03:00
|
|
|
Name = 0;
|
|
|
|
goto CreateNewDecl;
|
|
|
|
}
|
2009-01-21 05:38:50 +03:00
|
|
|
} else if (Name) {
|
2008-11-10 01:09:58 +03:00
|
|
|
// If this is a named struct, check to see if there was a previous forward
|
|
|
|
// declaration or definition.
|
2009-02-03 22:21:40 +03:00
|
|
|
// FIXME: We're looking into outer scopes here, even when we
|
|
|
|
// shouldn't be. Doing so can result in ambiguities that we
|
|
|
|
// shouldn't be diagnosing.
|
2009-02-03 22:26:08 +03:00
|
|
|
LookupResult R = LookupName(S, Name, LookupTagName,
|
|
|
|
/*RedeclarationOnly=*/(TK != TK_Reference));
|
2009-02-03 22:21:40 +03:00
|
|
|
if (R.isAmbiguous()) {
|
|
|
|
DiagnoseAmbiguousLookup(R, Name, NameLoc);
|
|
|
|
// FIXME: This is not best way to recover from case like:
|
|
|
|
//
|
|
|
|
// struct S s;
|
|
|
|
//
|
|
|
|
// causes needless err_ovl_no_viable_function_in_init latter.
|
|
|
|
Name = 0;
|
|
|
|
PrevDecl = 0;
|
|
|
|
Invalid = true;
|
|
|
|
}
|
|
|
|
else
|
2009-02-04 20:27:36 +03:00
|
|
|
PrevDecl = R;
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
|
|
|
|
if (!getLangOptions().CPlusPlus && TK != TK_Reference) {
|
|
|
|
// FIXME: This makes sure that we ignore the contexts associated
|
|
|
|
// with C structs, unions, and enums when looking for a matching
|
|
|
|
// tag declaration or definition. See the similar lookup tweak
|
Eliminated LookupCriteria, whose creation was causing a bottleneck for
LookupName et al. Instead, use an enum and a bool to describe its
contents.
Optimized the C/Objective-C path through LookupName, eliminating any
unnecessarily C++isms. Simplify IdentifierResolver::iterator, removing
some code and arguments that are no longer used.
Eliminated LookupDeclInScope/LookupDeclInContext, moving all callers
over to LookupName, LookupQualifiedName, or LookupParsedName, as
appropriate.
All together, I'm seeing a 0.2% speedup on Cocoa.h with PTH and
-disable-free. Plus, we're down to three name-lookup routines.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63354 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-30 04:04:22 +03:00
|
|
|
// in Sema::LookupName; is there a better way to deal with this?
|
2009-01-13 01:49:06 +03:00
|
|
|
while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC))
|
|
|
|
SearchDC = SearchDC->getParent();
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
}
|
2008-11-08 20:17:31 +03:00
|
|
|
}
|
|
|
|
|
2008-12-08 21:40:42 +03:00
|
|
|
if (PrevDecl && PrevDecl->isTemplateParameter()) {
|
2008-12-05 21:15:24 +03:00
|
|
|
// Maybe we will complain about the shadowed template parameter.
|
|
|
|
DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
|
|
|
|
// Just pretend that we didn't see the previous declaration.
|
|
|
|
PrevDecl = 0;
|
|
|
|
}
|
|
|
|
|
2009-02-17 01:07:16 +03:00
|
|
|
if (PrevDecl) {
|
2009-02-19 00:56:37 +03:00
|
|
|
// Check whether the previous declaration is usable.
|
|
|
|
(void)DiagnoseUseOfDecl(PrevDecl, NameLoc);
|
2009-02-17 01:07:16 +03:00
|
|
|
|
2008-04-27 17:50:30 +04:00
|
|
|
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.
|
2009-01-13 01:49:06 +03:00
|
|
|
if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, 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-11-19 11:23:25 +03:00
|
|
|
Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(PrevDecl->getLocation(), diag::note_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;
|
2009-01-17 03:42:38 +03:00
|
|
|
Invalid = true;
|
2008-04-27 17:50:30 +04:00
|
|
|
} else {
|
2008-12-15 19:32:14 +03:00
|
|
|
// If this is a use, just return the declaration we found.
|
2008-07-03 07:30:58 +04:00
|
|
|
|
2008-12-15 19:32:14 +03:00
|
|
|
// 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;
|
2009-02-04 22:02:06 +03:00
|
|
|
|
2008-07-03 07:30:58 +04:00
|
|
|
// Diagnose attempts to redefine a tag.
|
2008-12-15 19:32:14 +03:00
|
|
|
if (TK == TK_Definition) {
|
|
|
|
if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {
|
|
|
|
Diag(NameLoc, diag::err_redefinition) << Name;
|
|
|
|
Diag(Def->getLocation(), diag::note_previous_definition);
|
2009-01-17 03:42:38 +03:00
|
|
|
// If this is a redefinition, recover by making this
|
|
|
|
// struct be anonymous, which will make any later
|
|
|
|
// references get the previous definition.
|
2008-12-15 19:32:14 +03:00
|
|
|
Name = 0;
|
|
|
|
PrevDecl = 0;
|
2009-01-17 03:42:38 +03:00
|
|
|
Invalid = true;
|
|
|
|
} else {
|
|
|
|
// If the type is currently being defined, complain
|
|
|
|
// about a nested redefinition.
|
|
|
|
TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl));
|
|
|
|
if (Tag->isBeingDefined()) {
|
|
|
|
Diag(NameLoc, diag::err_nested_redefinition) << Name;
|
|
|
|
Diag(PrevTagDecl->getLocation(),
|
|
|
|
diag::note_previous_definition);
|
|
|
|
Name = 0;
|
|
|
|
PrevDecl = 0;
|
|
|
|
Invalid = true;
|
|
|
|
}
|
2008-12-15 19:32:14 +03:00
|
|
|
}
|
2009-01-17 03:42:38 +03:00
|
|
|
|
2008-07-03 07:30:58 +04:00
|
|
|
// Okay, this is definition of a previously declared or referenced
|
2008-12-15 19:32:14 +03:00
|
|
|
// tag PrevDecl. We're going to create a new Decl for it.
|
2009-01-17 03:42:38 +03:00
|
|
|
}
|
2008-04-27 17:50:30 +04:00
|
|
|
}
|
2008-12-15 19:32:14 +03:00
|
|
|
// If we get here we have (another) forward declaration or we
|
|
|
|
// have a definition. Just create a new decl.
|
|
|
|
} else {
|
|
|
|
// If we get here, this is a definition of a new tag 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 entities
|
|
|
|
// have distinct types.
|
|
|
|
PrevDecl = 0;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-12-15 19:32:14 +03:00
|
|
|
// If we get here, we're going to create a new Decl. If PrevDecl
|
|
|
|
// is non-NULL, it's a definition of the tag declared by
|
|
|
|
// PrevDecl. If it's NULL, we have a new definition.
|
2008-04-27 17:50:30 +04:00
|
|
|
} else {
|
2009-01-28 20:15:10 +03:00
|
|
|
// PrevDecl is a namespace, template, or anything else
|
|
|
|
// that lives in the IDNS_Tag identifier namespace.
|
2009-01-13 01:49:06 +03:00
|
|
|
if (isDeclInScope(PrevDecl, SearchDC, 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-11-19 11:23:25 +03:00
|
|
|
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
|
2008-07-16 11:45:46 +04:00
|
|
|
Name = 0;
|
2008-12-15 19:32:14 +03:00
|
|
|
PrevDecl = 0;
|
2009-01-17 03:42:38 +03:00
|
|
|
Invalid = true;
|
2008-12-15 19:32:14 +03:00
|
|
|
} else {
|
|
|
|
// The existing declaration isn't relevant to us; we're in a
|
|
|
|
// new scope, so clear out the previous declaration.
|
|
|
|
PrevDecl = 0;
|
2008-07-16 11:45:46 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2009-01-10 01:42:13 +03:00
|
|
|
} else if (TK == TK_Reference && SS.isEmpty() && Name &&
|
|
|
|
(Kind != TagDecl::TK_enum)) {
|
|
|
|
// C++ [basic.scope.pdecl]p5:
|
|
|
|
// -- for an elaborated-type-specifier of the form
|
|
|
|
//
|
|
|
|
// class-key identifier
|
|
|
|
//
|
|
|
|
// if the elaborated-type-specifier is used in the
|
|
|
|
// decl-specifier-seq or parameter-declaration-clause of a
|
|
|
|
// function defined in namespace scope, the identifier is
|
|
|
|
// declared as a class-name in the namespace that contains
|
|
|
|
// the declaration; otherwise, except as a friend
|
|
|
|
// declaration, the identifier is declared in the smallest
|
|
|
|
// non-class, non-function-prototype scope that contains the
|
|
|
|
// declaration.
|
|
|
|
//
|
|
|
|
// C99 6.7.2.3p8 has a similar (but not identical!) provision for
|
|
|
|
// C structs and unions.
|
|
|
|
|
|
|
|
// Find the context where we'll be declaring the tag.
|
2009-01-13 01:49:06 +03:00
|
|
|
// FIXME: We would like to maintain the current DeclContext as the
|
|
|
|
// lexical context,
|
2009-02-03 03:34:39 +03:00
|
|
|
while (SearchDC->isRecord())
|
|
|
|
SearchDC = SearchDC->getParent();
|
2009-01-10 01:42:13 +03:00
|
|
|
|
|
|
|
// Find the scope where we'll be declaring the tag.
|
|
|
|
while (S->isClassScope() ||
|
|
|
|
(getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) ||
|
2009-01-12 21:45:55 +03:00
|
|
|
((S->getFlags() & Scope::DeclScope) == 0) ||
|
|
|
|
(S->getEntity() &&
|
|
|
|
((DeclContext *)S->getEntity())->isTransparentContext()))
|
2009-01-10 01:42:13 +03:00
|
|
|
S = S->getParent();
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-11-08 20:17:31 +03:00
|
|
|
|
2008-12-17 10:13:27 +03:00
|
|
|
CreateNewDecl:
|
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;
|
|
|
|
|
2008-12-15 19:32:14 +03:00
|
|
|
// Otherwise, create a new declaration. If there is a previous
|
|
|
|
// declaration of the same entity, the two will be linked via
|
|
|
|
// PrevDecl.
|
2007-07-11 21:01:13 +04:00
|
|
|
TagDecl *New;
|
2009-01-07 03:43:41 +03:00
|
|
|
|
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.
|
2009-02-03 03:34:39 +03:00
|
|
|
New = EnumDecl::Create(Context, SearchDC, Loc, Name,
|
2008-12-15 19:32:14 +03:00
|
|
|
cast_or_null<EnumDecl>(PrevDecl));
|
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.
|
2009-02-07 01:42:48 +03:00
|
|
|
if (getLangOptions().CPlusPlus)
|
2008-09-05 21:39:33 +04:00
|
|
|
// FIXME: Look for a way to use RecordDecl for simple structs.
|
2009-02-03 03:34:39 +03:00
|
|
|
New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
|
2008-12-15 19:32:14 +03:00
|
|
|
cast_or_null<CXXRecordDecl>(PrevDecl));
|
2009-02-07 01:42:48 +03:00
|
|
|
else
|
2009-02-03 03:34:39 +03:00
|
|
|
New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name,
|
2008-12-15 19:32:14 +03:00
|
|
|
cast_or_null<RecordDecl>(PrevDecl));
|
2008-07-01 14:37:29 +04:00
|
|
|
}
|
2008-12-15 19:32:14 +03:00
|
|
|
|
|
|
|
if (Kind != TagDecl::TK_enum) {
|
|
|
|
// 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).
|
2009-02-17 04:09:29 +03:00
|
|
|
if (unsigned Alignment = getPragmaPackAlignment())
|
2008-12-15 19:32:14 +03:00
|
|
|
New->addAttr(new PackedAttr(Alignment * 8));
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-12-15 19:32:14 +03:00
|
|
|
|
2009-01-28 20:15:10 +03:00
|
|
|
if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) {
|
|
|
|
// C++ [dcl.typedef]p3:
|
|
|
|
// [...] Similarly, in a given scope, a class or enumeration
|
|
|
|
// shall not be declared with the same name as a typedef-name
|
|
|
|
// that is declared in that scope and refers to a type other
|
|
|
|
// than the class or enumeration itself.
|
Eliminated LookupCriteria, whose creation was causing a bottleneck for
LookupName et al. Instead, use an enum and a bool to describe its
contents.
Optimized the C/Objective-C path through LookupName, eliminating any
unnecessarily C++isms. Simplify IdentifierResolver::iterator, removing
some code and arguments that are no longer used.
Eliminated LookupDeclInScope/LookupDeclInContext, moving all callers
over to LookupName, LookupQualifiedName, or LookupParsedName, as
appropriate.
All together, I'm seeing a 0.2% speedup on Cocoa.h with PTH and
-disable-free. Plus, we're down to three name-lookup routines.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63354 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-30 04:04:22 +03:00
|
|
|
LookupResult Lookup = LookupName(S, Name, LookupOrdinaryName, true);
|
2009-01-28 20:15:10 +03:00
|
|
|
TypedefDecl *PrevTypedef = 0;
|
|
|
|
if (Lookup.getKind() == LookupResult::Found)
|
|
|
|
PrevTypedef = dyn_cast<TypedefDecl>(Lookup.getAsDecl());
|
|
|
|
|
|
|
|
if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) &&
|
|
|
|
Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
|
|
|
|
Context.getCanonicalType(Context.getTypeDeclType(New))) {
|
|
|
|
Diag(Loc, diag::err_tag_definition_of_typedef)
|
|
|
|
<< Context.getTypeDeclType(New)
|
|
|
|
<< PrevTypedef->getUnderlyingType();
|
|
|
|
Diag(PrevTypedef->getLocation(), diag::note_previous_definition);
|
|
|
|
Invalid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-17 03:42:38 +03:00
|
|
|
if (Invalid)
|
|
|
|
New->setInvalidDecl();
|
|
|
|
|
2008-06-29 03:58:55 +04:00
|
|
|
if (Attr)
|
|
|
|
ProcessDeclAttributeList(New, Attr);
|
2008-11-10 02:41:00 +03:00
|
|
|
|
2009-01-17 03:42:38 +03:00
|
|
|
// If we're declaring or defining a tag in function prototype scope
|
|
|
|
// in C, note that this type can only be used within the function.
|
2009-01-10 01:42:13 +03:00
|
|
|
if (Name && S->isFunctionPrototypeScope() && !getLangOptions().CPlusPlus)
|
|
|
|
Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
|
|
|
|
|
2008-11-10 02:41:00 +03:00
|
|
|
// Set the lexical context. If the tag has a C++ scope specifier, the
|
|
|
|
// lexical context will be different from the semantic context.
|
2009-02-03 03:34:39 +03:00
|
|
|
New->setLexicalDeclContext(CurContext);
|
2009-01-17 03:42:38 +03:00
|
|
|
|
|
|
|
if (TK == TK_Definition)
|
|
|
|
New->startDefinition();
|
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 this has an identifier, add it to the scope stack.
|
2008-12-15 19:32:14 +03:00
|
|
|
if (Name) {
|
2009-01-12 21:45:55 +03:00
|
|
|
S = getNonFieldDeclScope(S);
|
2009-02-03 03:34:39 +03:00
|
|
|
PushOnScopeChains(New, S);
|
2009-01-13 01:49:06 +03:00
|
|
|
} else {
|
2009-02-03 03:34:39 +03:00
|
|
|
CurContext->addDecl(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
|
|
|
}
|
2008-10-16 06:34:03 +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
|
|
|
return New;
|
|
|
|
}
|
|
|
|
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
void Sema::ActOnTagStartDefinition(Scope *S, DeclTy *TagD) {
|
2009-02-04 22:02:06 +03:00
|
|
|
AdjustDeclIfTemplate(TagD);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
TagDecl *Tag = cast<TagDecl>((Decl *)TagD);
|
|
|
|
|
|
|
|
// Enter the tag context.
|
|
|
|
PushDeclContext(S, Tag);
|
|
|
|
|
|
|
|
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) {
|
|
|
|
FieldCollector->StartClass();
|
|
|
|
|
|
|
|
if (Record->getIdentifier()) {
|
|
|
|
// C++ [class]p2:
|
|
|
|
// [...] The class-name is also inserted into the scope of the
|
|
|
|
// class itself; this is known as the injected-class-name. For
|
|
|
|
// purposes of access checking, the injected-class-name is treated
|
|
|
|
// as if it were a public member name.
|
|
|
|
RecordDecl *InjectedClassName
|
|
|
|
= CXXRecordDecl::Create(Context, Record->getTagKind(),
|
|
|
|
CurContext, Record->getLocation(),
|
|
|
|
Record->getIdentifier(), Record);
|
|
|
|
InjectedClassName->setImplicit();
|
|
|
|
PushOnScopeChains(InjectedClassName, S);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::ActOnTagFinishDefinition(Scope *S, DeclTy *TagD) {
|
2009-02-04 22:02:06 +03:00
|
|
|
AdjustDeclIfTemplate(TagD);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
TagDecl *Tag = cast<TagDecl>((Decl *)TagD);
|
|
|
|
|
|
|
|
if (isa<CXXRecordDecl>(Tag))
|
|
|
|
FieldCollector->FinishClass();
|
|
|
|
|
|
|
|
// Exit this scope of this tag's definition.
|
|
|
|
PopDeclContext();
|
|
|
|
|
|
|
|
// Notify the consumer that we've defined a tag.
|
|
|
|
Consumer.HandleTagDeclDefinition(Tag);
|
|
|
|
}
|
2008-06-21 23:39:06 +04:00
|
|
|
|
2008-12-06 23:33:04 +03:00
|
|
|
bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
|
2008-12-12 07:56:04 +03:00
|
|
|
QualType FieldTy, const Expr *BitWidth) {
|
2008-12-06 23:33:04 +03:00
|
|
|
// FIXME: 6.7.2.1p4 - verify the field type.
|
|
|
|
|
|
|
|
llvm::APSInt Value;
|
|
|
|
if (VerifyIntegerConstantExpression(BitWidth, &Value))
|
|
|
|
return true;
|
|
|
|
|
2008-12-12 07:56:04 +03:00
|
|
|
// Zero-width bitfield is ok for anonymous field.
|
|
|
|
if (Value == 0 && FieldName)
|
|
|
|
return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName;
|
|
|
|
|
|
|
|
if (Value.isNegative())
|
|
|
|
return Diag(FieldLoc, diag::err_bitfield_has_negative_width) << FieldName;
|
2008-12-06 23:33:04 +03:00
|
|
|
|
|
|
|
uint64_t TypeSize = Context.getTypeSize(FieldTy);
|
|
|
|
// FIXME: We won't need the 0 size once we check that the field type is valid.
|
2008-12-12 07:56:04 +03:00
|
|
|
if (TypeSize && Value.getZExtValue() > TypeSize)
|
|
|
|
return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
|
|
|
|
<< FieldName << (unsigned)TypeSize;
|
2008-12-06 23:33:04 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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-12-11 19:49:14 +03:00
|
|
|
Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD,
|
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;
|
2008-12-11 19:49:14 +03:00
|
|
|
RecordDecl *Record = (RecordDecl *)TagD;
|
2007-07-11 21:01:13 +04:00
|
|
|
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!
|
|
|
|
|
|
|
|
QualType T = GetTypeForDeclarator(D, S);
|
2007-08-29 00:14:24 +04:00
|
|
|
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
|
|
|
bool InvalidDecl = false;
|
2009-01-05 23:52:13 +03: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()) {
|
2009-02-20 21:53:20 +03:00
|
|
|
Diag(Loc, diag::err_typecheck_field_variable_size);
|
|
|
|
T = Context.IntTy;
|
|
|
|
InvalidDecl = true;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-12-06 23:33:04 +03:00
|
|
|
|
|
|
|
if (BitWidth) {
|
|
|
|
if (VerifyBitField(Loc, II, T, BitWidth))
|
|
|
|
InvalidDecl = true;
|
|
|
|
} else {
|
|
|
|
// Not a bitfield.
|
|
|
|
|
|
|
|
// validate II.
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-02-20 23:41:34 +03:00
|
|
|
FieldDecl *NewFD = FieldDecl::Create(Context, Record,
|
|
|
|
Loc, II, T, BitWidth,
|
|
|
|
D.getDeclSpec().getStorageClassSpec() ==
|
|
|
|
DeclSpec::SCS_mutable);
|
2008-12-11 19:49:14 +03:00
|
|
|
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
if (II) {
|
2009-02-04 20:27:36 +03:00
|
|
|
NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)
|
|
|
|
&& !isa<TagDecl>(PrevDecl)) {
|
|
|
|
Diag(Loc, diag::err_duplicate_member) << II;
|
|
|
|
Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
|
|
|
|
NewFD->setInvalidDecl();
|
|
|
|
Record->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-05 23:52:13 +03:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
2008-12-17 00:30:33 +03:00
|
|
|
CheckExtraCXXDefaultArguments(D);
|
2009-01-05 23:52:13 +03:00
|
|
|
if (!T->isPODType())
|
|
|
|
cast<CXXRecordDecl>(Record)->setPOD(false);
|
|
|
|
}
|
2008-12-17 00:30:33 +03:00
|
|
|
|
2008-06-29 04:02:00 +04:00
|
|
|
ProcessDeclAttributes(NewFD, D);
|
2009-02-19 03:22:47 +03:00
|
|
|
if (T.isObjCGCWeak())
|
2009-02-18 21:14:41 +03:00
|
|
|
Diag(Loc, diag::warn_attribute_weak_on_field);
|
2008-02-16 03:29:18 +03:00
|
|
|
|
2007-08-29 00:14:24 +04:00
|
|
|
if (D.getInvalidType() || InvalidDecl)
|
|
|
|
NewFD->setInvalidDecl();
|
2008-12-11 19:49:14 +03:00
|
|
|
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
if (II) {
|
2008-12-11 19:49:14 +03:00
|
|
|
PushOnScopeChains(NewFD, S);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
} else
|
2009-01-13 02:27:07 +03:00
|
|
|
Record->addDecl(NewFD);
|
2008-12-11 19:49:14 +03:00
|
|
|
|
2007-08-29 00:14:24 +04:00
|
|
|
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) {
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
|
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!
|
|
|
|
|
2008-12-06 23:33:04 +03:00
|
|
|
QualType T = GetTypeForDeclarator(D, S);
|
|
|
|
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
|
|
|
|
bool InvalidDecl = false;
|
2008-04-11 03:32:45 +04:00
|
|
|
|
|
|
|
if (BitWidth) {
|
2009-02-20 20:57:11 +03:00
|
|
|
// 6.7.2.1p3, 6.7.2.1p4
|
|
|
|
if (VerifyBitField(Loc, II, T, BitWidth))
|
|
|
|
InvalidDecl = true;
|
2008-04-11 03:32:45 +04:00
|
|
|
} else {
|
|
|
|
// Not a bitfield.
|
|
|
|
|
|
|
|
// validate II.
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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()) {
|
2008-12-07 03:20:55 +03:00
|
|
|
Diag(Loc, diag::err_typecheck_ivar_variable_size);
|
2008-04-11 03:32:45 +04:00
|
|
|
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.
|
2009-02-17 23:20:37 +03:00
|
|
|
ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, CurContext, Loc, II, T,ac,
|
2008-07-16 22:22:22 +04:00
|
|
|
(Expr *)BitfieldWidth);
|
2008-04-11 03:32:45 +04:00
|
|
|
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
if (II) {
|
2009-02-04 20:27:36 +03:00
|
|
|
NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)
|
|
|
|
&& !isa<TagDecl>(PrevDecl)) {
|
|
|
|
Diag(Loc, diag::err_duplicate_member) << II;
|
|
|
|
Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
|
|
|
|
NewID->setInvalidDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
if (II) {
|
|
|
|
// FIXME: When interfaces are DeclContexts, we'll need to add
|
|
|
|
// these to the interface.
|
|
|
|
S->AddDecl(NewID);
|
|
|
|
IdResolver.AddDecl(NewID);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// Verify that all the fields are okay.
|
|
|
|
unsigned NumNamedMembers = 0;
|
|
|
|
llvm::SmallVector<FieldDecl*, 32> RecFields;
|
2009-01-07 22:46:03 +03:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
for (unsigned i = 0; i != NumFields; ++i) {
|
2007-09-15 02:20:54 +04:00
|
|
|
FieldDecl *FD = cast_or_null<FieldDecl>(static_cast<Decl*>(Fields[i]));
|
|
|
|
assert(FD && "missing field decl");
|
|
|
|
|
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();
|
2009-01-07 22:46:03 +03:00
|
|
|
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
if (!FD->isAnonymousStructOrUnion()) {
|
2009-01-07 22:46:03 +03:00
|
|
|
// Remember all fields written by the user.
|
|
|
|
RecFields.push_back(FD);
|
|
|
|
}
|
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()) {
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(FD->getLocation(), diag::err_field_declared_as_function)
|
2008-11-24 08:29:24 +03:00
|
|
|
<< FD->getDeclName();
|
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.
|
2009-01-19 22:26:10 +03:00
|
|
|
DiagnoseIncompleteType(FD->getLocation(), FD->getType(),
|
|
|
|
diag::err_field_incomplete);
|
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.
|
2009-01-19 22:26:10 +03:00
|
|
|
DiagnoseIncompleteType(FD->getLocation(), FD->getType(),
|
|
|
|
diag::err_field_incomplete);
|
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 ...
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(FD->getLocation(), diag::err_flexible_array_empty_struct)
|
2008-11-24 08:29:24 +03:00
|
|
|
<< FD->getDeclName();
|
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) {
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(FD->getLocation(), diag::err_variable_sized_type_in_struct)
|
2008-11-24 08:29:24 +03:00
|
|
|
<< FD->getDeclName();
|
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.
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(FD->getLocation(), diag::ext_flexible_array_in_struct)
|
2008-11-24 08:29:24 +03:00
|
|
|
<< FD->getDeclName();
|
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()) {
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(FD->getLocation(), diag::err_statically_allocated_object)
|
2008-11-24 00:45:46 +03:00
|
|
|
<< FD->getDeclName();
|
2007-10-13 02:10:42 +04:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
EnclosingDecl->setInvalidDecl();
|
|
|
|
continue;
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
// Keep track of the number of named members.
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
if (FD->getIdentifier())
|
2007-07-11 21:01:13 +04:00
|
|
|
++NumNamedMembers;
|
|
|
|
}
|
2009-01-05 23:52:13 +03:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// Okay, we successfully defined 'Record'.
|
2008-02-06 03:51:33 +03:00
|
|
|
if (Record) {
|
2008-12-11 19:49:14 +03:00
|
|
|
Record->completeDefinition(Context);
|
2008-02-06 03:51:33 +03:00
|
|
|
} else {
|
2008-02-06 01:40:55 +03:00
|
|
|
ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(&RecFields[0]);
|
2008-12-13 23:28:25 +03:00
|
|
|
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl)) {
|
2009-02-21 00:35:13 +03:00
|
|
|
ID->setIVarList(ClsFields, RecFields.size(), Context);
|
|
|
|
ID->setLocEnd(RBrac);
|
|
|
|
|
2008-12-16 04:08:35 +03:00
|
|
|
// Must enforce the rule that ivars in the base classes may not be
|
|
|
|
// duplicates.
|
2008-12-18 01:21:44 +03:00
|
|
|
if (ID->getSuperClass()) {
|
|
|
|
for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
|
|
|
|
IVE = ID->ivar_end(); IVI != IVE; ++IVI) {
|
|
|
|
ObjCIvarDecl* Ivar = (*IVI);
|
|
|
|
IdentifierInfo *II = Ivar->getIdentifier();
|
2009-02-16 22:35:27 +03:00
|
|
|
ObjCIvarDecl* prevIvar = ID->getSuperClass()->lookupInstanceVariable(II);
|
2008-12-18 01:21:44 +03:00
|
|
|
if (prevIvar) {
|
|
|
|
Diag(Ivar->getLocation(), diag::err_duplicate_member) << II;
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61940 91177308-0d34-0410-b5e6-96231b3b80d8
2009-01-08 23:45:30 +03:00
|
|
|
Diag(prevIvar->getLocation(), diag::note_previous_declaration);
|
2008-12-16 04:08:35 +03:00
|
|
|
}
|
2008-12-18 01:21:44 +03:00
|
|
|
}
|
2008-12-16 04:08:35 +03:00
|
|
|
}
|
2008-12-13 23:28:25 +03:00
|
|
|
}
|
2008-02-06 01:40:55 +03:00
|
|
|
else if (ObjCImplementationDecl *IMPDecl =
|
|
|
|
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
|
2008-01-07 22:49:32 +03:00
|
|
|
assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl");
|
2009-02-21 00:35:13 +03:00
|
|
|
IMPDecl->setIVarList(ClsFields, RecFields.size(), Context);
|
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.
|
2009-01-12 21:45:55 +03:00
|
|
|
S = getNonFieldDeclScope(S);
|
2007-08-26 10:24:45 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// Verify that there isn't already something declared with this name in this
|
|
|
|
// scope.
|
2009-02-04 20:27:36 +03:00
|
|
|
NamedDecl *PrevDecl = LookupName(S, Id, LookupOrdinaryName);
|
2008-12-08 21:40:42 +03:00
|
|
|
if (PrevDecl && PrevDecl->isTemplateParameter()) {
|
2008-12-05 21:15:24 +03:00
|
|
|
// Maybe we will complain about the shadowed template parameter.
|
|
|
|
DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
|
|
|
|
// Just pretend that we didn't see the previous declaration.
|
|
|
|
PrevDecl = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PrevDecl) {
|
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))
|
2008-11-19 11:23:25 +03:00
|
|
|
Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id;
|
2007-07-11 21:01:13 +04:00
|
|
|
else
|
2008-11-19 11:23:25 +03:00
|
|
|
Diag(IdLoc, diag::err_redefinition) << Id;
|
2008-11-24 02:12:31 +03:00
|
|
|
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
|
2009-02-07 04:47:29 +03:00
|
|
|
Val->Destroy(Context);
|
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;
|
2008-12-05 19:33:57 +03:00
|
|
|
if (VerifyIntegerConstantExpression(Val, &EnumVal)) {
|
2009-02-07 04:47:29 +03:00
|
|
|
Val->Destroy(Context);
|
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,
|
2009-01-20 04:17:11 +03:00
|
|
|
Val, EnumVal);
|
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);
|
2008-12-17 05:04:30 +03:00
|
|
|
|
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));
|
2009-01-05 22:45:36 +03:00
|
|
|
QualType EnumType = Context.getTypeDeclType(Enum);
|
2007-07-11 21:01:13 +04:00
|
|
|
|
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
|
|
|
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)
|
2008-11-20 09:38:18 +03:00
|
|
|
Diag(ECD->getLocation(), diag::ext_enum_value_not_int)
|
|
|
|
<< 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
|
|
|
}
|
|
|
|
|
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);
|
2008-12-12 05:00:36 +03:00
|
|
|
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
// C++ [dcl.enum]p4: Following the closing brace of an
|
|
|
|
// enum-specifier, each enumerator has the type of its
|
|
|
|
// enumeration.
|
|
|
|
ECD->setType(EnumType);
|
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!
|
2008-12-12 05:00:36 +03:00
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
// C++ [dcl.enum]p4: Following the closing brace of an
|
|
|
|
// enum-specifier, each enumerator has the type of its
|
|
|
|
// enumeration.
|
|
|
|
ECD->setType(EnumType);
|
2007-08-29 21:31:48 +04:00
|
|
|
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.
|
2009-01-15 22:19:42 +03:00
|
|
|
if (ECD->getInitExpr())
|
2009-02-07 04:47:29 +03:00
|
|
|
ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, ECD->getInitExpr(),
|
|
|
|
/*isLvalue=*/false));
|
2008-12-12 05:00:36 +03:00
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
// C++ [dcl.enum]p4: Following the closing brace of an
|
|
|
|
// enum-specifier, each enumerator has the type of its
|
|
|
|
// enumeration.
|
|
|
|
ECD->setType(EnumType);
|
|
|
|
else
|
|
|
|
ECD->setType(NewTy);
|
2007-08-29 21:31:48 +04:00
|
|
|
}
|
2007-08-28 10:15:15 +04:00
|
|
|
|
2008-12-11 19:49:14 +03:00
|
|
|
Enum->completeDefinition(Context, BestType);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-02-08 03:33:21 +03:00
|
|
|
Sema::DeclTy *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
|
2008-12-13 19:23:55 +03:00
|
|
|
ExprArg expr) {
|
|
|
|
StringLiteral *AsmString = cast<StringLiteral>((Expr*)expr.release());
|
|
|
|
|
2009-01-20 04:17:11 +03:00
|
|
|
return FileScopeAsmDecl::Create(Context, CurContext, Loc, AsmString);
|
2008-02-08 03:33:21 +03:00
|
|
|
}
|
|
|
|
|