2007-07-11 21:01:13 +04:00
|
|
|
//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===//
|
|
|
|
//
|
|
|
|
// 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 the actions class which performs semantic analysis and
|
|
|
|
// builds an AST out of a parse stream.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Sema.h"
|
2009-04-21 21:11:58 +04:00
|
|
|
#include "clang/AST/ASTConsumer.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 09:35:13 +04:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2008-08-11 08:54:23 +04:00
|
|
|
#include "clang/AST/Expr.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2009-04-30 10:18:40 +04:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
using namespace clang;
|
|
|
|
|
2008-11-23 12:13:29 +03:00
|
|
|
/// ConvertQualTypeToStringFn - This function is used to pretty print the
|
|
|
|
/// specified QualType as a string in diagnostics.
|
2008-11-23 23:28:15 +03:00
|
|
|
static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
|
2009-02-20 02:45:49 +03:00
|
|
|
const char *Modifier, unsigned ModLen,
|
|
|
|
const char *Argument, unsigned ArgLen,
|
2009-02-20 02:53:20 +03:00
|
|
|
llvm::SmallVectorImpl<char> &Output,
|
|
|
|
void *Cookie) {
|
|
|
|
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
|
2008-11-23 12:21:17 +03:00
|
|
|
|
2008-11-23 23:28:15 +03:00
|
|
|
std::string S;
|
|
|
|
if (Kind == Diagnostic::ak_qualtype) {
|
2009-02-20 02:45:49 +03:00
|
|
|
assert(ModLen == 0 && ArgLen == 0 &&
|
|
|
|
"Invalid modifier for QualType argument");
|
|
|
|
|
2008-11-23 23:28:15 +03:00
|
|
|
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
|
2008-11-24 06:33:13 +03:00
|
|
|
|
2008-11-23 23:28:15 +03:00
|
|
|
// FIXME: Playing with std::string is really slow.
|
2009-05-30 00:38:28 +04:00
|
|
|
S = Ty.getAsString(Context.PrintingPolicy);
|
2009-02-20 02:45:49 +03:00
|
|
|
|
|
|
|
// If this is a sugared type (like a typedef, typeof, etc), then unwrap one
|
|
|
|
// level of the sugar so that the type is more obvious to the user.
|
Give Type::getDesugaredType a "for-display" mode that can apply more
heuristics to determine when it's useful to desugar a type for display
to the user. Introduce two C++-specific heuristics:
- For a qualified type (like "foo::bar"), only produce a new
desugred type if desugaring the qualified type ("bar", in this
case) produces something interesting. For example, if "foo::bar"
refers to a class named "bar", don't desugar. However, if
"foo::bar" refers to a typedef of something else, desugar to that
something else. This gives some useful desugaring such as
"foo::bar (aka 'int')".
- Don't desugar class template specialization types like
"basic_string<char>" down to their underlying "class
basic_string<char, char_traits<char>, allocator<char>>, etc.";
it's better just to leave such types alone.
Update diagnostics.html with some discussion and examples of type
preservation in C++, showing qualified names and class template
specialization types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68207 91177308-0d34-0410-b5e6-96231b3b80d8
2009-04-01 19:47:24 +04:00
|
|
|
QualType DesugaredTy = Ty->getDesugaredType(true);
|
2009-02-20 02:45:49 +03:00
|
|
|
DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() |
|
|
|
|
Ty.getCVRQualifiers());
|
2008-11-24 06:33:13 +03:00
|
|
|
|
2009-02-20 02:45:49 +03:00
|
|
|
if (Ty != DesugaredTy &&
|
|
|
|
// If the desugared type is a vector type, we don't want to expand it,
|
|
|
|
// it will turn into an attribute mess. People want their "vec4".
|
|
|
|
!isa<VectorType>(DesugaredTy) &&
|
|
|
|
|
2009-02-20 02:53:20 +03:00
|
|
|
// Don't desugar magic Objective-C types.
|
|
|
|
Ty.getUnqualifiedType() != Context.getObjCIdType() &&
|
|
|
|
Ty.getUnqualifiedType() != Context.getObjCSelType() &&
|
|
|
|
Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
|
|
|
|
Ty.getUnqualifiedType() != Context.getObjCClassType() &&
|
|
|
|
|
|
|
|
// Not va_list.
|
|
|
|
Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
|
2009-02-20 02:45:49 +03:00
|
|
|
S = "'"+S+"' (aka '";
|
2009-06-03 06:06:50 +04:00
|
|
|
S += DesugaredTy.getAsString(Context.PrintingPolicy);
|
2009-02-20 02:45:49 +03:00
|
|
|
S += "')";
|
|
|
|
Output.append(S.begin(), S.end());
|
|
|
|
return;
|
|
|
|
}
|
2008-11-24 06:33:13 +03:00
|
|
|
|
2009-02-04 20:27:36 +03:00
|
|
|
} else if (Kind == Diagnostic::ak_declarationname) {
|
2008-11-23 23:28:15 +03:00
|
|
|
|
|
|
|
DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
|
|
|
|
S = N.getAsString();
|
2008-11-24 06:33:13 +03:00
|
|
|
|
|
|
|
if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
|
|
|
|
S = '+' + S;
|
|
|
|
else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0)
|
|
|
|
S = '-' + S;
|
|
|
|
else
|
|
|
|
assert(ModLen == 0 && ArgLen == 0 &&
|
|
|
|
"Invalid modifier for DeclarationName argument");
|
2009-02-04 20:27:36 +03:00
|
|
|
} else {
|
|
|
|
assert(Kind == Diagnostic::ak_nameddecl);
|
2009-02-05 01:46:25 +03:00
|
|
|
if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
|
|
|
|
S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
|
|
|
|
else {
|
|
|
|
assert(ModLen == 0 && ArgLen == 0 &&
|
2009-02-04 20:27:36 +03:00
|
|
|
"Invalid modifier for NamedDecl* argument");
|
2009-02-05 01:46:25 +03:00
|
|
|
S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString();
|
|
|
|
}
|
2008-11-23 23:28:15 +03:00
|
|
|
}
|
2009-02-20 02:45:49 +03:00
|
|
|
|
|
|
|
Output.push_back('\'');
|
2008-11-23 12:13:29 +03:00
|
|
|
Output.append(S.begin(), S.end());
|
2009-02-20 02:45:49 +03:00
|
|
|
Output.push_back('\'');
|
2008-11-23 12:13:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
This reworks some of the Diagnostic interfaces a bit to change how diagnostics
are formed. In particular, a diagnostic with all its strings and ranges is now
packaged up and sent to DiagnosticClients as a DiagnosticInfo instead of as a
ton of random stuff. This has the benefit of simplifying the interface, making
it more extensible, and allowing us to do more checking for things like access
past the end of the various arrays passed in.
In addition to introducing DiagnosticInfo, this also substantially changes how
Diagnostic::Report works. Instead of being passed in all of the info required
to issue a diagnostic, Report now takes only the required info (a location and
ID) and returns a fresh DiagnosticInfo *by value*. The caller is then free to
stuff strings and ranges into the DiagnosticInfo with the << operator. When
the dtor runs on the DiagnosticInfo object (which should happen at the end of
the statement), the diagnostic is actually emitted with all of the accumulated
information. This is a somewhat tricky dance, but it means that the
accumulated DiagnosticInfo is allowed to keep pointers to other expression
temporaries without those pointers getting invalidated.
This is just the minimal change to get this stuff working, but this will allow
us to eliminate the zillions of variant "Diag" methods scattered throughout
(e.g.) sema. For example, instead of calling:
Diag(BuiltinLoc, diag::err_overload_no_match, typeNames,
SourceRange(BuiltinLoc, RParenLoc));
We will soon be able to just do:
Diag(BuiltinLoc, diag::err_overload_no_match)
<< typeNames << SourceRange(BuiltinLoc, RParenLoc));
This scales better to support arbitrary types being passed in (not just
strings) in a type-safe way. Go operator overloading?!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59502 91177308-0d34-0410-b5e6-96231b3b80d8
2008-11-18 10:04:44 +03:00
|
|
|
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
|
2008-08-24 02:20:38 +04:00
|
|
|
if (C.getLangOptions().CPlusPlus)
|
|
|
|
return CXXRecordDecl::Create(C, TagDecl::TK_struct,
|
|
|
|
C.getTranslationUnitDecl(),
|
2008-09-05 05:34:33 +04:00
|
|
|
SourceLocation(), &C.Idents.get(Name));
|
2008-11-19 08:08:23 +03:00
|
|
|
|
|
|
|
return RecordDecl::Create(C, TagDecl::TK_struct,
|
|
|
|
C.getTranslationUnitDecl(),
|
|
|
|
SourceLocation(), &C.Idents.get(Name));
|
2008-08-24 02:20:38 +04:00
|
|
|
}
|
|
|
|
|
2007-10-31 21:42:27 +03:00
|
|
|
void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
|
|
|
|
TUScope = S;
|
2008-12-11 19:49:14 +03:00
|
|
|
PushDeclContext(S, Context.getTranslationUnitDecl());
|
2009-04-30 06:43:43 +04:00
|
|
|
|
2009-04-30 10:18:40 +04:00
|
|
|
if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
|
|
|
|
// Install [u]int128_t for 64-bit targets.
|
|
|
|
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
|
|
|
|
SourceLocation(),
|
|
|
|
&Context.Idents.get("__int128_t"),
|
|
|
|
Context.Int128Ty), TUScope);
|
|
|
|
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
|
|
|
|
SourceLocation(),
|
|
|
|
&Context.Idents.get("__uint128_t"),
|
|
|
|
Context.UnsignedInt128Ty), TUScope);
|
|
|
|
}
|
2009-04-30 06:43:43 +04:00
|
|
|
|
|
|
|
|
2008-02-06 03:46:58 +03:00
|
|
|
if (!PP.getLangOptions().ObjC1) return;
|
|
|
|
|
2009-04-24 02:29:11 +04:00
|
|
|
if (Context.getObjCSelType().isNull()) {
|
|
|
|
// Synthesize "typedef struct objc_selector *SEL;"
|
|
|
|
RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector");
|
|
|
|
PushOnScopeChains(SelTag, TUScope);
|
2008-02-24 19:25:02 +03:00
|
|
|
|
2009-04-24 02:29:11 +04:00
|
|
|
QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag));
|
|
|
|
TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext,
|
|
|
|
SourceLocation(),
|
|
|
|
&Context.Idents.get("SEL"),
|
|
|
|
SelT);
|
|
|
|
PushOnScopeChains(SelTypedef, TUScope);
|
|
|
|
Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Context.getObjCClassType().isNull()) {
|
|
|
|
RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class");
|
|
|
|
QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag));
|
|
|
|
TypedefDecl *ClassTypedef =
|
|
|
|
TypedefDecl::Create(Context, CurContext, SourceLocation(),
|
|
|
|
&Context.Idents.get("Class"), ClassT);
|
|
|
|
PushOnScopeChains(ClassTag, TUScope);
|
|
|
|
PushOnScopeChains(ClassTypedef, TUScope);
|
|
|
|
Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
|
|
|
|
}
|
2008-06-22 00:20:39 +04:00
|
|
|
|
|
|
|
// Synthesize "@class Protocol;
|
2009-04-24 02:29:11 +04:00
|
|
|
if (Context.getObjCProtoType().isNull()) {
|
|
|
|
ObjCInterfaceDecl *ProtocolDecl =
|
|
|
|
ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
|
|
|
|
&Context.Idents.get("Protocol"),
|
|
|
|
SourceLocation(), true);
|
|
|
|
Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
|
|
|
|
PushOnScopeChains(ProtocolDecl, TUScope);
|
|
|
|
}
|
2008-08-24 02:20:38 +04:00
|
|
|
|
2009-04-24 02:29:11 +04:00
|
|
|
// Synthesize "typedef struct objc_object { Class isa; } *id;"
|
|
|
|
if (Context.getObjCIdType().isNull()) {
|
|
|
|
RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object");
|
|
|
|
|
|
|
|
QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag));
|
|
|
|
PushOnScopeChains(ObjectTag, TUScope);
|
|
|
|
TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext,
|
|
|
|
SourceLocation(),
|
|
|
|
&Context.Idents.get("id"),
|
|
|
|
ObjT);
|
|
|
|
PushOnScopeChains(IdTypedef, TUScope);
|
|
|
|
Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
|
|
|
|
}
|
2007-10-17 00:40:23 +04:00
|
|
|
}
|
2007-10-11 01:53:07 +04:00
|
|
|
|
2009-04-14 20:27:31 +04:00
|
|
|
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
|
|
|
bool CompleteTranslationUnit)
|
2009-01-22 22:21:44 +03:00
|
|
|
: LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
|
2009-04-25 01:10:55 +04:00
|
|
|
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
|
|
|
|
ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
|
2008-12-03 23:26:15 +03:00
|
|
|
CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
|
2009-04-14 20:27:31 +04:00
|
|
|
GlobalNewDeleteDeclared(false),
|
2009-05-15 01:44:34 +04:00
|
|
|
CompleteTranslationUnit(CompleteTranslationUnit),
|
|
|
|
CurrentInstantiationScope(0) {
|
2007-08-11 00:18:51 +04:00
|
|
|
|
2008-11-11 14:37:55 +03:00
|
|
|
StdNamespace = 0;
|
2007-10-11 01:53:07 +04:00
|
|
|
TUScope = 0;
|
2008-07-01 14:37:29 +04:00
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
FieldCollector.reset(new CXXFieldCollector());
|
2008-11-23 12:13:29 +03:00
|
|
|
|
|
|
|
// Tell diagnostics how to render things from the AST library.
|
2009-02-20 02:53:20 +03:00
|
|
|
PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
2008-01-16 22:17:22 +03:00
|
|
|
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
|
|
|
|
/// If there is already an implicit cast, merge into the existing one.
|
2009-01-18 09:42:49 +03:00
|
|
|
/// If isLvalue, the result of the cast is an lvalue.
|
Implement support for operator overloading using candidate operator
functions for built-in operators, e.g., the builtin
bool operator==(int const*, int const*)
can be used for the expression "x1 == x2" given:
struct X {
operator int const*();
} x1, x2;
The scheme for handling these built-in operators is relatively simple:
for each candidate required by the standard, create a special kind of
candidate function for the built-in. If overload resolution picks the
built-in operator, we perform the appropriate conversions on the
arguments and then let the normal built-in operator take care of it.
There may be some optimization opportunity left: if we can reduce the
number of built-in operator overloads we generate, overload resolution
for these cases will go faster. However, one must be careful when
doing this: GCC generates too few operator overloads in our little
test program, and fails to compile it because none of the overloads it
generates match.
Note that we only support operator overload for non-member binary
operators at the moment. The other operators will follow.
As part of this change, ImplicitCastExpr can now be an lvalue.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59148 91177308-0d34-0410-b5e6-96231b3b80d8
2008-11-12 20:17:38 +03:00
|
|
|
void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) {
|
2008-09-04 12:38:01 +04:00
|
|
|
QualType ExprTy = Context.getCanonicalType(Expr->getType());
|
|
|
|
QualType TypeTy = Context.getCanonicalType(Ty);
|
|
|
|
|
|
|
|
if (ExprTy == TypeTy)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (Expr->getType().getTypePtr()->isPointerType() &&
|
|
|
|
Ty.getTypePtr()->isPointerType()) {
|
|
|
|
QualType ExprBaseType =
|
|
|
|
cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType();
|
|
|
|
QualType BaseType =
|
|
|
|
cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType();
|
|
|
|
if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) {
|
2008-11-19 08:27:50 +03:00
|
|
|
Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast)
|
|
|
|
<< Expr->getSourceRange();
|
2008-09-04 12:38:01 +04:00
|
|
|
}
|
|
|
|
}
|
2008-01-16 22:17:22 +03:00
|
|
|
|
Implement support for operator overloading using candidate operator
functions for built-in operators, e.g., the builtin
bool operator==(int const*, int const*)
can be used for the expression "x1 == x2" given:
struct X {
operator int const*();
} x1, x2;
The scheme for handling these built-in operators is relatively simple:
for each candidate required by the standard, create a special kind of
candidate function for the built-in. If overload resolution picks the
built-in operator, we perform the appropriate conversions on the
arguments and then let the normal built-in operator take care of it.
There may be some optimization opportunity left: if we can reduce the
number of built-in operator overloads we generate, overload resolution
for these cases will go faster. However, one must be careful when
doing this: GCC generates too few operator overloads in our little
test program, and fails to compile it because none of the overloads it
generates match.
Note that we only support operator overload for non-member binary
operators at the moment. The other operators will follow.
As part of this change, ImplicitCastExpr can now be an lvalue.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59148 91177308-0d34-0410-b5e6-96231b3b80d8
2008-11-12 20:17:38 +03:00
|
|
|
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
|
2008-09-04 12:38:01 +04:00
|
|
|
ImpCast->setType(Ty);
|
Implement support for operator overloading using candidate operator
functions for built-in operators, e.g., the builtin
bool operator==(int const*, int const*)
can be used for the expression "x1 == x2" given:
struct X {
operator int const*();
} x1, x2;
The scheme for handling these built-in operators is relatively simple:
for each candidate required by the standard, create a special kind of
candidate function for the built-in. If overload resolution picks the
built-in operator, we perform the appropriate conversions on the
arguments and then let the normal built-in operator take care of it.
There may be some optimization opportunity left: if we can reduce the
number of built-in operator overloads we generate, overload resolution
for these cases will go faster. However, one must be careful when
doing this: GCC generates too few operator overloads in our little
test program, and fails to compile it because none of the overloads it
generates match.
Note that we only support operator overload for non-member binary
operators at the moment. The other operators will follow.
As part of this change, ImplicitCastExpr can now be an lvalue.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59148 91177308-0d34-0410-b5e6-96231b3b80d8
2008-11-12 20:17:38 +03:00
|
|
|
ImpCast->setLvalueCast(isLvalue);
|
|
|
|
} else
|
2009-02-07 04:47:29 +03:00
|
|
|
Expr = new (Context) ImplicitCastExpr(Ty, Expr, isLvalue);
|
2008-01-16 22:17:22 +03:00
|
|
|
}
|
|
|
|
|
2007-08-31 08:53:24 +04:00
|
|
|
void Sema::DeleteExpr(ExprTy *E) {
|
2009-01-22 03:58:24 +03:00
|
|
|
if (E) static_cast<Expr*>(E)->Destroy(Context);
|
2007-08-31 08:53:24 +04:00
|
|
|
}
|
|
|
|
void Sema::DeleteStmt(StmtTy *S) {
|
2009-01-22 03:58:24 +03:00
|
|
|
if (S) static_cast<Stmt*>(S)->Destroy(Context);
|
2007-08-31 08:53:24 +04:00
|
|
|
}
|
|
|
|
|
2008-08-23 07:19:52 +04:00
|
|
|
/// ActOnEndOfTranslationUnit - This is called at the very end of the
|
|
|
|
/// translation unit when EOF is reached and all but the top-level scope is
|
|
|
|
/// popped.
|
|
|
|
void Sema::ActOnEndOfTranslationUnit() {
|
2009-04-14 20:27:31 +04:00
|
|
|
if (!CompleteTranslationUnit)
|
|
|
|
return;
|
|
|
|
|
2009-03-11 02:43:53 +03:00
|
|
|
// C99 6.9.2p2:
|
|
|
|
// A declaration of an identifier for an 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. If a translation unit
|
|
|
|
// contains one or more tentative definitions for an identifier,
|
|
|
|
// and the translation unit contains no external definition for
|
|
|
|
// that identifier, then the behavior is exactly as if the
|
|
|
|
// translation unit contains a file scope declaration of that
|
|
|
|
// identifier, with the composite type as of the end of the
|
|
|
|
// translation unit, with an initializer equal to 0.
|
2009-04-21 21:11:58 +04:00
|
|
|
for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator
|
|
|
|
D = TentativeDefinitions.begin(),
|
|
|
|
DEnd = TentativeDefinitions.end();
|
|
|
|
D != DEnd; ++D) {
|
|
|
|
VarDecl *VD = D->second;
|
2008-08-23 07:19:52 +04:00
|
|
|
|
2009-04-21 21:11:58 +04:00
|
|
|
if (VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (const IncompleteArrayType *ArrayT
|
|
|
|
= Context.getAsIncompleteArrayType(VD->getType())) {
|
|
|
|
if (RequireCompleteType(VD->getLocation(),
|
|
|
|
ArrayT->getElementType(),
|
|
|
|
diag::err_tentative_def_incomplete_type_arr))
|
|
|
|
VD->setInvalidDecl();
|
|
|
|
else {
|
|
|
|
// Set the length of the array to 1 (C99 6.9.2p5).
|
|
|
|
Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
|
|
|
|
llvm::APInt One(Context.getTypeSize(Context.getSizeType()),
|
|
|
|
true);
|
|
|
|
QualType T
|
|
|
|
= Context.getConstantArrayType(ArrayT->getElementType(),
|
|
|
|
One, ArrayType::Normal, 0);
|
|
|
|
VD->setType(T);
|
2009-03-11 02:43:53 +03:00
|
|
|
}
|
2009-04-21 21:11:58 +04:00
|
|
|
} else if (RequireCompleteType(VD->getLocation(), VD->getType(),
|
|
|
|
diag::err_tentative_def_incomplete_type))
|
|
|
|
VD->setInvalidDecl();
|
|
|
|
|
|
|
|
// Notify the consumer that we've completed a tentative definition.
|
|
|
|
if (!VD->isInvalidDecl())
|
|
|
|
Consumer.CompleteTentativeDefinition(VD);
|
|
|
|
|
2009-03-11 02:43:53 +03:00
|
|
|
}
|
2008-08-23 07:19:52 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Helper functions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-12-05 02:50:19 +03:00
|
|
|
/// getCurFunctionDecl - If inside of a function body, this returns a pointer
|
|
|
|
/// to the function decl for the function being parsed. If we're currently
|
|
|
|
/// in a 'block', this returns the containing context.
|
|
|
|
FunctionDecl *Sema::getCurFunctionDecl() {
|
|
|
|
DeclContext *DC = CurContext;
|
|
|
|
while (isa<BlockDecl>(DC))
|
|
|
|
DC = DC->getParent();
|
|
|
|
return dyn_cast<FunctionDecl>(DC);
|
|
|
|
}
|
|
|
|
|
2008-08-11 09:35:13 +04:00
|
|
|
ObjCMethodDecl *Sema::getCurMethodDecl() {
|
2008-11-17 19:28:52 +03:00
|
|
|
DeclContext *DC = CurContext;
|
|
|
|
while (isa<BlockDecl>(DC))
|
|
|
|
DC = DC->getParent();
|
|
|
|
return dyn_cast<ObjCMethodDecl>(DC);
|
2008-08-11 09:35:13 +04:00
|
|
|
}
|
2008-12-05 02:50:19 +03:00
|
|
|
|
|
|
|
NamedDecl *Sema::getCurFunctionOrMethodDecl() {
|
|
|
|
DeclContext *DC = CurContext;
|
|
|
|
while (isa<BlockDecl>(DC))
|
|
|
|
DC = DC->getParent();
|
|
|
|
if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC))
|
2009-01-20 04:17:11 +03:00
|
|
|
return cast<NamedDecl>(DC);
|
2008-12-05 02:50:19 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-21 01:48:49 +03:00
|
|
|
Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
|
2009-06-14 11:33:30 +04:00
|
|
|
if (!this->Emit())
|
|
|
|
return;
|
2009-03-21 01:48:49 +03:00
|
|
|
|
|
|
|
// If this is not a note, and we're in a template instantiation
|
|
|
|
// that is different from the last template instantiation where
|
|
|
|
// we emitted an error, print a template instantiation
|
|
|
|
// backtrace.
|
|
|
|
if (!SemaRef.Diags.isBuiltinNote(DiagID) &&
|
|
|
|
!SemaRef.ActiveTemplateInstantiations.empty() &&
|
|
|
|
SemaRef.ActiveTemplateInstantiations.back()
|
|
|
|
!= SemaRef.LastTemplateInstantiationErrorContext) {
|
|
|
|
SemaRef.PrintInstantiationStack();
|
|
|
|
SemaRef.LastTemplateInstantiationErrorContext
|
|
|
|
= SemaRef.ActiveTemplateInstantiations.back();
|
|
|
|
}
|
|
|
|
}
|