2006-11-10 13:03:26 +08:00
|
|
|
//===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-11-10 13:03:26 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements semantic analysis for expressions.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Sema.h"
|
2006-11-10 14:20:45 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 13:35:13 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2008-04-08 12:40:51 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2008-05-30 05:12:08 +08:00
|
|
|
#include "clang/AST/ExprObjC.h"
|
2009-02-05 03:02:06 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2006-11-10 13:03:26 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2007-03-10 07:16:33 +08:00
|
|
|
#include "clang/Lex/LiteralSupport.h"
|
2007-03-14 04:29:44 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2006-11-10 13:03:26 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2008-09-04 02:15:37 +08:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
2008-10-27 07:43:26 +08:00
|
|
|
#include "clang/Parse/Designator.h"
|
2008-09-04 02:15:37 +08:00
|
|
|
#include "clang/Parse/Scope.h"
|
2006-11-10 13:03:26 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-02-19 05:56:37 +08:00
|
|
|
/// \brief Determine whether the use of this declaration is valid, and
|
|
|
|
/// emit any corresponding diagnostics.
|
|
|
|
///
|
|
|
|
/// This routine diagnoses various problems with referencing
|
|
|
|
/// declarations that can occur when using a declaration. For example,
|
|
|
|
/// it might warn if a deprecated or unavailable declaration is being
|
|
|
|
/// used, or produce an error (and return true) if a C++0x deleted
|
|
|
|
/// function is being used.
|
|
|
|
///
|
|
|
|
/// \returns true if there was an error (this declaration cannot be
|
|
|
|
/// referenced), false otherwise.
|
|
|
|
bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
|
2009-02-16 06:43:40 +08:00
|
|
|
// See if the decl is deprecated.
|
|
|
|
if (D->getAttr<DeprecatedAttr>()) {
|
2009-02-19 05:56:37 +08:00
|
|
|
// Implementing deprecated stuff requires referencing deprecated
|
|
|
|
// stuff. Don't warn if we are implementing a deprecated
|
|
|
|
// construct.
|
2009-02-17 03:35:30 +08:00
|
|
|
bool isSilenced = false;
|
|
|
|
|
|
|
|
if (NamedDecl *ND = getCurFunctionOrMethodDecl()) {
|
|
|
|
// If this reference happens *in* a deprecated function or method, don't
|
|
|
|
// warn.
|
|
|
|
isSilenced = ND->getAttr<DeprecatedAttr>();
|
|
|
|
|
|
|
|
// If this is an Objective-C method implementation, check to see if the
|
|
|
|
// method was deprecated on the declaration, not the definition.
|
|
|
|
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) {
|
|
|
|
// The semantic decl context of a ObjCMethodDecl is the
|
|
|
|
// ObjCImplementationDecl.
|
|
|
|
if (ObjCImplementationDecl *Impl
|
|
|
|
= dyn_cast<ObjCImplementationDecl>(MD->getParent())) {
|
|
|
|
|
|
|
|
MD = Impl->getClassInterface()->getMethod(MD->getSelector(),
|
|
|
|
MD->isInstanceMethod());
|
|
|
|
isSilenced |= MD && MD->getAttr<DeprecatedAttr>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isSilenced)
|
2009-02-16 06:43:40 +08:00
|
|
|
Diag(Loc, diag::warn_deprecated) << D->getDeclName();
|
|
|
|
}
|
|
|
|
|
2009-02-19 05:56:37 +08:00
|
|
|
// See if this is a deleted function.
|
2009-02-24 12:26:15 +08:00
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
2009-02-19 05:56:37 +08:00
|
|
|
if (FD->isDeleted()) {
|
|
|
|
Diag(Loc, diag::err_deleted_function_use);
|
|
|
|
Diag(D->getLocation(), diag::note_unavailable_here) << true;
|
|
|
|
return true;
|
|
|
|
}
|
2009-02-24 12:26:15 +08:00
|
|
|
}
|
2009-02-19 05:56:37 +08:00
|
|
|
|
|
|
|
// See if the decl is unavailable
|
|
|
|
if (D->getAttr<UnavailableAttr>()) {
|
2009-02-16 06:43:40 +08:00
|
|
|
Diag(Loc, diag::warn_unavailable) << D->getDeclName();
|
2009-02-19 05:56:37 +08:00
|
|
|
Diag(D->getLocation(), diag::note_unavailable_here) << 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2009-02-16 06:43:40 +08:00
|
|
|
}
|
|
|
|
|
Introduce code modification hints into the diagnostics system. When we
know how to recover from an error, we can attach a hint to the
diagnostic that states how to modify the code, which can be one of:
- Insert some new code (a text string) at a particular source
location
- Remove the code within a given range
- Replace the code within a given range with some new code (a text
string)
Right now, we use these hints to annotate diagnostic information. For
example, if one uses the '>>' in a template argument in C++98, as in
this code:
template<int I> class B { };
B<1000 >> 2> *b1;
we'll warn that the behavior will change in C++0x. The fix is to
insert parenthese, so we use code insertion annotations to illustrate
where the parentheses go:
test.cpp:10:10: warning: use of right-shift operator ('>>') in template
argument will require parentheses in C++0x
B<1000 >> 2> *b1;
^
( )
Use of these annotations is partially implemented for HTML
diagnostics, but it's not (yet) producing valid HTML, which may be
related to PR2386, so it has been #if 0'd out.
In this future, we could consider hooking this mechanism up to the
rewriter to actually try to fix these problems during compilation (or,
after a compilation whose only errors have fixes). For now, however, I
suggest that we use these code modification hints whenever we can, so
that we get better diagnostics now and will have better coverage when
we find better ways to use this information.
This also fixes PR3410 by placing the complaint about missing tokens
just after the previous token (rather than at the location of the next
token).
llvm-svn: 65570
2009-02-27 05:00:50 +08:00
|
|
|
SourceRange Sema::getExprRange(ExprTy *E) const {
|
|
|
|
Expr *Ex = (Expr *)E;
|
|
|
|
return Ex? Ex->getSourceRange() : SourceRange();
|
|
|
|
}
|
|
|
|
|
2008-07-26 05:10:04 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Standard Promotions and Conversions
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4).
|
|
|
|
void Sema::DefaultFunctionArrayConversion(Expr *&E) {
|
|
|
|
QualType Ty = E->getType();
|
|
|
|
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
|
|
|
|
|
|
|
|
if (Ty->isFunctionType())
|
|
|
|
ImpCastExprToType(E, Context.getPointerType(Ty));
|
2008-07-26 05:33:13 +08:00
|
|
|
else if (Ty->isArrayType()) {
|
|
|
|
// In C90 mode, arrays only promote to pointers if the array expression is
|
|
|
|
// an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has
|
|
|
|
// type 'array of type' is converted to an expression that has type 'pointer
|
|
|
|
// to type'...". In C99 this was changed to: C99 6.3.2.1p3: "an expression
|
|
|
|
// that has type 'array of type' ...". The relevant change is "an lvalue"
|
|
|
|
// (C90) to "an expression" (C99).
|
2008-09-11 12:25:59 +08:00
|
|
|
//
|
|
|
|
// C++ 4.2p1:
|
|
|
|
// An lvalue or rvalue of type "array of N T" or "array of unknown bound of
|
|
|
|
// T" can be converted to an rvalue of type "pointer to T".
|
|
|
|
//
|
|
|
|
if (getLangOptions().C99 || getLangOptions().CPlusPlus ||
|
|
|
|
E->isLvalue(Context) == Expr::LV_Valid)
|
2008-07-26 05:33:13 +08:00
|
|
|
ImpCastExprToType(E, Context.getArrayDecayedType(Ty));
|
|
|
|
}
|
2008-07-26 05:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// UsualUnaryConversions - Performs various conversions that are common to most
|
|
|
|
/// operators (C99 6.3). The conversions of array and function types are
|
|
|
|
/// sometimes surpressed. For example, the array->pointer conversion doesn't
|
|
|
|
/// apply if the array is an argument to the sizeof or address (&) operators.
|
|
|
|
/// In these instances, this routine should *not* be called.
|
|
|
|
Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
|
|
|
|
QualType Ty = Expr->getType();
|
|
|
|
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
|
|
|
|
|
|
|
|
if (Ty->isPromotableIntegerType()) // C99 6.3.1.1p2
|
|
|
|
ImpCastExprToType(Expr, Context.IntTy);
|
|
|
|
else
|
|
|
|
DefaultFunctionArrayConversion(Expr);
|
|
|
|
|
|
|
|
return Expr;
|
|
|
|
}
|
|
|
|
|
2008-07-26 06:25:12 +08:00
|
|
|
/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
|
|
|
|
/// do not have a prototype. Arguments that have type float are promoted to
|
|
|
|
/// double. All other argument types are converted by UsualUnaryConversions().
|
|
|
|
void Sema::DefaultArgumentPromotion(Expr *&Expr) {
|
|
|
|
QualType Ty = Expr->getType();
|
|
|
|
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
|
|
|
|
|
|
|
|
// If this is a 'float' (CVR qualified or typedef) promote to double.
|
|
|
|
if (const BuiltinType *BT = Ty->getAsBuiltinType())
|
|
|
|
if (BT->getKind() == BuiltinType::Float)
|
|
|
|
return ImpCastExprToType(Expr, Context.DoubleTy);
|
|
|
|
|
|
|
|
UsualUnaryConversions(Expr);
|
|
|
|
}
|
|
|
|
|
2009-01-17 00:48:51 +08:00
|
|
|
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
|
|
|
|
// will warn if the resulting type is not a POD type.
|
2009-02-16 06:43:40 +08:00
|
|
|
void Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
|
2009-01-17 00:48:51 +08:00
|
|
|
DefaultArgumentPromotion(Expr);
|
|
|
|
|
|
|
|
if (!Expr->getType()->isPODType()) {
|
|
|
|
Diag(Expr->getLocStart(),
|
|
|
|
diag::warn_cannot_pass_non_pod_arg_to_vararg) <<
|
|
|
|
Expr->getType() << CT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-26 05:10:04 +08:00
|
|
|
/// UsualArithmeticConversions - Performs various conversions that are common to
|
|
|
|
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
|
|
|
|
/// routine returns the first non-arithmetic type found. The client is
|
|
|
|
/// responsible for emitting appropriate error diagnostics.
|
|
|
|
/// FIXME: verify the conversion rules for "complex int" are consistent with
|
|
|
|
/// GCC.
|
|
|
|
QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
|
|
|
|
bool isCompAssign) {
|
|
|
|
if (!isCompAssign) {
|
|
|
|
UsualUnaryConversions(lhsExpr);
|
|
|
|
UsualUnaryConversions(rhsExpr);
|
|
|
|
}
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
|
2008-07-26 05:10:04 +08:00
|
|
|
// For conversion purposes, we ignore any qualifiers.
|
|
|
|
// For example, "const float" and "float" are equivalent.
|
2008-07-27 06:17:49 +08:00
|
|
|
QualType lhs =
|
|
|
|
Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType();
|
|
|
|
QualType rhs =
|
|
|
|
Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType();
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
|
|
|
|
// If both types are identical, no conversion is needed.
|
|
|
|
if (lhs == rhs)
|
|
|
|
return lhs;
|
|
|
|
|
|
|
|
// If either side is a non-arithmetic type (e.g. a pointer), we are done.
|
|
|
|
// The caller can deal with this (e.g. pointer + int).
|
|
|
|
if (!lhs->isArithmeticType() || !rhs->isArithmeticType())
|
|
|
|
return lhs;
|
|
|
|
|
|
|
|
QualType destType = UsualArithmeticConversionsType(lhs, rhs);
|
|
|
|
if (!isCompAssign) {
|
|
|
|
ImpCastExprToType(lhsExpr, destType);
|
|
|
|
ImpCastExprToType(rhsExpr, destType);
|
|
|
|
}
|
|
|
|
return destType;
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType Sema::UsualArithmeticConversionsType(QualType lhs, QualType rhs) {
|
|
|
|
// Perform the usual unary conversions. We do this early so that
|
|
|
|
// integral promotions to "int" can allow us to exit early, in the
|
|
|
|
// lhs == rhs check. Also, for conversion purposes, we ignore any
|
|
|
|
// qualifiers. For example, "const float" and "float" are
|
|
|
|
// equivalent.
|
2009-02-16 06:43:40 +08:00
|
|
|
if (lhs->isPromotableIntegerType())
|
|
|
|
lhs = Context.IntTy;
|
|
|
|
else
|
|
|
|
lhs = lhs.getUnqualifiedType();
|
|
|
|
if (rhs->isPromotableIntegerType())
|
|
|
|
rhs = Context.IntTy;
|
|
|
|
else
|
|
|
|
rhs = rhs.getUnqualifiedType();
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
|
2008-07-26 05:10:04 +08:00
|
|
|
// If both types are identical, no conversion is needed.
|
|
|
|
if (lhs == rhs)
|
|
|
|
return lhs;
|
|
|
|
|
|
|
|
// If either side is a non-arithmetic type (e.g. a pointer), we are done.
|
|
|
|
// The caller can deal with this (e.g. pointer + int).
|
|
|
|
if (!lhs->isArithmeticType() || !rhs->isArithmeticType())
|
|
|
|
return lhs;
|
|
|
|
|
|
|
|
// At this point, we have two different arithmetic types.
|
|
|
|
|
|
|
|
// Handle complex types first (C99 6.3.1.8p1).
|
|
|
|
if (lhs->isComplexType() || rhs->isComplexType()) {
|
|
|
|
// if we have an integer operand, the result is the complex type.
|
|
|
|
if (rhs->isIntegerType() || rhs->isComplexIntegerType()) {
|
|
|
|
// convert the rhs to the lhs complex type.
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
|
|
|
|
// convert the lhs to the rhs complex type.
|
|
|
|
return rhs;
|
|
|
|
}
|
|
|
|
// This handles complex/complex, complex/float, or float/complex.
|
|
|
|
// When both operands are complex, the shorter operand is converted to the
|
|
|
|
// type of the longer, and that is the type of the result. This corresponds
|
|
|
|
// to what is done when combining two real floating-point operands.
|
|
|
|
// The fun begins when size promotion occur across type domains.
|
|
|
|
// From H&S 6.3.4: When one operand is complex and the other is a real
|
|
|
|
// floating-point type, the less precise type is converted, within it's
|
|
|
|
// real or complex domain, to the precision of the other type. For example,
|
|
|
|
// when combining a "long double" with a "double _Complex", the
|
|
|
|
// "double _Complex" is promoted to "long double _Complex".
|
|
|
|
int result = Context.getFloatingTypeOrder(lhs, rhs);
|
|
|
|
|
|
|
|
if (result > 0) { // The left side is bigger, convert rhs.
|
|
|
|
rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs);
|
|
|
|
} else if (result < 0) { // The right side is bigger, convert lhs.
|
|
|
|
lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs);
|
|
|
|
}
|
|
|
|
// At this point, lhs and rhs have the same rank/size. Now, make sure the
|
|
|
|
// domains match. This is a requirement for our implementation, C99
|
|
|
|
// does not require this promotion.
|
|
|
|
if (lhs != rhs) { // Domains don't match, we have complex/float mix.
|
|
|
|
if (lhs->isRealFloatingType()) { // handle "double, _Complex double".
|
|
|
|
return rhs;
|
|
|
|
} else { // handle "_Complex double, double".
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs; // The domain/size match exactly.
|
|
|
|
}
|
|
|
|
// Now handle "real" floating types (i.e. float, double, long double).
|
|
|
|
if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) {
|
|
|
|
// if we have an integer operand, the result is the real floating type.
|
2008-12-11 07:30:05 +08:00
|
|
|
if (rhs->isIntegerType()) {
|
2008-07-26 05:10:04 +08:00
|
|
|
// convert rhs to the lhs floating point type.
|
|
|
|
return lhs;
|
|
|
|
}
|
2008-12-11 07:30:05 +08:00
|
|
|
if (rhs->isComplexIntegerType()) {
|
|
|
|
// convert rhs to the complex floating point type.
|
|
|
|
return Context.getComplexType(lhs);
|
|
|
|
}
|
|
|
|
if (lhs->isIntegerType()) {
|
2008-07-26 05:10:04 +08:00
|
|
|
// convert lhs to the rhs floating point type.
|
|
|
|
return rhs;
|
|
|
|
}
|
2008-12-11 07:30:05 +08:00
|
|
|
if (lhs->isComplexIntegerType()) {
|
|
|
|
// convert lhs to the complex floating point type.
|
|
|
|
return Context.getComplexType(rhs);
|
|
|
|
}
|
2008-07-26 05:10:04 +08:00
|
|
|
// We have two real floating types, float/complex combos were handled above.
|
|
|
|
// Convert the smaller operand to the bigger result.
|
|
|
|
int result = Context.getFloatingTypeOrder(lhs, rhs);
|
2009-02-16 06:43:40 +08:00
|
|
|
if (result > 0) // convert the rhs
|
2008-07-26 05:10:04 +08:00
|
|
|
return lhs;
|
2009-02-16 06:43:40 +08:00
|
|
|
assert(result < 0 && "illegal float comparison");
|
|
|
|
return rhs; // convert the lhs
|
2008-07-26 05:10:04 +08:00
|
|
|
}
|
|
|
|
if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) {
|
|
|
|
// Handle GCC complex int extension.
|
|
|
|
const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType();
|
|
|
|
const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType();
|
|
|
|
|
|
|
|
if (lhsComplexInt && rhsComplexInt) {
|
|
|
|
if (Context.getIntegerTypeOrder(lhsComplexInt->getElementType(),
|
2009-02-16 06:43:40 +08:00
|
|
|
rhsComplexInt->getElementType()) >= 0)
|
|
|
|
return lhs; // convert the rhs
|
2008-07-26 05:10:04 +08:00
|
|
|
return rhs;
|
|
|
|
} else if (lhsComplexInt && rhs->isIntegerType()) {
|
|
|
|
// convert the rhs to the lhs complex type.
|
|
|
|
return lhs;
|
|
|
|
} else if (rhsComplexInt && lhs->isIntegerType()) {
|
|
|
|
// convert the lhs to the rhs complex type.
|
|
|
|
return rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Finally, we have two differing integer types.
|
|
|
|
// The rules for this case are in C99 6.3.1.8
|
|
|
|
int compare = Context.getIntegerTypeOrder(lhs, rhs);
|
|
|
|
bool lhsSigned = lhs->isSignedIntegerType(),
|
|
|
|
rhsSigned = rhs->isSignedIntegerType();
|
|
|
|
QualType destType;
|
|
|
|
if (lhsSigned == rhsSigned) {
|
|
|
|
// Same signedness; use the higher-ranked type
|
|
|
|
destType = compare >= 0 ? lhs : rhs;
|
|
|
|
} else if (compare != (lhsSigned ? 1 : -1)) {
|
|
|
|
// The unsigned type has greater than or equal rank to the
|
|
|
|
// signed type, so use the unsigned type
|
|
|
|
destType = lhsSigned ? rhs : lhs;
|
|
|
|
} else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) {
|
|
|
|
// The two types are different widths; if we are here, that
|
|
|
|
// means the signed type is larger than the unsigned type, so
|
|
|
|
// use the signed type.
|
|
|
|
destType = lhsSigned ? lhs : rhs;
|
|
|
|
} else {
|
|
|
|
// The signed type is higher-ranked than the unsigned type,
|
|
|
|
// but isn't actually any bigger (like unsigned int and long
|
|
|
|
// on most 32-bit systems). Use the unsigned type corresponding
|
|
|
|
// to the signed type.
|
|
|
|
destType = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
|
|
|
|
}
|
|
|
|
return destType;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Semantic Analysis for various Expression Types
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
2007-09-16 11:34:24 +08:00
|
|
|
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
|
2006-11-10 13:03:26 +08:00
|
|
|
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
|
|
|
|
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
|
|
|
|
/// multiple tokens. However, the common case is that StringToks points to one
|
|
|
|
/// string.
|
2009-01-19 02:53:16 +08:00
|
|
|
///
|
|
|
|
Action::OwningExprResult
|
2007-09-16 11:34:24 +08:00
|
|
|
Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
|
2006-11-10 13:03:26 +08:00
|
|
|
assert(NumStringToks && "Must have at least one string!");
|
|
|
|
|
2009-01-17 02:51:42 +08:00
|
|
|
StringLiteralParser Literal(StringToks, NumStringToks, PP);
|
2007-03-14 06:37:02 +08:00
|
|
|
if (Literal.hadError)
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError();
|
2006-11-10 13:03:26 +08:00
|
|
|
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<SourceLocation, 4> StringTokLocs;
|
2006-11-10 13:03:26 +08:00
|
|
|
for (unsigned i = 0; i != NumStringToks; ++i)
|
|
|
|
StringTokLocs.push_back(StringToks[i].getLocation());
|
2008-02-11 08:02:17 +08:00
|
|
|
|
|
|
|
QualType StrTy = Context.CharTy;
|
2008-08-10 01:20:01 +08:00
|
|
|
if (Literal.AnyWide) StrTy = Context.getWCharType();
|
2008-02-11 08:02:17 +08:00
|
|
|
if (Literal.Pascal) StrTy = Context.UnsignedCharTy;
|
2008-09-12 08:47:35 +08:00
|
|
|
|
|
|
|
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
StrTy.addConst();
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2008-02-11 08:02:17 +08:00
|
|
|
// Get an array type for the string, according to C99 6.4.5. This includes
|
|
|
|
// the nul terminator character as well as the string length for pascal
|
|
|
|
// strings.
|
|
|
|
StrTy = Context.getConstantArrayType(StrTy,
|
2009-02-27 07:01:51 +08:00
|
|
|
llvm::APInt(32, Literal.GetNumStringChars()+1),
|
2008-02-11 08:02:17 +08:00
|
|
|
ArrayType::Normal, 0);
|
2009-02-18 13:49:11 +08:00
|
|
|
|
2006-11-10 13:03:26 +08:00
|
|
|
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
|
2009-02-18 14:40:38 +08:00
|
|
|
return Owned(StringLiteral::Create(Context, Literal.GetString(),
|
|
|
|
Literal.GetStringLength(),
|
|
|
|
Literal.AnyWide, StrTy,
|
|
|
|
&StringTokLocs[0],
|
|
|
|
StringTokLocs.size()));
|
2006-11-10 13:03:26 +08:00
|
|
|
}
|
|
|
|
|
2008-10-20 13:16:36 +08:00
|
|
|
/// ShouldSnapshotBlockValueReference - Return true if a reference inside of
|
|
|
|
/// CurBlock to VD should cause it to be snapshotted (as we do for auto
|
|
|
|
/// variables defined outside the block) or false if this is not needed (e.g.
|
|
|
|
/// for values inside the block or for globals).
|
|
|
|
///
|
|
|
|
/// FIXME: This will create BlockDeclRefExprs for global variables,
|
|
|
|
/// function references, etc which is suboptimal :) and breaks
|
|
|
|
/// things like "integer constant expression" tests.
|
|
|
|
static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
|
|
|
|
ValueDecl *VD) {
|
|
|
|
// If the value is defined inside the block, we couldn't snapshot it even if
|
|
|
|
// we wanted to.
|
|
|
|
if (CurBlock->TheDecl == VD->getDeclContext())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If this is an enum constant or function, it is constant, don't snapshot.
|
|
|
|
if (isa<EnumConstantDecl>(VD) || isa<FunctionDecl>(VD))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If this is a reference to an extern, static, or global variable, no need to
|
|
|
|
// snapshot it.
|
|
|
|
// FIXME: What about 'const' variables in C++?
|
|
|
|
if (const VarDecl *Var = dyn_cast<VarDecl>(VD))
|
|
|
|
return Var->hasLocalStorage();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-09-16 02:49:24 +08:00
|
|
|
/// ActOnIdentifierExpr - The parser read an identifier in expression context,
|
2006-11-20 14:49:47 +08:00
|
|
|
/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this
|
2008-03-20 07:46:26 +08:00
|
|
|
/// identifier is used in a function call context.
|
2009-01-19 02:53:16 +08:00
|
|
|
/// SS is only used for a C++ qualified-id (foo::bar) to indicate the
|
2008-11-09 01:17:31 +08:00
|
|
|
/// class or namespace that the identifier must be a member of.
|
2009-01-19 02:53:16 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
|
|
|
IdentifierInfo &II,
|
|
|
|
bool HasTrailingLParen,
|
2009-02-04 04:19:35 +08:00
|
|
|
const CXXScopeSpec *SS,
|
|
|
|
bool isAddressOfOperand) {
|
|
|
|
return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS,
|
2009-02-04 23:01:18 +08:00
|
|
|
isAddressOfOperand);
|
2008-11-18 23:03:34 +08:00
|
|
|
}
|
|
|
|
|
2009-01-06 13:10:23 +08:00
|
|
|
/// BuildDeclRefExpr - Build either a DeclRefExpr or a
|
|
|
|
/// QualifiedDeclRefExpr based on whether or not SS is a
|
|
|
|
/// nested-name-specifier.
|
2009-02-04 04:19:35 +08:00
|
|
|
DeclRefExpr *
|
|
|
|
Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
|
|
|
|
bool TypeDependent, bool ValueDependent,
|
|
|
|
const CXXScopeSpec *SS) {
|
2009-01-21 08:14:39 +08:00
|
|
|
if (SS && !SS->isEmpty())
|
|
|
|
return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
|
2009-02-19 11:04:26 +08:00
|
|
|
ValueDependent,
|
|
|
|
SS->getRange().getBegin());
|
2009-01-21 08:14:39 +08:00
|
|
|
else
|
|
|
|
return new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
|
2009-01-06 13:10:23 +08:00
|
|
|
}
|
|
|
|
|
2009-01-07 08:43:41 +08:00
|
|
|
/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or
|
|
|
|
/// variable corresponding to the anonymous union or struct whose type
|
|
|
|
/// is Record.
|
2009-01-20 09:17:11 +08:00
|
|
|
static Decl *getObjectForAnonymousRecordDecl(RecordDecl *Record) {
|
2009-01-07 08:43:41 +08:00
|
|
|
assert(Record->isAnonymousStructOrUnion() &&
|
|
|
|
"Record must be an anonymous struct or union!");
|
|
|
|
|
2009-01-20 09:17:11 +08:00
|
|
|
// FIXME: Once Decls are directly linked together, this will
|
2009-01-07 08:43:41 +08:00
|
|
|
// be an O(1) operation rather than a slow walk through DeclContext's
|
|
|
|
// vector (which itself will be eliminated). DeclGroups might make
|
|
|
|
// this even better.
|
|
|
|
DeclContext *Ctx = Record->getDeclContext();
|
|
|
|
for (DeclContext::decl_iterator D = Ctx->decls_begin(),
|
|
|
|
DEnd = Ctx->decls_end();
|
|
|
|
D != DEnd; ++D) {
|
|
|
|
if (*D == Record) {
|
|
|
|
// The object for the anonymous struct/union directly
|
|
|
|
// follows its type in the list of declarations.
|
|
|
|
++D;
|
|
|
|
assert(D != DEnd && "Missing object for anonymous record");
|
2009-01-20 09:17:11 +08:00
|
|
|
assert(!cast<NamedDecl>(*D)->getDeclName() && "Decl should be unnamed");
|
2009-01-07 08:43:41 +08:00
|
|
|
return *D;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(false && "Missing object for anonymous record");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-19 02:53:16 +08:00
|
|
|
Sema::OwningExprResult
|
2009-01-07 08:43:41 +08:00
|
|
|
Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
|
|
|
FieldDecl *Field,
|
|
|
|
Expr *BaseObjectExpr,
|
|
|
|
SourceLocation OpLoc) {
|
|
|
|
assert(Field->getDeclContext()->isRecord() &&
|
|
|
|
cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()
|
|
|
|
&& "Field must be stored inside an anonymous struct or union");
|
|
|
|
|
|
|
|
// Construct the sequence of field member references
|
|
|
|
// we'll have to perform to get to the field in the anonymous
|
|
|
|
// union/struct. The list of members is built from the field
|
|
|
|
// outward, so traverse it backwards to go from an object in
|
|
|
|
// the current context to the field we found.
|
|
|
|
llvm::SmallVector<FieldDecl *, 4> AnonFields;
|
|
|
|
AnonFields.push_back(Field);
|
|
|
|
VarDecl *BaseObject = 0;
|
|
|
|
DeclContext *Ctx = Field->getDeclContext();
|
|
|
|
do {
|
|
|
|
RecordDecl *Record = cast<RecordDecl>(Ctx);
|
2009-01-20 09:17:11 +08:00
|
|
|
Decl *AnonObject = getObjectForAnonymousRecordDecl(Record);
|
2009-01-07 08:43:41 +08:00
|
|
|
if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject))
|
|
|
|
AnonFields.push_back(AnonField);
|
|
|
|
else {
|
|
|
|
BaseObject = cast<VarDecl>(AnonObject);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Ctx = Ctx->getParent();
|
|
|
|
} while (Ctx->isRecord() &&
|
|
|
|
cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
|
|
|
|
|
|
|
|
// Build the expression that refers to the base object, from
|
|
|
|
// which we will build a sequence of member references to each
|
|
|
|
// of the anonymous union objects and, eventually, the field we
|
|
|
|
// found via name lookup.
|
|
|
|
bool BaseObjectIsPointer = false;
|
|
|
|
unsigned ExtraQuals = 0;
|
|
|
|
if (BaseObject) {
|
|
|
|
// BaseObject is an anonymous struct/union variable (and is,
|
|
|
|
// therefore, not part of another non-anonymous record).
|
2009-02-07 09:47:29 +08:00
|
|
|
if (BaseObjectExpr) BaseObjectExpr->Destroy(Context);
|
2009-01-21 08:14:39 +08:00
|
|
|
BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(),
|
2009-02-19 11:04:26 +08:00
|
|
|
SourceLocation());
|
2009-01-07 08:43:41 +08:00
|
|
|
ExtraQuals
|
|
|
|
= Context.getCanonicalType(BaseObject->getType()).getCVRQualifiers();
|
|
|
|
} else if (BaseObjectExpr) {
|
|
|
|
// The caller provided the base object expression. Determine
|
|
|
|
// whether its a pointer and whether it adds any qualifiers to the
|
|
|
|
// anonymous struct/union fields we're looking into.
|
|
|
|
QualType ObjectType = BaseObjectExpr->getType();
|
|
|
|
if (const PointerType *ObjectPtr = ObjectType->getAsPointerType()) {
|
|
|
|
BaseObjectIsPointer = true;
|
|
|
|
ObjectType = ObjectPtr->getPointeeType();
|
|
|
|
}
|
|
|
|
ExtraQuals = Context.getCanonicalType(ObjectType).getCVRQualifiers();
|
|
|
|
} else {
|
|
|
|
// We've found a member of an anonymous struct/union that is
|
|
|
|
// inside a non-anonymous struct/union, so in a well-formed
|
|
|
|
// program our base object expression is "this".
|
|
|
|
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
|
|
|
|
if (!MD->isStatic()) {
|
|
|
|
QualType AnonFieldType
|
|
|
|
= Context.getTagDeclType(
|
|
|
|
cast<RecordDecl>(AnonFields.back()->getDeclContext()));
|
|
|
|
QualType ThisType = Context.getTagDeclType(MD->getParent());
|
|
|
|
if ((Context.getCanonicalType(AnonFieldType)
|
|
|
|
== Context.getCanonicalType(ThisType)) ||
|
|
|
|
IsDerivedFrom(ThisType, AnonFieldType)) {
|
|
|
|
// Our base object expression is "this".
|
2009-01-21 08:14:39 +08:00
|
|
|
BaseObjectExpr = new (Context) CXXThisExpr(SourceLocation(),
|
2009-02-19 11:04:26 +08:00
|
|
|
MD->getThisType(Context));
|
2009-01-07 08:43:41 +08:00
|
|
|
BaseObjectIsPointer = true;
|
|
|
|
}
|
|
|
|
} else {
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
|
|
|
|
<< Field->getDeclName());
|
2009-01-07 08:43:41 +08:00
|
|
|
}
|
|
|
|
ExtraQuals = MD->getTypeQualifiers();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!BaseObjectExpr)
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use)
|
|
|
|
<< Field->getDeclName());
|
2009-01-07 08:43:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build the implicit member references to the field of the
|
|
|
|
// anonymous struct/union.
|
|
|
|
Expr *Result = BaseObjectExpr;
|
|
|
|
for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
|
|
|
|
FI = AnonFields.rbegin(), FIEnd = AnonFields.rend();
|
|
|
|
FI != FIEnd; ++FI) {
|
|
|
|
QualType MemberType = (*FI)->getType();
|
|
|
|
if (!(*FI)->isMutable()) {
|
|
|
|
unsigned combinedQualifiers
|
|
|
|
= MemberType.getCVRQualifiers() | ExtraQuals;
|
|
|
|
MemberType = MemberType.getQualifiedType(combinedQualifiers);
|
|
|
|
}
|
2009-01-21 08:14:39 +08:00
|
|
|
Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
|
|
|
|
OpLoc, MemberType);
|
2009-01-07 08:43:41 +08:00
|
|
|
BaseObjectIsPointer = false;
|
|
|
|
ExtraQuals = Context.getCanonicalType(MemberType).getCVRQualifiers();
|
|
|
|
}
|
|
|
|
|
2009-01-19 02:53:16 +08:00
|
|
|
return Owned(Result);
|
2009-01-07 08:43:41 +08:00
|
|
|
}
|
|
|
|
|
2008-11-18 23:03:34 +08:00
|
|
|
/// ActOnDeclarationNameExpr - The parser has read some kind of name
|
|
|
|
/// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine
|
|
|
|
/// performs lookup on that name and returns an expression that refers
|
|
|
|
/// to that name. This routine isn't directly called from the parser,
|
|
|
|
/// because the parser doesn't know about DeclarationName. Rather,
|
|
|
|
/// this routine is called by ActOnIdentifierExpr,
|
|
|
|
/// ActOnOperatorFunctionIdExpr, and ActOnConversionFunctionExpr,
|
|
|
|
/// which form the DeclarationName from the corresponding syntactic
|
|
|
|
/// forms.
|
|
|
|
///
|
|
|
|
/// HasTrailingLParen indicates whether this identifier is used in a
|
|
|
|
/// function call context. LookupCtx is only used for a C++
|
|
|
|
/// qualified-id (foo::bar) to indicate the class or namespace that
|
|
|
|
/// the identifier must be a member of.
|
2008-12-06 08:22:45 +08:00
|
|
|
///
|
2009-02-04 04:19:35 +08:00
|
|
|
/// isAddressOfOperand means that this expression is the direct operand
|
|
|
|
/// of an address-of operator. This matters because this is the only
|
|
|
|
/// situation where a qualified name referencing a non-static member may
|
|
|
|
/// appear outside a member function of this class.
|
2009-01-19 02:53:16 +08:00
|
|
|
Sema::OwningExprResult
|
|
|
|
Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|
|
|
DeclarationName Name, bool HasTrailingLParen,
|
2009-02-04 23:01:18 +08:00
|
|
|
const CXXScopeSpec *SS,
|
2009-02-04 04:19:35 +08:00
|
|
|
bool isAddressOfOperand) {
|
2008-03-31 08:36:02 +08:00
|
|
|
// Could be enum-constant, value decl, instance variable, etc.
|
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.
llvm-svn: 63354
2009-01-30 09:04:22 +08:00
|
|
|
if (SS && SS->isInvalid())
|
|
|
|
return ExprError();
|
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.
llvm-svn: 64504
2009-02-14 07:20:09 +08:00
|
|
|
LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName,
|
|
|
|
false, true, Loc);
|
2009-01-15 08:26:24 +08:00
|
|
|
|
2009-02-05 01:27:36 +08:00
|
|
|
NamedDecl *D = 0;
|
2009-01-19 02:53:16 +08:00
|
|
|
if (Lookup.isAmbiguous()) {
|
|
|
|
DiagnoseAmbiguousLookup(Lookup, Name, Loc,
|
|
|
|
SS && SS->isSet() ? SS->getRange()
|
|
|
|
: SourceRange());
|
|
|
|
return ExprError();
|
|
|
|
} else
|
2009-01-15 08:26:24 +08:00
|
|
|
D = Lookup.getAsDecl();
|
2008-12-06 08:22:45 +08:00
|
|
|
|
2008-03-31 08:36:02 +08:00
|
|
|
// If this reference is in an Objective-C method, then ivar lookup happens as
|
|
|
|
// well.
|
2008-11-18 23:03:34 +08:00
|
|
|
IdentifierInfo *II = Name.getAsIdentifierInfo();
|
|
|
|
if (II && getCurMethodDecl()) {
|
2008-03-31 08:36:02 +08:00
|
|
|
// There are two cases to handle here. 1) scoped lookup could have failed,
|
|
|
|
// in which case we should look for an ivar. 2) scoped lookup could have
|
2009-03-03 05:55:29 +08:00
|
|
|
// found a decl, but that decl is outside the current instance method (i.e.
|
|
|
|
// a global variable). In these two cases, we do a lookup for an ivar with
|
|
|
|
// this name, if the lookup sucedes, we replace it our current decl.
|
2009-01-20 09:17:11 +08:00
|
|
|
if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) {
|
2008-06-28 14:07:14 +08:00
|
|
|
ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
|
2009-03-03 09:21:12 +08:00
|
|
|
ObjCInterfaceDecl *ClassDeclared;
|
|
|
|
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
|
2009-02-17 01:19:12 +08:00
|
|
|
// Check if referencing a field with __attribute__((deprecated)).
|
2009-02-19 05:56:37 +08:00
|
|
|
if (DiagnoseUseOfDecl(IV, Loc))
|
|
|
|
return ExprError();
|
2009-03-03 05:55:29 +08:00
|
|
|
bool IsClsMethod = getCurMethodDecl()->isClassMethod();
|
|
|
|
// If a class method attemps to use a free standing ivar, this is
|
|
|
|
// an error.
|
|
|
|
if (IsClsMethod && D && !D->isDefinedOutsideFunctionOrMethod())
|
|
|
|
return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method)
|
|
|
|
<< IV->getDeclName());
|
|
|
|
// If a class method uses a global variable, even if an ivar with
|
|
|
|
// same name exists, use the global.
|
|
|
|
if (!IsClsMethod) {
|
2009-03-03 09:21:12 +08:00
|
|
|
if (IV->getAccessControl() == ObjCIvarDecl::Private &&
|
|
|
|
ClassDeclared != IFace)
|
|
|
|
Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName();
|
2009-03-03 05:55:29 +08:00
|
|
|
// FIXME: This should use a new expr for a direct reference, don't turn
|
|
|
|
// this into Self->ivar, just return a BareIVarExpr or something.
|
|
|
|
IdentifierInfo &II = Context.Idents.get("self");
|
|
|
|
OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false);
|
|
|
|
ObjCIvarRefExpr *MRef = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
|
|
|
|
Loc, static_cast<Expr*>(SelfExpr.release()),
|
|
|
|
true, true);
|
|
|
|
Context.setFieldDecl(IFace, IV, MRef);
|
|
|
|
return Owned(MRef);
|
|
|
|
}
|
2008-03-31 08:36:02 +08:00
|
|
|
}
|
|
|
|
}
|
2009-03-03 05:55:29 +08:00
|
|
|
else if (getCurMethodDecl()->isInstanceMethod()) {
|
|
|
|
// We should warn if a local variable hides an ivar.
|
|
|
|
ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
|
2009-03-03 09:21:12 +08:00
|
|
|
ObjCInterfaceDecl *ClassDeclared;
|
|
|
|
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
|
|
|
|
if (IV->getAccessControl() != ObjCIvarDecl::Private ||
|
|
|
|
IFace == ClassDeclared)
|
|
|
|
Diag(Loc, diag::warn_ivar_use_hidden)<<IV->getDeclName();
|
|
|
|
}
|
2009-03-03 05:55:29 +08:00
|
|
|
}
|
2008-08-11 03:10:41 +08:00
|
|
|
// Needed to implement property "super.method" notation.
|
2009-01-20 09:17:11 +08:00
|
|
|
if (D == 0 && II->isStr("super")) {
|
2008-06-03 07:03:37 +08:00
|
|
|
QualType T = Context.getPointerType(Context.getObjCInterfaceType(
|
2008-06-28 14:07:14 +08:00
|
|
|
getCurMethodDecl()->getClassInterface()));
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) ObjCSuperExpr(Loc, T));
|
2008-06-03 07:03:37 +08:00
|
|
|
}
|
2008-03-31 08:36:02 +08:00
|
|
|
}
|
2009-02-17 03:28:42 +08:00
|
|
|
|
2009-02-19 05:56:37 +08:00
|
|
|
// Determine whether this name might be a candidate for
|
|
|
|
// argument-dependent lookup.
|
|
|
|
bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
|
|
|
|
HasTrailingLParen;
|
|
|
|
|
|
|
|
if (ADL && D == 0) {
|
2009-02-17 03:28:42 +08:00
|
|
|
// We've seen something of the form
|
|
|
|
//
|
|
|
|
// identifier(
|
|
|
|
//
|
|
|
|
// and we did not find any entity by the name
|
|
|
|
// "identifier". However, this identifier is still subject to
|
|
|
|
// argument-dependent lookup, so keep track of the name.
|
|
|
|
return Owned(new (Context) UnresolvedFunctionNameExpr(Name,
|
|
|
|
Context.OverloadTy,
|
|
|
|
Loc));
|
|
|
|
}
|
|
|
|
|
2006-11-20 12:58:19 +08:00
|
|
|
if (D == 0) {
|
2007-02-13 09:51:42 +08:00
|
|
|
// Otherwise, this could be an implicitly declared function reference (legal
|
2007-01-28 16:20:04 +08:00
|
|
|
// in C90, extension in C99).
|
2008-11-18 23:03:34 +08:00
|
|
|
if (HasTrailingLParen && II &&
|
2008-03-31 08:36:02 +08:00
|
|
|
!getLangOptions().CPlusPlus) // Not in C++.
|
2008-11-18 23:03:34 +08:00
|
|
|
D = ImplicitlyDefineFunction(Loc, *II, S);
|
2007-04-03 06:35:25 +08:00
|
|
|
else {
|
2006-11-20 14:49:47 +08:00
|
|
|
// If this name wasn't predeclared and if this is not a function call,
|
|
|
|
// diagnose the problem.
|
2008-11-09 01:17:31 +08:00
|
|
|
if (SS && !SS->isEmpty())
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc, diag::err_typecheck_no_member)
|
|
|
|
<< Name << SS->getRange());
|
2008-11-18 23:03:34 +08:00
|
|
|
else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
|
|
|
|
Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc, diag::err_undeclared_use)
|
|
|
|
<< Name.getAsString());
|
2008-11-09 01:17:31 +08:00
|
|
|
else
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name);
|
2007-04-03 06:35:25 +08:00
|
|
|
}
|
2006-11-20 12:58:19 +08:00
|
|
|
}
|
2009-01-07 08:43:41 +08:00
|
|
|
|
2009-02-04 04:19:35 +08:00
|
|
|
// If this is an expression of the form &Class::member, don't build an
|
|
|
|
// implicit member ref, because we want a pointer to the member in general,
|
|
|
|
// not any specific instance's member.
|
|
|
|
if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) {
|
|
|
|
DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
|
2009-02-05 01:27:36 +08:00
|
|
|
if (D && isa<CXXRecordDecl>(DC)) {
|
2009-02-04 04:19:35 +08:00
|
|
|
QualType DType;
|
|
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
|
|
|
|
DType = FD->getType().getNonReferenceType();
|
|
|
|
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
|
|
|
|
DType = Method->getType();
|
|
|
|
} else if (isa<OverloadedFunctionDecl>(D)) {
|
|
|
|
DType = Context.OverloadTy;
|
|
|
|
}
|
|
|
|
// Could be an inner type. That's diagnosed below, so ignore it here.
|
|
|
|
if (!DType.isNull()) {
|
|
|
|
// The pointer is type- and value-dependent if it points into something
|
|
|
|
// dependent.
|
|
|
|
bool Dependent = false;
|
|
|
|
for (; DC; DC = DC->getParent()) {
|
|
|
|
// FIXME: could stop early at namespace scope.
|
|
|
|
if (DC->isRecord()) {
|
|
|
|
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
|
|
|
|
if (Context.getTypeDeclType(Record)->isDependentType()) {
|
|
|
|
Dependent = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-02-05 01:27:36 +08:00
|
|
|
return Owned(BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS));
|
2009-02-04 04:19:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-07 08:43:41 +08:00
|
|
|
// We may have found a field within an anonymous union or struct
|
|
|
|
// (C++ [class.union]).
|
|
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(D))
|
|
|
|
if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
|
|
|
|
return BuildAnonymousStructUnionMemberReference(Loc, FD);
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
|
|
|
|
if (!MD->isStatic()) {
|
|
|
|
// C++ [class.mfct.nonstatic]p2:
|
|
|
|
// [...] if name lookup (3.4.1) resolves the name in the
|
|
|
|
// id-expression to a nonstatic nontype member of class X or of
|
|
|
|
// a base class of X, the id-expression is transformed into a
|
|
|
|
// class member access expression (5.2.5) using (*this) (9.3.2)
|
|
|
|
// as the postfix-expression to the left of the '.' operator.
|
|
|
|
DeclContext *Ctx = 0;
|
|
|
|
QualType MemberType;
|
|
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
|
|
|
|
Ctx = FD->getDeclContext();
|
|
|
|
MemberType = FD->getType();
|
|
|
|
|
|
|
|
if (const ReferenceType *RefType = MemberType->getAsReferenceType())
|
|
|
|
MemberType = RefType->getPointeeType();
|
|
|
|
else if (!FD->isMutable()) {
|
|
|
|
unsigned combinedQualifiers
|
|
|
|
= MemberType.getCVRQualifiers() | MD->getTypeQualifiers();
|
|
|
|
MemberType = MemberType.getQualifiedType(combinedQualifiers);
|
|
|
|
}
|
|
|
|
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
|
|
|
|
if (!Method->isStatic()) {
|
|
|
|
Ctx = Method->getParent();
|
|
|
|
MemberType = Method->getType();
|
|
|
|
}
|
|
|
|
} else if (OverloadedFunctionDecl *Ovl
|
|
|
|
= dyn_cast<OverloadedFunctionDecl>(D)) {
|
|
|
|
for (OverloadedFunctionDecl::function_iterator
|
|
|
|
Func = Ovl->function_begin(),
|
|
|
|
FuncEnd = Ovl->function_end();
|
|
|
|
Func != FuncEnd; ++Func) {
|
|
|
|
if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(*Func))
|
|
|
|
if (!DMethod->isStatic()) {
|
|
|
|
Ctx = Ovl->getDeclContext();
|
|
|
|
MemberType = Context.OverloadTy;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-07 08:43:41 +08:00
|
|
|
|
|
|
|
if (Ctx && Ctx->isRecord()) {
|
2008-12-22 13:46:06 +08:00
|
|
|
QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx));
|
|
|
|
QualType ThisType = Context.getTagDeclType(MD->getParent());
|
|
|
|
if ((Context.getCanonicalType(CtxType)
|
|
|
|
== Context.getCanonicalType(ThisType)) ||
|
|
|
|
IsDerivedFrom(ThisType, CtxType)) {
|
|
|
|
// Build the implicit member access expression.
|
2009-01-21 08:14:39 +08:00
|
|
|
Expr *This = new (Context) CXXThisExpr(SourceLocation(),
|
2009-02-19 11:04:26 +08:00
|
|
|
MD->getThisType(Context));
|
2009-02-05 01:27:36 +08:00
|
|
|
return Owned(new (Context) MemberExpr(This, true, D,
|
2009-02-19 11:04:26 +08:00
|
|
|
SourceLocation(), MemberType));
|
2008-12-22 13:46:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
|
2008-07-01 18:37:29 +08:00
|
|
|
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
|
|
|
|
if (MD->isStatic())
|
|
|
|
// "invalid use of member 'x' in static member function"
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
|
|
|
|
<< FD->getDeclName());
|
2008-07-01 18:37:29 +08:00
|
|
|
}
|
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
// Any other ways we could have found the field in a well-formed
|
|
|
|
// program would have been turned into implicit member expressions
|
|
|
|
// above.
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use)
|
|
|
|
<< FD->getDeclName());
|
2008-07-01 18:37:29 +08:00
|
|
|
}
|
2008-12-22 13:46:06 +08:00
|
|
|
|
2007-04-04 07:13:13 +08:00
|
|
|
if (isa<TypedefDecl>(D))
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc, diag::err_unexpected_typedef) << Name);
|
2008-01-08 03:49:32 +08:00
|
|
|
if (isa<ObjCInterfaceDecl>(D))
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc, diag::err_unexpected_interface) << Name);
|
2008-04-27 21:50:30 +08:00
|
|
|
if (isa<NamespaceDecl>(D))
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError(Diag(Loc, diag::err_unexpected_namespace) << Name);
|
2007-03-24 06:27:02 +08:00
|
|
|
|
2008-09-06 06:11:13 +08:00
|
|
|
// Make the DeclRefExpr or BlockDeclRefExpr for the decl.
|
2008-10-22 00:13:35 +08:00
|
|
|
if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
|
2009-01-19 02:53:16 +08:00
|
|
|
return Owned(BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
|
|
|
|
false, false, SS));
|
2009-02-10 07:23:08 +08:00
|
|
|
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
|
|
|
|
return Owned(BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
|
|
|
|
false, false, SS));
|
2008-09-06 06:11:13 +08:00
|
|
|
ValueDecl *VD = cast<ValueDecl>(D);
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2009-02-19 05:56:37 +08:00
|
|
|
// Check whether this declaration can be used. Note that we suppress
|
|
|
|
// this check when we're going to perform argument-dependent lookup
|
|
|
|
// on this function name, because this might not be the function
|
|
|
|
// that overload resolution actually selects.
|
|
|
|
if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
|
|
|
|
return ExprError();
|
|
|
|
|
2008-12-11 07:01:14 +08:00
|
|
|
if (VarDecl *Var = dyn_cast<VarDecl>(VD)) {
|
2009-02-17 01:19:12 +08:00
|
|
|
// Warn about constructs like:
|
|
|
|
// if (void *X = foo()) { ... } else { X }.
|
|
|
|
// In the else block, the pointer is always false.
|
2008-12-11 07:01:14 +08:00
|
|
|
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
|
|
|
|
Scope *CheckS = S;
|
|
|
|
while (CheckS) {
|
|
|
|
if (CheckS->isWithinElse() &&
|
|
|
|
CheckS->getControlParent()->isDeclScope(Var)) {
|
|
|
|
if (Var->getType()->isBooleanType())
|
2009-01-19 02:53:16 +08:00
|
|
|
ExprError(Diag(Loc, diag::warn_value_always_false)
|
|
|
|
<< Var->getDeclName());
|
2008-12-11 07:01:14 +08:00
|
|
|
else
|
2009-01-19 02:53:16 +08:00
|
|
|
ExprError(Diag(Loc, diag::warn_value_always_zero)
|
|
|
|
<< Var->getDeclName());
|
2008-12-11 07:01:14 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move up one more control parent to check again.
|
|
|
|
CheckS = CheckS->getControlParent();
|
|
|
|
if (CheckS)
|
|
|
|
CheckS = CheckS->getParent();
|
|
|
|
}
|
|
|
|
}
|
2009-02-26 00:33:18 +08:00
|
|
|
} else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(VD)) {
|
|
|
|
if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) {
|
|
|
|
// C99 DR 316 says that, if a function type comes from a
|
|
|
|
// function definition (without a prototype), that type is only
|
|
|
|
// used for checking compatibility. Therefore, when referencing
|
|
|
|
// the function, we pretend that we don't have the full function
|
|
|
|
// type.
|
|
|
|
QualType T = Func->getType();
|
|
|
|
QualType NoProtoType = T;
|
2009-02-27 07:50:07 +08:00
|
|
|
if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
|
|
|
|
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
|
2009-02-26 00:33:18 +08:00
|
|
|
return Owned(BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS));
|
|
|
|
}
|
2008-12-11 07:01:14 +08:00
|
|
|
}
|
2008-09-06 06:11:13 +08:00
|
|
|
|
|
|
|
// Only create DeclRefExpr's for valid Decl's.
|
|
|
|
if (VD->isInvalidDecl())
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError();
|
|
|
|
|
2008-10-20 13:16:36 +08:00
|
|
|
// If the identifier reference is inside a block, and it refers to a value
|
|
|
|
// that is outside the block, create a BlockDeclRefExpr instead of a
|
|
|
|
// DeclRefExpr. This ensures the value is treated as a copy-in snapshot when
|
|
|
|
// the block is formed.
|
2008-09-06 06:11:13 +08:00
|
|
|
//
|
2008-10-20 13:16:36 +08:00
|
|
|
// We do not do this for things like enum constants, global variables, etc,
|
|
|
|
// as they do not get snapshotted.
|
|
|
|
//
|
|
|
|
if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
|
2009-02-20 06:01:56 +08:00
|
|
|
// Blocks that have these can't be constant.
|
|
|
|
CurBlock->hasBlockDeclRefExprs = true;
|
|
|
|
|
2008-10-10 09:28:17 +08:00
|
|
|
// The BlocksAttr indicates the variable is bound by-reference.
|
|
|
|
if (VD->getAttr<BlocksAttr>())
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) BlockDeclRefExpr(VD,
|
2009-01-21 03:53:53 +08:00
|
|
|
VD->getType().getNonReferenceType(), Loc, true));
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2008-10-10 09:28:17 +08:00
|
|
|
// Variable will be bound by-copy, make it const within the closure.
|
|
|
|
VD->getType().addConst();
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) BlockDeclRefExpr(VD,
|
2009-01-21 03:53:53 +08:00
|
|
|
VD->getType().getNonReferenceType(), Loc, false));
|
2008-10-10 09:28:17 +08:00
|
|
|
}
|
|
|
|
// If this reference is not in a block or if the referenced variable is
|
|
|
|
// within the block, create a normal DeclRefExpr.
|
2008-12-06 07:32:09 +08:00
|
|
|
|
|
|
|
bool TypeDependent = false;
|
2008-12-11 04:57:37 +08:00
|
|
|
bool ValueDependent = false;
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
// C++ [temp.dep.expr]p3:
|
|
|
|
// An id-expression is type-dependent if it contains:
|
|
|
|
// - an identifier that was declared with a dependent type,
|
|
|
|
if (VD->getType()->isDependentType())
|
|
|
|
TypeDependent = true;
|
|
|
|
// - FIXME: a template-id that is dependent,
|
|
|
|
// - a conversion-function-id that specifies a dependent type,
|
|
|
|
else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
|
|
|
|
Name.getCXXNameType()->isDependentType())
|
|
|
|
TypeDependent = true;
|
|
|
|
// - a nested-name-specifier that contains a class-name that
|
|
|
|
// names a dependent type.
|
|
|
|
else if (SS && !SS->isEmpty()) {
|
|
|
|
for (DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
|
|
|
|
DC; DC = DC->getParent()) {
|
|
|
|
// FIXME: could stop early at namespace scope.
|
2009-01-07 08:43:41 +08:00
|
|
|
if (DC->isRecord()) {
|
2008-12-11 04:57:37 +08:00
|
|
|
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
|
|
|
|
if (Context.getTypeDeclType(Record)->isDependentType()) {
|
|
|
|
TypeDependent = true;
|
|
|
|
break;
|
|
|
|
}
|
2008-12-06 07:32:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-11 04:57:37 +08:00
|
|
|
// C++ [temp.dep.constexpr]p2:
|
|
|
|
//
|
|
|
|
// An identifier is value-dependent if it is:
|
|
|
|
// - a name declared with a dependent type,
|
|
|
|
if (TypeDependent)
|
|
|
|
ValueDependent = true;
|
|
|
|
// - the name of a non-type template parameter,
|
|
|
|
else if (isa<NonTypeTemplateParmDecl>(VD))
|
|
|
|
ValueDependent = true;
|
|
|
|
// - a constant with integral or enumeration type and is
|
|
|
|
// initialized with an expression that is value-dependent
|
|
|
|
// (FIXME!).
|
|
|
|
}
|
2008-12-06 07:32:09 +08:00
|
|
|
|
2009-01-19 02:53:16 +08:00
|
|
|
return Owned(BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
|
|
|
|
TypeDependent, ValueDependent, SS));
|
2006-11-20 12:58:19 +08:00
|
|
|
}
|
2006-11-10 13:29:30 +08:00
|
|
|
|
2009-01-19 02:53:16 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
|
|
|
|
tok::TokenKind Kind) {
|
2008-08-10 09:53:14 +08:00
|
|
|
PredefinedExpr::IdentType IT;
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2006-11-10 13:29:30 +08:00
|
|
|
switch (Kind) {
|
2008-01-13 02:39:25 +08:00
|
|
|
default: assert(0 && "Unknown simple primary expr!");
|
2008-08-10 09:53:14 +08:00
|
|
|
case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
|
|
|
|
case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
|
|
|
|
case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
2008-01-13 02:39:25 +08:00
|
|
|
|
2008-01-12 16:14:25 +08:00
|
|
|
// Pre-defined identifiers are of type char[x], where x is the length of the
|
|
|
|
// string.
|
2008-01-13 03:32:28 +08:00
|
|
|
unsigned Length;
|
2008-12-05 07:50:19 +08:00
|
|
|
if (FunctionDecl *FD = getCurFunctionDecl())
|
|
|
|
Length = FD->getIdentifier()->getLength();
|
2008-12-12 13:05:20 +08:00
|
|
|
else if (ObjCMethodDecl *MD = getCurMethodDecl())
|
|
|
|
Length = MD->getSynthesizedMethodSize();
|
|
|
|
else {
|
|
|
|
Diag(Loc, diag::ext_predef_outside_function);
|
|
|
|
// __PRETTY_FUNCTION__ -> "top level", the others produce an empty string.
|
|
|
|
Length = IT == PredefinedExpr::PrettyFunction ? strlen("top level") : 0;
|
|
|
|
}
|
2009-01-19 02:53:16 +08:00
|
|
|
|
|
|
|
|
2008-01-13 03:32:28 +08:00
|
|
|
llvm::APInt LengthI(32, Length + 1);
|
2008-01-13 02:39:25 +08:00
|
|
|
QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const);
|
2008-01-13 03:32:28 +08:00
|
|
|
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2009-01-19 02:53:16 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallString<16> CharBuffer;
|
2007-04-27 04:39:23 +08:00
|
|
|
CharBuffer.resize(Tok.getLength());
|
|
|
|
const char *ThisTokBegin = &CharBuffer[0];
|
|
|
|
unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-04-27 04:39:23 +08:00
|
|
|
CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
|
|
|
|
Tok.getLocation(), PP);
|
|
|
|
if (Literal.hadError())
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError();
|
2008-03-01 16:32:21 +08:00
|
|
|
|
|
|
|
QualType type = getLangOptions().CPlusPlus ? Context.CharTy : Context.IntTy;
|
|
|
|
|
2009-01-21 06:23:13 +08:00
|
|
|
return Owned(new (Context) CharacterLiteral(Literal.getValue(),
|
|
|
|
Literal.isWide(),
|
|
|
|
type, Tok.getLocation()));
|
2007-04-27 04:39:23 +08:00
|
|
|
}
|
|
|
|
|
2009-01-19 02:53:16 +08:00
|
|
|
Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
|
|
|
|
// Fast path for a single digit (which is quite common). A single digit
|
2007-03-14 04:29:44 +08:00
|
|
|
// cannot have a trigraph, escaped newline, radix prefix, or type suffix.
|
|
|
|
if (Tok.getLength() == 1) {
|
2009-01-27 06:36:52 +08:00
|
|
|
const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok);
|
2009-01-16 15:10:29 +08:00
|
|
|
unsigned IntSize = Context.Target.getIntWidth();
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) IntegerLiteral(llvm::APInt(IntSize, Val-'0'),
|
2009-01-21 03:53:53 +08:00
|
|
|
Context.IntTy, Tok.getLocation()));
|
2007-03-14 04:29:44 +08:00
|
|
|
}
|
2009-01-14 07:19:12 +08:00
|
|
|
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallString<512> IntegerBuffer;
|
2008-10-01 04:53:45 +08:00
|
|
|
// Add padding so that NumericLiteralParser can overread by one character.
|
|
|
|
IntegerBuffer.resize(Tok.getLength()+1);
|
2007-03-06 09:09:46 +08:00
|
|
|
const char *ThisTokBegin = &IntegerBuffer[0];
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// Get the spelling of the token, which eliminates trigraphs, etc.
|
2007-03-06 09:09:46 +08:00
|
|
|
unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-03-10 07:16:33 +08:00
|
|
|
NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
|
2007-03-13 07:22:38 +08:00
|
|
|
Tok.getLocation(), PP);
|
2007-03-14 04:29:44 +08:00
|
|
|
if (Literal.hadError)
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError();
|
|
|
|
|
2007-08-26 11:42:43 +08:00
|
|
|
Expr *Res;
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-08-26 11:42:43 +08:00
|
|
|
if (Literal.isFloatingLiteral()) {
|
2007-09-23 02:29:59 +08:00
|
|
|
QualType Ty;
|
2008-07-01 02:32:54 +08:00
|
|
|
if (Literal.isFloat)
|
2007-09-23 02:29:59 +08:00
|
|
|
Ty = Context.FloatTy;
|
2008-07-01 02:32:54 +08:00
|
|
|
else if (!Literal.isLong)
|
2007-09-23 02:29:59 +08:00
|
|
|
Ty = Context.DoubleTy;
|
2008-07-01 02:32:54 +08:00
|
|
|
else
|
2008-03-08 16:52:55 +08:00
|
|
|
Ty = Context.LongDoubleTy;
|
2008-07-01 02:32:54 +08:00
|
|
|
|
|
|
|
const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty);
|
|
|
|
|
2007-11-29 08:56:49 +08:00
|
|
|
// isExact will be set by GetFloatValue().
|
|
|
|
bool isExact = false;
|
2009-01-21 06:23:13 +08:00
|
|
|
Res = new (Context) FloatingLiteral(Literal.GetFloatValue(Format, &isExact),
|
|
|
|
&isExact, Ty, Tok.getLocation());
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-08-26 11:42:43 +08:00
|
|
|
} else if (!Literal.isIntegerLiteral()) {
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError();
|
2007-08-26 11:42:43 +08:00
|
|
|
} else {
|
2008-04-02 12:24:33 +08:00
|
|
|
QualType Ty;
|
2007-05-21 09:08:44 +08:00
|
|
|
|
2007-08-30 06:00:19 +08:00
|
|
|
// long long is a C99 feature.
|
|
|
|
if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
|
2007-08-30 06:13:52 +08:00
|
|
|
Literal.isLongLong)
|
2007-08-30 06:00:19 +08:00
|
|
|
Diag(Tok.getLocation(), diag::ext_longlong);
|
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// Get the value in the widest-possible width.
|
2008-03-06 02:54:05 +08:00
|
|
|
llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(), 0);
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
if (Literal.GetIntegerValue(ResultVal)) {
|
|
|
|
// If this value didn't fit into uintmax_t, warn and force to ull.
|
|
|
|
Diag(Tok.getLocation(), diag::warn_integer_too_large);
|
2008-04-02 12:24:33 +08:00
|
|
|
Ty = Context.UnsignedLongLongTy;
|
|
|
|
assert(Context.getTypeSize(Ty) == ResultVal.getBitWidth() &&
|
2008-03-06 02:54:05 +08:00
|
|
|
"long long is not intmax_t?");
|
2007-03-06 09:09:46 +08:00
|
|
|
} else {
|
2007-05-21 09:08:44 +08:00
|
|
|
// If this value fits into a ULL, try to figure out what else it fits into
|
|
|
|
// according to the rules of C99 6.4.4.1p5.
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// Octal, Hexadecimal, and integers with a U suffix are allowed to
|
|
|
|
// be an unsigned int.
|
|
|
|
bool AllowUnsigned = Literal.isUnsigned || Literal.getRadix() != 10;
|
|
|
|
|
|
|
|
// Check from smallest to largest, picking the smallest type we can.
|
2008-05-09 13:59:00 +08:00
|
|
|
unsigned Width = 0;
|
2007-08-24 05:58:08 +08:00
|
|
|
if (!Literal.isLong && !Literal.isLongLong) {
|
|
|
|
// Are int/unsigned possibilities?
|
2008-05-09 13:59:00 +08:00
|
|
|
unsigned IntSize = Context.Target.getIntWidth();
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// Does it fit in a unsigned int?
|
|
|
|
if (ResultVal.isIntN(IntSize)) {
|
|
|
|
// Does it fit in a signed int?
|
|
|
|
if (!Literal.isUnsigned && ResultVal[IntSize-1] == 0)
|
2008-04-02 12:24:33 +08:00
|
|
|
Ty = Context.IntTy;
|
2007-05-21 09:08:44 +08:00
|
|
|
else if (AllowUnsigned)
|
2008-04-02 12:24:33 +08:00
|
|
|
Ty = Context.UnsignedIntTy;
|
2008-05-09 13:59:00 +08:00
|
|
|
Width = IntSize;
|
2007-05-21 09:08:44 +08:00
|
|
|
}
|
|
|
|
}
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// Are long/unsigned long possibilities?
|
2008-04-02 12:24:33 +08:00
|
|
|
if (Ty.isNull() && !Literal.isLongLong) {
|
2008-05-09 13:59:00 +08:00
|
|
|
unsigned LongSize = Context.Target.getLongWidth();
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// Does it fit in a unsigned long?
|
|
|
|
if (ResultVal.isIntN(LongSize)) {
|
|
|
|
// Does it fit in a signed long?
|
|
|
|
if (!Literal.isUnsigned && ResultVal[LongSize-1] == 0)
|
2008-04-02 12:24:33 +08:00
|
|
|
Ty = Context.LongTy;
|
2007-05-21 09:08:44 +08:00
|
|
|
else if (AllowUnsigned)
|
2008-04-02 12:24:33 +08:00
|
|
|
Ty = Context.UnsignedLongTy;
|
2008-05-09 13:59:00 +08:00
|
|
|
Width = LongSize;
|
2007-05-21 09:08:44 +08:00
|
|
|
}
|
2009-01-19 02:53:16 +08:00
|
|
|
}
|
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// Finally, check long long if needed.
|
2008-04-02 12:24:33 +08:00
|
|
|
if (Ty.isNull()) {
|
2008-05-09 13:59:00 +08:00
|
|
|
unsigned LongLongSize = Context.Target.getLongLongWidth();
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// Does it fit in a unsigned long long?
|
|
|
|
if (ResultVal.isIntN(LongLongSize)) {
|
|
|
|
// Does it fit in a signed long long?
|
|
|
|
if (!Literal.isUnsigned && ResultVal[LongLongSize-1] == 0)
|
2008-04-02 12:24:33 +08:00
|
|
|
Ty = Context.LongLongTy;
|
2007-05-21 09:08:44 +08:00
|
|
|
else if (AllowUnsigned)
|
2008-04-02 12:24:33 +08:00
|
|
|
Ty = Context.UnsignedLongLongTy;
|
2008-05-09 13:59:00 +08:00
|
|
|
Width = LongLongSize;
|
2007-05-21 09:08:44 +08:00
|
|
|
}
|
|
|
|
}
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-05-21 09:08:44 +08:00
|
|
|
// If we still couldn't decide a type, we probably have something that
|
|
|
|
// does not fit in a signed long long, but has no U suffix.
|
2008-04-02 12:24:33 +08:00
|
|
|
if (Ty.isNull()) {
|
2007-05-21 09:08:44 +08:00
|
|
|
Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed);
|
2008-04-02 12:24:33 +08:00
|
|
|
Ty = Context.UnsignedLongLongTy;
|
2008-05-09 13:59:00 +08:00
|
|
|
Width = Context.Target.getLongLongWidth();
|
2007-05-21 09:08:44 +08:00
|
|
|
}
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2008-05-09 13:59:00 +08:00
|
|
|
if (ResultVal.getBitWidth() != Width)
|
|
|
|
ResultVal.trunc(Width);
|
2007-03-07 09:21:37 +08:00
|
|
|
}
|
2009-01-21 06:23:13 +08:00
|
|
|
Res = new (Context) IntegerLiteral(ResultVal, Ty, Tok.getLocation());
|
2007-03-06 09:09:46 +08:00
|
|
|
}
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2007-08-26 11:42:43 +08:00
|
|
|
// If this is an imaginary literal, create the ImaginaryLiteral wrapper.
|
|
|
|
if (Literal.isImaginary)
|
2009-01-21 08:14:39 +08:00
|
|
|
Res = new (Context) ImaginaryLiteral(Res,
|
|
|
|
Context.getComplexType(Res->getType()));
|
2009-01-19 02:53:16 +08:00
|
|
|
|
|
|
|
return Owned(Res);
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2009-01-19 02:53:16 +08:00
|
|
|
Action::OwningExprResult Sema::ActOnParenExpr(SourceLocation L,
|
|
|
|
SourceLocation R, ExprArg Val) {
|
|
|
|
Expr *E = (Expr *)Val.release();
|
2008-04-02 12:24:33 +08:00
|
|
|
assert((E != 0) && "ActOnParenExpr() missing expr");
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) ParenExpr(L, R, E));
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2007-06-05 06:22:31 +08:00
|
|
|
/// The UsualUnaryConversions() function is *not* called by this routine.
|
2007-05-17 03:47:19 +08:00
|
|
|
/// See C99 6.3.2.1p[2-4] for more details.
|
2009-02-26 22:39:58 +08:00
|
|
|
bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
|
2008-11-12 01:56:53 +08:00
|
|
|
SourceLocation OpLoc,
|
|
|
|
const SourceRange &ExprRange,
|
|
|
|
bool isSizeof) {
|
2009-02-26 22:39:58 +08:00
|
|
|
if (exprType->isDependentType())
|
|
|
|
return false;
|
|
|
|
|
2007-05-15 10:32:35 +08:00
|
|
|
// C99 6.5.3.4p1:
|
2009-01-25 03:46:37 +08:00
|
|
|
if (isa<FunctionType>(exprType)) {
|
2007-05-15 10:32:35 +08:00
|
|
|
// alignof(function) is allowed.
|
2009-01-25 03:46:37 +08:00
|
|
|
if (isSizeof)
|
|
|
|
Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exprType->isVoidType()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(OpLoc, diag::ext_sizeof_void_type)
|
|
|
|
<< (isSizeof ? "sizeof" : "__alignof") << ExprRange;
|
2009-01-25 03:46:37 +08:00
|
|
|
return false;
|
|
|
|
}
|
2008-11-12 01:56:53 +08:00
|
|
|
|
2009-01-25 03:46:37 +08:00
|
|
|
return DiagnoseIncompleteType(OpLoc, exprType,
|
|
|
|
isSizeof ? diag::err_sizeof_incomplete_type :
|
|
|
|
diag::err_alignof_incomplete_type,
|
|
|
|
ExprRange);
|
2007-05-15 10:32:35 +08:00
|
|
|
}
|
|
|
|
|
2009-01-25 04:17:12 +08:00
|
|
|
bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
|
|
|
|
const SourceRange &ExprRange) {
|
|
|
|
E = E->IgnoreParens();
|
2009-02-26 22:39:58 +08:00
|
|
|
|
2009-01-25 04:17:12 +08:00
|
|
|
// alignof decl is always ok.
|
|
|
|
if (isa<DeclRefExpr>(E))
|
|
|
|
return false;
|
2009-02-26 22:39:58 +08:00
|
|
|
|
|
|
|
// Cannot know anything else if the expression is dependent.
|
|
|
|
if (E->isTypeDependent())
|
|
|
|
return false;
|
|
|
|
|
2009-01-25 04:17:12 +08:00
|
|
|
if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
|
|
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
|
|
|
|
if (FD->isBitField()) {
|
2009-01-25 05:29:22 +08:00
|
|
|
Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange;
|
2009-01-25 04:17:12 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// Other fields are ok.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
|
|
|
|
}
|
|
|
|
|
2008-11-12 01:56:53 +08:00
|
|
|
/// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and
|
|
|
|
/// the same for @c alignof and @c __alignof
|
|
|
|
/// Note that the ArgRange is invalid if isType is false.
|
2009-01-19 08:08:26 +08:00
|
|
|
Action::OwningExprResult
|
2008-11-12 01:56:53 +08:00
|
|
|
Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
|
|
|
|
void *TyOrEx, const SourceRange &ArgRange) {
|
2006-11-20 12:34:45 +08:00
|
|
|
// If error parsing type, ignore.
|
2009-01-19 08:08:26 +08:00
|
|
|
if (TyOrEx == 0) return ExprError();
|
2007-05-15 10:32:35 +08:00
|
|
|
|
2008-11-12 01:56:53 +08:00
|
|
|
QualType ArgTy;
|
|
|
|
SourceRange Range;
|
|
|
|
if (isType) {
|
|
|
|
ArgTy = QualType::getFromOpaquePtr(TyOrEx);
|
|
|
|
Range = ArgRange;
|
2009-01-25 03:49:13 +08:00
|
|
|
|
|
|
|
// Verify that the operand is valid.
|
|
|
|
if (CheckSizeOfAlignOfOperand(ArgTy, OpLoc, Range, isSizeof))
|
|
|
|
return ExprError();
|
2008-11-12 01:56:53 +08:00
|
|
|
} else {
|
|
|
|
// Get the end location.
|
|
|
|
Expr *ArgEx = (Expr *)TyOrEx;
|
|
|
|
Range = ArgEx->getSourceRange();
|
|
|
|
ArgTy = ArgEx->getType();
|
2009-01-25 03:49:13 +08:00
|
|
|
|
|
|
|
// Verify that the operand is valid.
|
2009-01-25 04:17:12 +08:00
|
|
|
bool isInvalid;
|
2009-01-25 05:29:22 +08:00
|
|
|
if (!isSizeof) {
|
2009-01-25 04:17:12 +08:00
|
|
|
isInvalid = CheckAlignOfExpr(ArgEx, OpLoc, Range);
|
2009-01-25 05:29:22 +08:00
|
|
|
} else if (ArgEx->isBitField()) { // C99 6.5.3.4p1.
|
|
|
|
Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = CheckSizeOfAlignOfOperand(ArgTy, OpLoc, Range, true);
|
|
|
|
}
|
2009-01-25 04:17:12 +08:00
|
|
|
|
|
|
|
if (isInvalid) {
|
2009-01-25 03:49:13 +08:00
|
|
|
DeleteExpr(ArgEx);
|
|
|
|
return ExprError();
|
|
|
|
}
|
2008-11-12 01:56:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) SizeOfAlignOfExpr(isSizeof, isType, TyOrEx,
|
2009-01-25 03:46:37 +08:00
|
|
|
Context.getSizeType(), OpLoc,
|
|
|
|
Range.getEnd()));
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2009-02-17 16:12:06 +08:00
|
|
|
QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
|
2009-02-26 22:39:58 +08:00
|
|
|
if (V->isTypeDependent())
|
|
|
|
return Context.DependentTy;
|
|
|
|
|
2007-08-25 05:16:53 +08:00
|
|
|
DefaultFunctionArrayConversion(V);
|
|
|
|
|
2007-08-26 13:39:26 +08:00
|
|
|
// These operators return the element type of a complex type.
|
2007-08-25 05:16:53 +08:00
|
|
|
if (const ComplexType *CT = V->getType()->getAsComplexType())
|
|
|
|
return CT->getElementType();
|
2007-08-26 13:39:26 +08:00
|
|
|
|
|
|
|
// Otherwise they pass through real integer and floating point types here.
|
|
|
|
if (V->getType()->isArithmeticType())
|
|
|
|
return V->getType();
|
|
|
|
|
|
|
|
// Reject anything else.
|
2009-02-17 16:12:06 +08:00
|
|
|
Diag(Loc, diag::err_realimag_invalid_type) << V->getType()
|
|
|
|
<< (isReal ? "__real" : "__imag");
|
2007-08-26 13:39:26 +08:00
|
|
|
return QualType();
|
2007-08-25 05:16:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-10 13:29:30 +08:00
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
|
|
|
tok::TokenKind Kind, ExprArg Input) {
|
|
|
|
Expr *Arg = (Expr *)Input.get();
|
2008-11-19 23:42:04 +08:00
|
|
|
|
2006-11-10 13:29:30 +08:00
|
|
|
UnaryOperator::Opcode Opc;
|
|
|
|
switch (Kind) {
|
|
|
|
default: assert(0 && "Unknown unary op!");
|
|
|
|
case tok::plusplus: Opc = UnaryOperator::PostInc; break;
|
|
|
|
case tok::minusminus: Opc = UnaryOperator::PostDec; break;
|
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-11-19 23:42:04 +08:00
|
|
|
if (getLangOptions().CPlusPlus &&
|
|
|
|
(Arg->getType()->isRecordType() || Arg->getType()->isEnumeralType())) {
|
|
|
|
// Which overloaded operator?
|
2009-01-19 08:08:26 +08:00
|
|
|
OverloadedOperatorKind OverOp =
|
2008-11-19 23:42:04 +08:00
|
|
|
(Opc == UnaryOperator::PostInc)? OO_PlusPlus : OO_MinusMinus;
|
|
|
|
|
|
|
|
// C++ [over.inc]p1:
|
|
|
|
//
|
|
|
|
// [...] If the function is a member function with one
|
|
|
|
// parameter (which shall be of type int) or a non-member
|
|
|
|
// function with two parameters (the second of which shall be
|
|
|
|
// of type int), it defines the postfix increment operator ++
|
|
|
|
// for objects of that type. When the postfix increment is
|
|
|
|
// called as a result of using the ++ operator, the int
|
|
|
|
// argument will have value zero.
|
|
|
|
Expr *Args[2] = {
|
|
|
|
Arg,
|
2009-01-21 08:14:39 +08:00
|
|
|
new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,
|
|
|
|
/*isSigned=*/true), Context.IntTy, SourceLocation())
|
2008-11-19 23:42:04 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Build the candidate set for overloading
|
|
|
|
OverloadCandidateSet CandidateSet;
|
2009-02-05 00:44:47 +08:00
|
|
|
if (AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet))
|
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
|
|
|
|
// Perform overload resolution.
|
|
|
|
OverloadCandidateSet::iterator Best;
|
|
|
|
switch (BestViableFunction(CandidateSet, Best)) {
|
|
|
|
case OR_Success: {
|
|
|
|
// We found a built-in operator or an overloaded operator.
|
|
|
|
FunctionDecl *FnDecl = Best->Function;
|
|
|
|
|
|
|
|
if (FnDecl) {
|
|
|
|
// We matched an overloaded operator. Build a call to that
|
|
|
|
// operator.
|
|
|
|
|
|
|
|
// Convert the arguments.
|
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
|
|
|
|
if (PerformObjectArgumentInitialization(Arg, Method))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
} else {
|
|
|
|
// Convert the arguments.
|
2009-01-19 08:08:26 +08:00
|
|
|
if (PerformCopyInitialization(Arg,
|
2008-11-19 23:42:04 +08:00
|
|
|
FnDecl->getParamDecl(0)->getType(),
|
|
|
|
"passing"))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the result type
|
2009-01-19 08:08:26 +08:00
|
|
|
QualType ResultTy
|
2008-11-19 23:42:04 +08:00
|
|
|
= FnDecl->getType()->getAsFunctionType()->getResultType();
|
|
|
|
ResultTy = ResultTy.getNonReferenceType();
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-11-19 23:42:04 +08:00
|
|
|
// Build the actual expression node.
|
2009-01-21 08:14:39 +08:00
|
|
|
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
|
2009-02-19 10:54:59 +08:00
|
|
|
SourceLocation());
|
2008-11-19 23:42:04 +08:00
|
|
|
UsualUnaryConversions(FnExpr);
|
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
Input.release();
|
2009-02-10 04:51:47 +08:00
|
|
|
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
|
|
|
|
ResultTy, OpLoc));
|
2008-11-19 23:42:04 +08:00
|
|
|
} else {
|
|
|
|
// We matched a built-in operator. Convert the arguments, then
|
|
|
|
// break out so that we will build the appropriate built-in
|
|
|
|
// operator node.
|
|
|
|
if (PerformCopyInitialization(Arg, Best->BuiltinTypes.ParamTypes[0],
|
|
|
|
"passing"))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
|
|
|
|
break;
|
2009-01-19 08:08:26 +08:00
|
|
|
}
|
2008-11-19 23:42:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case OR_No_Viable_Function:
|
|
|
|
// No viable function; fall through to handling this as a
|
|
|
|
// built-in operator, which will produce an error message for us.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OR_Ambiguous:
|
|
|
|
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
|
|
|
|
<< UnaryOperator::getOpcodeStr(Opc)
|
|
|
|
<< Arg->getSourceRange();
|
|
|
|
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2009-02-19 05:56:37 +08:00
|
|
|
|
|
|
|
case OR_Deleted:
|
|
|
|
Diag(OpLoc, diag::err_ovl_deleted_oper)
|
|
|
|
<< Best->Function->isDeleted()
|
|
|
|
<< UnaryOperator::getOpcodeStr(Opc)
|
|
|
|
<< Arg->getSourceRange();
|
|
|
|
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Either we found no viable overloaded operator or we matched a
|
|
|
|
// built-in operator. In either case, fall through to trying to
|
|
|
|
// build a built-in operation.
|
|
|
|
}
|
|
|
|
|
2008-12-20 17:35:34 +08:00
|
|
|
QualType result = CheckIncrementDecrementOperand(Arg, OpLoc,
|
|
|
|
Opc == UnaryOperator::PostInc);
|
2007-05-07 08:24:15 +08:00
|
|
|
if (result.isNull())
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
|
|
|
Input.release();
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) UnaryOperator(Arg, Opc, result, OpLoc));
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
|
|
|
|
ExprArg Idx, SourceLocation RLoc) {
|
|
|
|
Expr *LHSExp = static_cast<Expr*>(Base.get()),
|
|
|
|
*RHSExp = static_cast<Expr*>(Idx.get());
|
2007-07-16 08:14:47 +08:00
|
|
|
|
2008-11-20 01:17:41 +08:00
|
|
|
if (getLangOptions().CPlusPlus &&
|
2009-01-19 08:08:26 +08:00
|
|
|
(LHSExp->getType()->isRecordType() ||
|
2008-12-16 06:34:21 +08:00
|
|
|
LHSExp->getType()->isEnumeralType() ||
|
|
|
|
RHSExp->getType()->isRecordType() ||
|
|
|
|
RHSExp->getType()->isEnumeralType())) {
|
2008-11-20 01:17:41 +08:00
|
|
|
// Add the appropriate overloaded operators (C++ [over.match.oper])
|
|
|
|
// to the candidate set.
|
|
|
|
OverloadCandidateSet CandidateSet;
|
|
|
|
Expr *Args[2] = { LHSExp, RHSExp };
|
2009-02-05 00:44:47 +08:00
|
|
|
if (AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
|
|
|
|
SourceRange(LLoc, RLoc)))
|
|
|
|
return ExprError();
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-11-20 01:17:41 +08:00
|
|
|
// Perform overload resolution.
|
|
|
|
OverloadCandidateSet::iterator Best;
|
|
|
|
switch (BestViableFunction(CandidateSet, Best)) {
|
|
|
|
case OR_Success: {
|
|
|
|
// We found a built-in operator or an overloaded operator.
|
|
|
|
FunctionDecl *FnDecl = Best->Function;
|
|
|
|
|
|
|
|
if (FnDecl) {
|
|
|
|
// We matched an overloaded operator. Build a call to that
|
|
|
|
// operator.
|
|
|
|
|
|
|
|
// Convert the arguments.
|
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
|
|
|
|
if (PerformObjectArgumentInitialization(LHSExp, Method) ||
|
|
|
|
PerformCopyInitialization(RHSExp,
|
|
|
|
FnDecl->getParamDecl(0)->getType(),
|
|
|
|
"passing"))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-20 01:17:41 +08:00
|
|
|
} else {
|
|
|
|
// Convert the arguments.
|
|
|
|
if (PerformCopyInitialization(LHSExp,
|
|
|
|
FnDecl->getParamDecl(0)->getType(),
|
|
|
|
"passing") ||
|
|
|
|
PerformCopyInitialization(RHSExp,
|
|
|
|
FnDecl->getParamDecl(1)->getType(),
|
|
|
|
"passing"))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-20 01:17:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the result type
|
2009-01-19 08:08:26 +08:00
|
|
|
QualType ResultTy
|
2008-11-20 01:17:41 +08:00
|
|
|
= FnDecl->getType()->getAsFunctionType()->getResultType();
|
|
|
|
ResultTy = ResultTy.getNonReferenceType();
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-11-20 01:17:41 +08:00
|
|
|
// Build the actual expression node.
|
2009-02-19 11:04:26 +08:00
|
|
|
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
|
|
|
|
SourceLocation());
|
2008-11-20 01:17:41 +08:00
|
|
|
UsualUnaryConversions(FnExpr);
|
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
Base.release();
|
|
|
|
Idx.release();
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
|
2009-01-21 08:14:39 +08:00
|
|
|
ResultTy, LLoc));
|
2008-11-20 01:17:41 +08:00
|
|
|
} else {
|
|
|
|
// We matched a built-in operator. Convert the arguments, then
|
|
|
|
// break out so that we will build the appropriate built-in
|
|
|
|
// operator node.
|
|
|
|
if (PerformCopyInitialization(LHSExp, Best->BuiltinTypes.ParamTypes[0],
|
|
|
|
"passing") ||
|
|
|
|
PerformCopyInitialization(RHSExp, Best->BuiltinTypes.ParamTypes[1],
|
|
|
|
"passing"))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-20 01:17:41 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case OR_No_Viable_Function:
|
|
|
|
// No viable function; fall through to handling this as a
|
|
|
|
// built-in operator, which will produce an error message for us.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OR_Ambiguous:
|
|
|
|
Diag(LLoc, diag::err_ovl_ambiguous_oper)
|
|
|
|
<< "[]"
|
|
|
|
<< LHSExp->getSourceRange() << RHSExp->getSourceRange();
|
|
|
|
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2009-02-19 05:56:37 +08:00
|
|
|
|
|
|
|
case OR_Deleted:
|
|
|
|
Diag(LLoc, diag::err_ovl_deleted_oper)
|
|
|
|
<< Best->Function->isDeleted()
|
|
|
|
<< "[]"
|
|
|
|
<< LHSExp->getSourceRange() << RHSExp->getSourceRange();
|
|
|
|
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
|
|
|
return ExprError();
|
2008-11-20 01:17:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Either we found no viable overloaded operator or we matched a
|
|
|
|
// built-in operator. In either case, fall through to trying to
|
|
|
|
// build a built-in operation.
|
|
|
|
}
|
|
|
|
|
2007-07-16 08:14:47 +08:00
|
|
|
// Perform default conversions.
|
|
|
|
DefaultFunctionArrayConversion(LHSExp);
|
|
|
|
DefaultFunctionArrayConversion(RHSExp);
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2007-07-16 08:14:47 +08:00
|
|
|
QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
|
2007-03-24 06:27:02 +08:00
|
|
|
|
2007-03-29 05:49:40 +08:00
|
|
|
// C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent
|
2007-08-31 01:45:32 +08:00
|
|
|
// to the expression *((e1)+(e2)). This means the array "Base" may actually be
|
2009-02-19 11:04:26 +08:00
|
|
|
// in the subscript position. As a result, we need to derive the array base
|
2007-03-24 06:27:02 +08:00
|
|
|
// and index from the expression types.
|
2007-07-16 08:14:47 +08:00
|
|
|
Expr *BaseExpr, *IndexExpr;
|
|
|
|
QualType ResultType;
|
2009-02-26 22:39:58 +08:00
|
|
|
if (LHSTy->isDependentType() || RHSTy->isDependentType()) {
|
|
|
|
BaseExpr = LHSExp;
|
|
|
|
IndexExpr = RHSExp;
|
|
|
|
ResultType = Context.DependentTy;
|
|
|
|
} else if (const PointerType *PTy = LHSTy->getAsPointerType()) {
|
2007-07-16 08:14:47 +08:00
|
|
|
BaseExpr = LHSExp;
|
|
|
|
IndexExpr = RHSExp;
|
|
|
|
// FIXME: need to deal with const...
|
|
|
|
ResultType = PTy->getPointeeType();
|
2007-08-01 00:53:04 +08:00
|
|
|
} else if (const PointerType *PTy = RHSTy->getAsPointerType()) {
|
2007-07-16 08:23:25 +08:00
|
|
|
// Handle the uncommon case of "123[Ptr]".
|
2007-07-16 08:14:47 +08:00
|
|
|
BaseExpr = RHSExp;
|
|
|
|
IndexExpr = LHSExp;
|
|
|
|
// FIXME: need to deal with const...
|
|
|
|
ResultType = PTy->getPointeeType();
|
2007-08-01 03:29:30 +08:00
|
|
|
} else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
|
|
|
|
BaseExpr = LHSExp; // vectors: V[123]
|
2007-07-16 08:14:47 +08:00
|
|
|
IndexExpr = RHSExp;
|
2009-01-18 08:45:31 +08:00
|
|
|
|
2007-07-16 08:14:47 +08:00
|
|
|
// FIXME: need to deal with const...
|
|
|
|
ResultType = VTy->getElementType();
|
2007-06-09 11:47:53 +08:00
|
|
|
} else {
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(LHSExp->getLocStart(),
|
|
|
|
diag::err_typecheck_subscript_value) << RHSExp->getSourceRange());
|
|
|
|
}
|
2007-03-29 05:49:40 +08:00
|
|
|
// C99 6.5.2.1p1
|
2009-02-26 22:39:58 +08:00
|
|
|
if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent())
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(IndexExpr->getLocStart(),
|
|
|
|
diag::err_typecheck_subscript) << IndexExpr->getSourceRange());
|
2007-07-16 08:14:47 +08:00
|
|
|
|
|
|
|
// C99 6.5.2.1p1: "shall have type "pointer to *object* type". In practice,
|
|
|
|
// the following check catches trying to index a pointer to a function (e.g.
|
2008-04-02 14:59:01 +08:00
|
|
|
// void (*)(int)) and pointers to incomplete types. Functions are not
|
|
|
|
// objects in C99.
|
2009-02-26 22:39:58 +08:00
|
|
|
if (!ResultType->isObjectType() && !ResultType->isDependentType())
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(BaseExpr->getLocStart(),
|
2008-11-19 13:08:23 +08:00
|
|
|
diag::err_typecheck_subscript_not_object)
|
2009-01-19 08:08:26 +08:00
|
|
|
<< BaseExpr->getType() << BaseExpr->getSourceRange());
|
2007-07-11 02:23:31 +08:00
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
Base.release();
|
|
|
|
Idx.release();
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
|
2009-01-21 08:14:39 +08:00
|
|
|
ResultType, RLoc));
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2007-07-28 06:15:19 +08:00
|
|
|
QualType Sema::
|
2008-04-19 07:10:10 +08:00
|
|
|
CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
|
2007-07-28 06:15:19 +08:00
|
|
|
IdentifierInfo &CompName, SourceLocation CompLoc) {
|
2008-04-19 07:10:10 +08:00
|
|
|
const ExtVectorType *vecType = baseType->getAsExtVectorType();
|
2008-05-09 14:41:27 +08:00
|
|
|
|
2007-07-28 06:15:19 +08:00
|
|
|
// The vector accessor can't exceed the number of elements.
|
|
|
|
const char *compStr = CompName.getName();
|
2009-01-18 09:47:54 +08:00
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
// This flag determines whether or not the component is one of the four
|
2009-01-18 09:47:54 +08:00
|
|
|
// special names that indicate a subset of exactly half the elements are
|
|
|
|
// to be selected.
|
|
|
|
bool HalvingSwizzle = false;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-01-18 09:47:54 +08:00
|
|
|
// This flag determines whether or not CompName has an 's' char prefix,
|
|
|
|
// indicating that it is a string of hex values to be used as vector indices.
|
|
|
|
bool HexSwizzle = *compStr == 's';
|
2008-05-09 14:41:27 +08:00
|
|
|
|
|
|
|
// Check that we've found one of the special components, or that the component
|
|
|
|
// names must come from the same set.
|
2009-02-19 11:04:26 +08:00
|
|
|
if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
|
2009-01-18 09:47:54 +08:00
|
|
|
!strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
|
|
|
|
HalvingSwizzle = true;
|
2008-05-09 14:41:27 +08:00
|
|
|
} else if (vecType->getPointAccessorIdx(*compStr) != -1) {
|
2007-08-03 06:33:49 +08:00
|
|
|
do
|
|
|
|
compStr++;
|
|
|
|
while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1);
|
2009-01-18 09:47:54 +08:00
|
|
|
} else if (HexSwizzle || vecType->getNumericAccessorIdx(*compStr) != -1) {
|
2007-08-03 06:33:49 +08:00
|
|
|
do
|
|
|
|
compStr++;
|
2009-01-18 09:47:54 +08:00
|
|
|
while (*compStr && vecType->getNumericAccessorIdx(*compStr) != -1);
|
2007-08-03 06:33:49 +08:00
|
|
|
}
|
2009-01-18 09:47:54 +08:00
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
if (!HalvingSwizzle && *compStr) {
|
2007-07-28 06:15:19 +08:00
|
|
|
// We didn't get to the end of the string. This means the component names
|
|
|
|
// didn't come from the same set *or* we encountered an illegal name.
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
|
|
|
|
<< std::string(compStr,compStr+1) << SourceRange(CompLoc);
|
2007-07-28 06:15:19 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-01-18 09:47:54 +08:00
|
|
|
// Ensure no component accessor exceeds the width of the vector type it
|
|
|
|
// operates on.
|
|
|
|
if (!HalvingSwizzle) {
|
|
|
|
compStr = CompName.getName();
|
|
|
|
|
|
|
|
if (HexSwizzle)
|
2007-07-28 06:15:19 +08:00
|
|
|
compStr++;
|
2009-01-18 09:47:54 +08:00
|
|
|
|
|
|
|
while (*compStr) {
|
|
|
|
if (!vecType->isAccessorWithinNumElements(*compStr++)) {
|
|
|
|
Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
|
|
|
|
<< baseType << SourceRange(CompLoc);
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
}
|
2007-07-28 06:15:19 +08:00
|
|
|
}
|
2008-05-09 14:41:27 +08:00
|
|
|
|
2009-01-18 09:47:54 +08:00
|
|
|
// If this is a halving swizzle, verify that the base type has an even
|
|
|
|
// number of elements.
|
|
|
|
if (HalvingSwizzle && (vecType->getNumElements() & 1U)) {
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(OpLoc, diag::err_ext_vector_component_requires_even)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< baseType << SourceRange(CompLoc);
|
2008-05-09 14:41:27 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-07-28 06:15:19 +08:00
|
|
|
// The component accessor looks fine - now we need to compute the actual type.
|
2009-02-19 11:04:26 +08:00
|
|
|
// The vector type is implied by the component accessor. For example,
|
2007-07-28 06:15:19 +08:00
|
|
|
// vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
|
2009-01-18 09:47:54 +08:00
|
|
|
// vec4.s0 is a float, vec4.s23 is a vec3, etc.
|
2008-05-09 14:41:27 +08:00
|
|
|
// vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
|
2009-01-18 09:47:54 +08:00
|
|
|
unsigned CompSize = HalvingSwizzle ? vecType->getNumElements() / 2
|
|
|
|
: CompName.getLength();
|
|
|
|
if (HexSwizzle)
|
|
|
|
CompSize--;
|
|
|
|
|
2007-07-28 06:15:19 +08:00
|
|
|
if (CompSize == 1)
|
|
|
|
return vecType->getElementType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-04-19 07:10:10 +08:00
|
|
|
QualType VT = Context.getExtVectorType(vecType->getElementType(), CompSize);
|
2009-02-19 11:04:26 +08:00
|
|
|
// Now look up the TypeDefDecl from the vector type. Without this,
|
2008-04-19 07:10:10 +08:00
|
|
|
// diagostics look bad. We want extended vector types to appear built-in.
|
|
|
|
for (unsigned i = 0, E = ExtVectorDecls.size(); i != E; ++i) {
|
|
|
|
if (ExtVectorDecls[i]->getUnderlyingType() == VT)
|
|
|
|
return Context.getTypedefType(ExtVectorDecls[i]);
|
2007-07-30 00:33:31 +08:00
|
|
|
}
|
|
|
|
return VT; // should never get here (a typedef type should always be found).
|
2007-07-28 06:15:19 +08:00
|
|
|
}
|
|
|
|
|
2009-02-16 06:43:40 +08:00
|
|
|
|
2008-11-23 04:25:50 +08:00
|
|
|
/// constructSetterName - Return the setter name for the given
|
|
|
|
/// identifier, i.e. "set" + Name where the initial character of Name
|
|
|
|
/// has been capitalized.
|
|
|
|
// FIXME: Merge with same routine in Parser. But where should this
|
|
|
|
// live?
|
|
|
|
static IdentifierInfo *constructSetterName(IdentifierTable &Idents,
|
|
|
|
const IdentifierInfo *Name) {
|
|
|
|
llvm::SmallString<100> SelectorName;
|
|
|
|
SelectorName = "set";
|
|
|
|
SelectorName.append(Name->getName(), Name->getName()+Name->getLength());
|
|
|
|
SelectorName[3] = toupper(SelectorName[3]);
|
|
|
|
return &Idents.get(&SelectorName[0], &SelectorName[SelectorName.size()]);
|
|
|
|
}
|
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|
|
|
tok::TokenKind OpKind, SourceLocation MemberLoc,
|
2009-03-05 06:30:12 +08:00
|
|
|
IdentifierInfo &Member,
|
|
|
|
DeclTy *ObjCImpDecl) {
|
2009-01-19 08:08:26 +08:00
|
|
|
Expr *BaseExpr = static_cast<Expr *>(Base.release());
|
2007-07-26 11:11:44 +08:00
|
|
|
assert(BaseExpr && "no record expression");
|
2007-12-17 05:42:28 +08:00
|
|
|
|
|
|
|
// Perform default conversions.
|
|
|
|
DefaultFunctionArrayConversion(BaseExpr);
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2007-07-26 11:11:44 +08:00
|
|
|
QualType BaseType = BaseExpr->getType();
|
|
|
|
assert(!BaseType.isNull() && "no type for member expression");
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-07-21 12:36:39 +08:00
|
|
|
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
|
|
|
|
// must have pointer type, and the accessed type is the pointee.
|
2007-03-24 06:27:02 +08:00
|
|
|
if (OpKind == tok::arrow) {
|
2007-08-01 00:53:04 +08:00
|
|
|
if (const PointerType *PT = BaseType->getAsPointerType())
|
2007-07-26 11:11:44 +08:00
|
|
|
BaseType = PT->getPointeeType();
|
2008-11-21 00:27:02 +08:00
|
|
|
else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
|
2009-01-19 08:08:26 +08:00
|
|
|
return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc,
|
|
|
|
MemberLoc, Member));
|
2007-07-26 11:11:44 +08:00
|
|
|
else
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(MemberLoc,
|
|
|
|
diag::err_typecheck_member_reference_arrow)
|
|
|
|
<< BaseType << BaseExpr->getSourceRange());
|
2007-03-24 06:27:02 +08:00
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-07-21 12:36:39 +08:00
|
|
|
// Handle field access to simple records. This also handles access to fields
|
|
|
|
// of the ObjC 'id' struct.
|
2007-08-01 03:29:30 +08:00
|
|
|
if (const RecordType *RTy = BaseType->getAsRecordType()) {
|
2007-07-26 11:11:44 +08:00
|
|
|
RecordDecl *RDecl = RTy->getDecl();
|
2009-02-19 11:04:26 +08:00
|
|
|
if (DiagnoseIncompleteType(OpLoc, BaseType,
|
2009-01-20 03:26:10 +08:00
|
|
|
diag::err_typecheck_incomplete_tag,
|
|
|
|
BaseExpr->getSourceRange()))
|
|
|
|
return ExprError();
|
|
|
|
|
2007-07-26 11:11:44 +08:00
|
|
|
// The record definition is complete, now make sure the member is valid.
|
2008-12-12 00:49:14 +08:00
|
|
|
// FIXME: Qualified name lookup for C++ is a bit more complicated
|
|
|
|
// than this.
|
2009-01-19 08:08:26 +08:00
|
|
|
LookupResult Result
|
2009-02-19 11:04:26 +08:00
|
|
|
= LookupQualifiedName(RDecl, DeclarationName(&Member),
|
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.
llvm-svn: 63354
2009-01-30 09:04:22 +08:00
|
|
|
LookupMemberName, false);
|
2009-01-15 08:26:24 +08:00
|
|
|
|
2009-02-05 01:27:36 +08:00
|
|
|
NamedDecl *MemberDecl = 0;
|
2009-01-15 08:26:24 +08:00
|
|
|
if (!Result)
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member)
|
|
|
|
<< &Member << BaseExpr->getSourceRange());
|
|
|
|
else if (Result.isAmbiguous()) {
|
|
|
|
DiagnoseAmbiguousLookup(Result, DeclarationName(&Member),
|
|
|
|
MemberLoc, BaseExpr->getSourceRange());
|
|
|
|
return ExprError();
|
|
|
|
} else
|
2009-01-15 08:26:24 +08:00
|
|
|
MemberDecl = Result;
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2009-02-14 06:08:30 +08:00
|
|
|
// If the decl being referenced had an error, return an error for this
|
|
|
|
// sub-expr without emitting another error, in order to avoid cascading
|
|
|
|
// error cases.
|
|
|
|
if (MemberDecl->isInvalidDecl())
|
|
|
|
return ExprError();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-19 05:56:37 +08:00
|
|
|
// Check the use of this field
|
|
|
|
if (DiagnoseUseOfDecl(MemberDecl, MemberLoc))
|
|
|
|
return ExprError();
|
2009-02-14 06:08:30 +08:00
|
|
|
|
2008-12-23 08:26:44 +08:00
|
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
|
2009-01-07 08:43:41 +08:00
|
|
|
// We may have found a field within an anonymous union or struct
|
|
|
|
// (C++ [class.union]).
|
|
|
|
if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
|
2009-01-19 02:53:16 +08:00
|
|
|
return BuildAnonymousStructUnionMemberReference(MemberLoc, FD,
|
2009-01-19 08:08:26 +08:00
|
|
|
BaseExpr, OpLoc);
|
2009-01-07 08:43:41 +08:00
|
|
|
|
2008-12-21 07:49:58 +08:00
|
|
|
// Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
|
|
|
|
// FIXME: Handle address space modifiers
|
2008-12-23 08:26:44 +08:00
|
|
|
QualType MemberType = FD->getType();
|
2008-12-21 07:49:58 +08:00
|
|
|
if (const ReferenceType *Ref = MemberType->getAsReferenceType())
|
|
|
|
MemberType = Ref->getPointeeType();
|
|
|
|
else {
|
|
|
|
unsigned combinedQualifiers =
|
|
|
|
MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
|
2008-12-23 08:26:44 +08:00
|
|
|
if (FD->isMutable())
|
2008-12-21 07:49:58 +08:00
|
|
|
combinedQualifiers &= ~QualType::Const;
|
|
|
|
MemberType = MemberType.getQualifiedType(combinedQualifiers);
|
|
|
|
}
|
2008-02-07 06:48:16 +08:00
|
|
|
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD,
|
|
|
|
MemberLoc, MemberType));
|
2008-12-23 08:26:44 +08:00
|
|
|
} else if (CXXClassVarDecl *Var = dyn_cast<CXXClassVarDecl>(MemberDecl))
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
|
2009-01-19 08:08:26 +08:00
|
|
|
Var, MemberLoc,
|
|
|
|
Var->getType().getNonReferenceType()));
|
2008-12-23 08:26:44 +08:00
|
|
|
else if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl))
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
|
2009-01-21 08:14:39 +08:00
|
|
|
MemberFn, MemberLoc, MemberFn->getType()));
|
2009-01-19 08:08:26 +08:00
|
|
|
else if (OverloadedFunctionDecl *Ovl
|
2008-12-23 08:26:44 +08:00
|
|
|
= dyn_cast<OverloadedFunctionDecl>(MemberDecl))
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
|
2009-01-19 08:08:26 +08:00
|
|
|
MemberLoc, Context.OverloadTy));
|
2008-12-23 08:26:44 +08:00
|
|
|
else if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl))
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
|
|
|
|
Enum, MemberLoc, Enum->getType()));
|
2008-12-23 08:26:44 +08:00
|
|
|
else if (isa<TypeDecl>(MemberDecl))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
|
|
|
|
<< DeclarationName(&Member) << int(OpKind == tok::arrow));
|
2008-12-21 07:49:58 +08:00
|
|
|
|
|
|
|
// We found a declaration kind that we didn't expect. This is a
|
|
|
|
// generic error message that tells the user that she can't refer
|
|
|
|
// to this member with '.' or '->'.
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(MemberLoc,
|
|
|
|
diag::err_typecheck_member_reference_unknown)
|
|
|
|
<< DeclarationName(&Member) << int(OpKind == tok::arrow));
|
2008-07-21 12:28:12 +08:00
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-07-21 12:59:05 +08:00
|
|
|
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
|
|
|
|
// (*Obj).ivar.
|
2008-07-21 12:36:39 +08:00
|
|
|
if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) {
|
2009-03-03 09:21:12 +08:00
|
|
|
ObjCInterfaceDecl *ClassDeclared;
|
|
|
|
if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(&Member,
|
|
|
|
ClassDeclared)) {
|
2009-02-14 06:08:30 +08:00
|
|
|
// If the decl being referenced had an error, return an error for this
|
|
|
|
// sub-expr without emitting another error, in order to avoid cascading
|
|
|
|
// error cases.
|
|
|
|
if (IV->isInvalidDecl())
|
|
|
|
return ExprError();
|
2009-02-19 05:56:37 +08:00
|
|
|
|
|
|
|
// Check whether we can reference this field.
|
|
|
|
if (DiagnoseUseOfDecl(IV, MemberLoc))
|
|
|
|
return ExprError();
|
2009-03-03 09:21:12 +08:00
|
|
|
if (IV->getAccessControl() != ObjCIvarDecl::Public) {
|
|
|
|
ObjCInterfaceDecl *ClassOfMethodDecl = 0;
|
|
|
|
if (ObjCMethodDecl *MD = getCurMethodDecl())
|
|
|
|
ClassOfMethodDecl = MD->getClassInterface();
|
2009-03-05 06:30:12 +08:00
|
|
|
else if (ObjCImpDecl && getCurFunctionDecl()) {
|
|
|
|
// Case of a c-function declared inside an objc implementation.
|
|
|
|
// FIXME: For a c-style function nested inside an objc implementation
|
|
|
|
// class, there is no implementation context available, so we pass down
|
|
|
|
// the context as argument to this routine. Ideally, this context need
|
|
|
|
// be passed down in the AST node and somehow calculated from the AST
|
|
|
|
// for a function decl.
|
|
|
|
Decl *ImplDecl = static_cast<Decl *>(ObjCImpDecl);
|
|
|
|
if (ObjCImplementationDecl *IMPD =
|
|
|
|
dyn_cast<ObjCImplementationDecl>(ImplDecl))
|
|
|
|
ClassOfMethodDecl = IMPD->getClassInterface();
|
|
|
|
else if (ObjCCategoryImplDecl* CatImplClass =
|
|
|
|
dyn_cast<ObjCCategoryImplDecl>(ImplDecl))
|
|
|
|
ClassOfMethodDecl = CatImplClass->getClassInterface();
|
2009-03-05 02:34:24 +08:00
|
|
|
}
|
2009-03-05 06:30:12 +08:00
|
|
|
if (IV->getAccessControl() == ObjCIvarDecl::Private) {
|
2009-03-03 09:21:12 +08:00
|
|
|
if (ClassDeclared != IFTy->getDecl() ||
|
2009-03-05 06:30:12 +08:00
|
|
|
ClassOfMethodDecl != ClassDeclared)
|
2009-03-03 09:21:12 +08:00
|
|
|
Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName();
|
|
|
|
}
|
|
|
|
// @protected
|
|
|
|
else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl))
|
|
|
|
Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName();
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
|
|
|
ObjCIvarRefExpr *MRef= new (Context) ObjCIvarRefExpr(IV, IV->getType(),
|
2009-01-21 08:14:39 +08:00
|
|
|
MemberLoc, BaseExpr,
|
2008-12-19 01:29:46 +08:00
|
|
|
OpKind == tok::arrow);
|
|
|
|
Context.setFieldDecl(IFTy->getDecl(), IV, MRef);
|
2009-01-19 08:08:26 +08:00
|
|
|
return Owned(MRef);
|
2008-12-14 06:20:28 +08:00
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
|
|
|
|
<< IFTy->getDecl()->getDeclName() << &Member
|
|
|
|
<< BaseExpr->getSourceRange());
|
2008-07-21 12:28:12 +08:00
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-07-21 12:59:05 +08:00
|
|
|
// Handle Objective-C property access, which is "Obj.property" where Obj is a
|
|
|
|
// pointer to a (potentially qualified) interface type.
|
|
|
|
const PointerType *PTy;
|
|
|
|
const ObjCInterfaceType *IFTy;
|
|
|
|
if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) &&
|
|
|
|
(IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) {
|
|
|
|
ObjCInterfaceDecl *IFace = IFTy->getDecl();
|
2008-08-30 13:35:15 +08:00
|
|
|
|
2008-09-03 09:05:41 +08:00
|
|
|
// Search for a declared property first.
|
2009-02-17 02:35:08 +08:00
|
|
|
if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) {
|
2009-02-19 05:56:37 +08:00
|
|
|
// Check whether we can reference this property.
|
|
|
|
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
|
|
|
return ExprError();
|
2009-02-17 02:35:08 +08:00
|
|
|
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
2009-02-17 02:35:08 +08:00
|
|
|
MemberLoc, BaseExpr));
|
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-09-03 09:05:41 +08:00
|
|
|
// Check protocols on qualified interfaces.
|
2008-07-21 13:20:01 +08:00
|
|
|
for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(),
|
|
|
|
E = IFTy->qual_end(); I != E; ++I)
|
2009-02-17 02:35:08 +08:00
|
|
|
if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
|
2009-02-19 05:56:37 +08:00
|
|
|
// Check whether we can reference this property.
|
|
|
|
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
|
|
|
return ExprError();
|
2009-02-17 02:35:08 +08:00
|
|
|
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
2009-02-17 02:35:08 +08:00
|
|
|
MemberLoc, BaseExpr));
|
|
|
|
}
|
2008-09-03 09:05:41 +08:00
|
|
|
|
|
|
|
// If that failed, look for an "implicit" property by seeing if the nullary
|
|
|
|
// selector is implemented.
|
|
|
|
|
|
|
|
// FIXME: The logic for looking up nullary and unary selectors should be
|
|
|
|
// shared with the code in ActOnInstanceMessage.
|
|
|
|
|
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
|
|
|
|
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-09-03 09:05:41 +08:00
|
|
|
// If this reference is in an @implementation, check for 'private' methods.
|
|
|
|
if (!Getter)
|
|
|
|
if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
|
|
|
|
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
|
2009-02-19 11:04:26 +08:00
|
|
|
if (ObjCImplementationDecl *ImpDecl =
|
2008-09-03 09:05:41 +08:00
|
|
|
ObjCImplementations[ClassDecl->getIdentifier()])
|
|
|
|
Getter = ImpDecl->getInstanceMethod(Sel);
|
|
|
|
|
2008-10-23 03:16:27 +08:00
|
|
|
// Look through local category implementations associated with the class.
|
|
|
|
if (!Getter) {
|
|
|
|
for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Getter; i++) {
|
|
|
|
if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
|
|
|
|
Getter = ObjCCategoryImpls[i]->getInstanceMethod(Sel);
|
|
|
|
}
|
|
|
|
}
|
2008-09-03 09:05:41 +08:00
|
|
|
if (Getter) {
|
2009-02-19 05:56:37 +08:00
|
|
|
// Check if we can reference this property.
|
|
|
|
if (DiagnoseUseOfDecl(Getter, MemberLoc))
|
|
|
|
return ExprError();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-03 09:05:41 +08:00
|
|
|
// If we found a getter then this may be a valid dot-reference, we
|
2008-11-23 04:25:50 +08:00
|
|
|
// will look for the matching setter, in case it is needed.
|
|
|
|
IdentifierInfo *SetterName = constructSetterName(PP.getIdentifierTable(),
|
|
|
|
&Member);
|
|
|
|
Selector SetterSel = PP.getSelectorTable().getUnarySelector(SetterName);
|
|
|
|
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
|
|
|
|
if (!Setter) {
|
2009-02-19 11:04:26 +08:00
|
|
|
// If this reference is in an @implementation, also check for 'private'
|
2008-11-23 04:25:50 +08:00
|
|
|
// methods.
|
|
|
|
if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
|
|
|
|
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
|
2009-02-19 11:04:26 +08:00
|
|
|
if (ObjCImplementationDecl *ImpDecl =
|
2008-11-23 04:25:50 +08:00
|
|
|
ObjCImplementations[ClassDecl->getIdentifier()])
|
|
|
|
Setter = ImpDecl->getInstanceMethod(SetterSel);
|
|
|
|
}
|
|
|
|
// Look through local category implementations associated with the class.
|
|
|
|
if (!Setter) {
|
|
|
|
for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
|
|
|
|
if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
|
|
|
|
Setter = ObjCCategoryImpls[i]->getInstanceMethod(SetterSel);
|
|
|
|
}
|
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2009-02-19 05:56:37 +08:00
|
|
|
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
|
|
|
|
return ExprError();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
// FIXME: we must check that the setter has property type.
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) ObjCKVCRefExpr(Getter, Getter->getResultType(),
|
2009-01-21 08:14:39 +08:00
|
|
|
Setter, MemberLoc, BaseExpr));
|
2008-09-03 09:05:41 +08:00
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
|
|
|
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
|
|
|
<< &Member << BaseType);
|
2007-11-13 06:29:28 +08:00
|
|
|
}
|
2008-10-21 06:53:06 +08:00
|
|
|
// Handle properties on qualified "id" protocols.
|
|
|
|
const ObjCQualifiedIdType *QIdTy;
|
|
|
|
if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) {
|
|
|
|
// Check protocols on qualified interfaces.
|
|
|
|
for (ObjCQualifiedIdType::qual_iterator I = QIdTy->qual_begin(),
|
2008-12-10 08:21:50 +08:00
|
|
|
E = QIdTy->qual_end(); I != E; ++I) {
|
2009-02-17 02:35:08 +08:00
|
|
|
if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
|
2009-02-19 05:56:37 +08:00
|
|
|
// Check the use of this declaration
|
|
|
|
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
|
|
|
return ExprError();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
2009-02-17 02:35:08 +08:00
|
|
|
MemberLoc, BaseExpr));
|
|
|
|
}
|
2008-12-10 08:21:50 +08:00
|
|
|
// Also must look for a getter name which uses property syntax.
|
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
|
|
|
|
if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
|
2009-02-19 05:56:37 +08:00
|
|
|
// Check the use of this method.
|
|
|
|
if (DiagnoseUseOfDecl(OMD, MemberLoc))
|
|
|
|
return ExprError();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
|
|
|
return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
|
2009-01-21 08:14:39 +08:00
|
|
|
OMD->getResultType(), OMD, OpLoc, MemberLoc, NULL, 0));
|
2008-12-10 08:21:50 +08:00
|
|
|
}
|
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
|
|
|
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
|
|
|
<< &Member << BaseType);
|
2009-02-19 11:04:26 +08:00
|
|
|
}
|
2008-07-21 12:28:12 +08:00
|
|
|
// Handle 'field access' to vectors, such as 'V.xx'.
|
2009-02-17 05:11:58 +08:00
|
|
|
if (BaseType->isExtVectorType()) {
|
2008-07-21 12:28:12 +08:00
|
|
|
QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc);
|
|
|
|
if (ret.isNull())
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, Member,
|
2009-01-21 08:14:39 +08:00
|
|
|
MemberLoc));
|
2008-07-21 12:28:12 +08:00
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
|
|
|
return ExprError(Diag(MemberLoc,
|
|
|
|
diag::err_typecheck_member_reference_struct_union)
|
|
|
|
<< BaseType << BaseExpr->getSourceRange());
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
/// ConvertArgumentsForCall - Converts the arguments specified in
|
|
|
|
/// Args/NumArgs to the parameter types of the function FDecl with
|
|
|
|
/// function prototype Proto. Call is the call expression itself, and
|
|
|
|
/// Fn is the function expression. For a C++ member function, this
|
|
|
|
/// routine does not attempt to convert the object argument. Returns
|
|
|
|
/// true if the call is ill-formed.
|
2009-02-19 11:04:26 +08:00
|
|
|
bool
|
|
|
|
Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
|
2008-12-22 13:46:06 +08:00
|
|
|
FunctionDecl *FDecl,
|
2009-02-27 07:50:07 +08:00
|
|
|
const FunctionProtoType *Proto,
|
2008-12-22 13:46:06 +08:00
|
|
|
Expr **Args, unsigned NumArgs,
|
|
|
|
SourceLocation RParenLoc) {
|
2009-02-19 11:04:26 +08:00
|
|
|
// C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
|
2008-12-22 13:46:06 +08:00
|
|
|
// assignment, to the types of the corresponding parameter, ...
|
|
|
|
unsigned NumArgsInProto = Proto->getNumArgs();
|
|
|
|
unsigned NumArgsToCheck = NumArgs;
|
2009-01-24 05:30:56 +08:00
|
|
|
bool Invalid = false;
|
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
// If too few arguments are available (and we don't have default
|
|
|
|
// arguments for the remaining parameters), don't make the call.
|
|
|
|
if (NumArgs < NumArgsInProto) {
|
|
|
|
if (!FDecl || NumArgs < FDecl->getMinRequiredArguments())
|
|
|
|
return Diag(RParenLoc, diag::err_typecheck_call_too_few_args)
|
|
|
|
<< Fn->getType()->isBlockPointerType() << Fn->getSourceRange();
|
|
|
|
// Use default arguments for missing arguments
|
|
|
|
NumArgsToCheck = NumArgsInProto;
|
2009-02-07 09:47:29 +08:00
|
|
|
Call->setNumArgs(Context, NumArgsInProto);
|
2008-12-22 13:46:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If too many are passed and not variadic, error on the extras and drop
|
|
|
|
// them.
|
|
|
|
if (NumArgs > NumArgsInProto) {
|
|
|
|
if (!Proto->isVariadic()) {
|
|
|
|
Diag(Args[NumArgsInProto]->getLocStart(),
|
|
|
|
diag::err_typecheck_call_too_many_args)
|
|
|
|
<< Fn->getType()->isBlockPointerType() << Fn->getSourceRange()
|
|
|
|
<< SourceRange(Args[NumArgsInProto]->getLocStart(),
|
|
|
|
Args[NumArgs-1]->getLocEnd());
|
|
|
|
// This deletes the extra arguments.
|
2009-02-07 09:47:29 +08:00
|
|
|
Call->setNumArgs(Context, NumArgsInProto);
|
2009-01-24 05:30:56 +08:00
|
|
|
Invalid = true;
|
2008-12-22 13:46:06 +08:00
|
|
|
}
|
|
|
|
NumArgsToCheck = NumArgsInProto;
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
// Continue to check argument types (even if we have too few/many args).
|
|
|
|
for (unsigned i = 0; i != NumArgsToCheck; i++) {
|
|
|
|
QualType ProtoArgType = Proto->getArgType(i);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
Expr *Arg;
|
2008-12-24 08:01:03 +08:00
|
|
|
if (i < NumArgs) {
|
2008-12-22 13:46:06 +08:00
|
|
|
Arg = Args[i];
|
2008-12-24 08:01:03 +08:00
|
|
|
|
|
|
|
// Pass the argument.
|
|
|
|
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
|
|
|
|
return true;
|
2009-02-19 11:04:26 +08:00
|
|
|
} else
|
2008-12-24 08:01:03 +08:00
|
|
|
// We already type-checked the argument, so we know it works.
|
2009-01-21 08:14:39 +08:00
|
|
|
Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i));
|
2008-12-22 13:46:06 +08:00
|
|
|
QualType ArgType = Arg->getType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
Call->setArg(i, Arg);
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
// If this is a variadic call, handle args passed through "...".
|
|
|
|
if (Proto->isVariadic()) {
|
2009-01-17 00:48:51 +08:00
|
|
|
VariadicCallType CallType = VariadicFunction;
|
|
|
|
if (Fn->getType()->isBlockPointerType())
|
|
|
|
CallType = VariadicBlock; // Block
|
|
|
|
else if (isa<MemberExpr>(Fn))
|
|
|
|
CallType = VariadicMethod;
|
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
// Promote the arguments (C99 6.5.2.2p7).
|
|
|
|
for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
|
|
|
|
Expr *Arg = Args[i];
|
2009-01-17 00:48:51 +08:00
|
|
|
DefaultVariadicArgumentPromotion(Arg, CallType);
|
2008-12-22 13:46:06 +08:00
|
|
|
Call->setArg(i, Arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-24 05:30:56 +08:00
|
|
|
return Invalid;
|
2008-12-22 13:46:06 +08:00
|
|
|
}
|
|
|
|
|
2007-09-16 11:34:24 +08:00
|
|
|
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
|
2006-11-10 13:29:30 +08:00
|
|
|
/// This provides the location of the left/right parens and a list of comma
|
|
|
|
/// locations.
|
2009-01-19 08:08:26 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
|
|
|
|
MultiExprArg args,
|
2008-12-22 13:46:06 +08:00
|
|
|
SourceLocation *CommaLocs, SourceLocation RParenLoc) {
|
2009-01-19 08:08:26 +08:00
|
|
|
unsigned NumArgs = args.size();
|
|
|
|
Expr *Fn = static_cast<Expr *>(fn.release());
|
|
|
|
Expr **Args = reinterpret_cast<Expr**>(args.release());
|
2007-07-21 11:03:59 +08:00
|
|
|
assert(Fn && "no function call expression");
|
2008-04-08 12:40:51 +08:00
|
|
|
FunctionDecl *FDecl = NULL;
|
2009-02-04 23:01:18 +08:00
|
|
|
DeclarationName UnqualifiedName;
|
2008-10-22 00:13:35 +08:00
|
|
|
|
2009-02-04 23:01:18 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
// Determine whether this is a dependent call inside a C++ template,
|
2009-02-19 11:04:26 +08:00
|
|
|
// in which case we won't do any semantic analysis now.
|
2009-02-04 23:01:18 +08:00
|
|
|
// FIXME: Will need to cache the results of name lookup (including ADL) in Fn.
|
|
|
|
bool Dependent = false;
|
|
|
|
if (Fn->isTypeDependent())
|
|
|
|
Dependent = true;
|
|
|
|
else if (Expr::hasAnyTypeDependentArguments(Args, NumArgs))
|
2008-12-06 08:22:45 +08:00
|
|
|
Dependent = true;
|
|
|
|
|
2009-02-04 23:01:18 +08:00
|
|
|
if (Dependent)
|
2009-02-10 04:51:47 +08:00
|
|
|
return Owned(new (Context) CallExpr(Context, Fn, Args, NumArgs,
|
2009-02-04 23:01:18 +08:00
|
|
|
Context.DependentTy, RParenLoc));
|
2008-12-06 07:32:09 +08:00
|
|
|
|
2009-02-04 23:01:18 +08:00
|
|
|
// Determine whether this is a call to an object (C++ [over.call.object]).
|
|
|
|
if (Fn->getType()->isRecordType())
|
|
|
|
return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
|
|
|
|
CommaLocs, RParenLoc));
|
2008-12-22 13:46:06 +08:00
|
|
|
|
2009-02-04 08:32:51 +08:00
|
|
|
// Determine whether this is a call to a member function.
|
2008-12-22 13:46:06 +08:00
|
|
|
if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens()))
|
|
|
|
if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
|
|
|
|
isa<CXXMethodDecl>(MemExpr->getMemberDecl()))
|
2009-01-19 08:08:26 +08:00
|
|
|
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
|
|
|
|
CommaLocs, RParenLoc));
|
2008-12-22 13:46:06 +08:00
|
|
|
}
|
|
|
|
|
2009-02-04 08:32:51 +08:00
|
|
|
// If we're directly calling a function, get the appropriate declaration.
|
2009-01-06 13:10:23 +08:00
|
|
|
DeclRefExpr *DRExpr = NULL;
|
2009-02-04 08:32:51 +08:00
|
|
|
Expr *FnExpr = Fn;
|
|
|
|
bool ADL = true;
|
|
|
|
while (true) {
|
|
|
|
if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
|
|
|
|
FnExpr = IcExpr->getSubExpr();
|
|
|
|
else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
|
2009-02-19 11:04:26 +08:00
|
|
|
// Parentheses around a function disable ADL
|
2009-02-04 23:01:18 +08:00
|
|
|
// (C++0x [basic.lookup.argdep]p1).
|
2009-02-04 08:32:51 +08:00
|
|
|
ADL = false;
|
|
|
|
FnExpr = PExpr->getSubExpr();
|
|
|
|
} else if (isa<UnaryOperator>(FnExpr) &&
|
2009-02-19 11:04:26 +08:00
|
|
|
cast<UnaryOperator>(FnExpr)->getOpcode()
|
2009-02-04 08:32:51 +08:00
|
|
|
== UnaryOperator::AddrOf) {
|
|
|
|
FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
|
2009-02-14 15:22:29 +08:00
|
|
|
} else if ((DRExpr = dyn_cast<DeclRefExpr>(FnExpr))) {
|
|
|
|
// Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
|
|
|
|
ADL &= !isa<QualifiedDeclRefExpr>(DRExpr);
|
|
|
|
break;
|
2009-02-19 11:04:26 +08:00
|
|
|
} else if (UnresolvedFunctionNameExpr *DepName
|
2009-02-14 15:22:29 +08:00
|
|
|
= dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
|
|
|
|
UnqualifiedName = DepName->getName();
|
|
|
|
break;
|
2009-02-04 08:32:51 +08:00
|
|
|
} else {
|
2009-02-14 15:22:29 +08:00
|
|
|
// Any kind of name that does not refer to a declaration (or
|
|
|
|
// set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3).
|
|
|
|
ADL = false;
|
2009-02-04 08:32:51 +08:00
|
|
|
break;
|
|
|
|
}
|
2008-10-22 00:13:35 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-04 23:01:18 +08:00
|
|
|
OverloadedFunctionDecl *Ovl = 0;
|
|
|
|
if (DRExpr) {
|
2009-02-04 08:32:51 +08:00
|
|
|
FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
|
2009-02-04 23:01:18 +08:00
|
|
|
Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
|
|
|
|
}
|
2008-10-22 00:13:35 +08: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.
llvm-svn: 64336
2009-02-12 07:02:49 +08:00
|
|
|
if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
|
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.
llvm-svn: 64504
2009-02-14 07:20:09 +08:00
|
|
|
// We don't perform ADL for implicit declarations of builtins.
|
2009-02-15 02:57:46 +08:00
|
|
|
if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
|
2009-02-04 08:32:51 +08:00
|
|
|
ADL = false;
|
|
|
|
|
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.
llvm-svn: 64336
2009-02-12 07:02:49 +08:00
|
|
|
// We don't perform ADL in C.
|
|
|
|
if (!getLangOptions().CPlusPlus)
|
|
|
|
ADL = false;
|
|
|
|
|
2009-02-04 23:01:18 +08:00
|
|
|
if (Ovl || ADL) {
|
2009-02-19 11:04:26 +08:00
|
|
|
FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0,
|
|
|
|
UnqualifiedName, LParenLoc, Args,
|
2009-02-04 08:32:51 +08:00
|
|
|
NumArgs, CommaLocs, RParenLoc, ADL);
|
|
|
|
if (!FDecl)
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
// Update Fn to refer to the actual function selected.
|
|
|
|
Expr *NewFn = 0;
|
2009-02-19 11:04:26 +08:00
|
|
|
if (QualifiedDeclRefExpr *QDRExpr
|
2009-02-04 23:01:18 +08:00
|
|
|
= dyn_cast_or_null<QualifiedDeclRefExpr>(DRExpr))
|
2009-02-19 11:04:26 +08:00
|
|
|
NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
|
|
|
|
QDRExpr->getLocation(),
|
2009-02-04 08:32:51 +08:00
|
|
|
false, false,
|
|
|
|
QDRExpr->getSourceRange().getBegin());
|
|
|
|
else
|
2009-02-19 11:04:26 +08:00
|
|
|
NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
|
2009-02-04 08:32:51 +08:00
|
|
|
Fn->getSourceRange().getBegin());
|
|
|
|
Fn->Destroy(Context);
|
|
|
|
Fn = NewFn;
|
|
|
|
}
|
2008-10-22 00:13:35 +08:00
|
|
|
}
|
2008-04-08 12:40:51 +08:00
|
|
|
|
|
|
|
// Promote the function operand.
|
|
|
|
UsualUnaryConversions(Fn);
|
|
|
|
|
2007-12-28 13:29:59 +08:00
|
|
|
// Make the call expr early, before semantic checks. This guarantees cleanup
|
|
|
|
// of arguments and function on error.
|
2009-02-10 04:51:47 +08:00
|
|
|
ExprOwningPtr<CallExpr> TheCall(this, new (Context) CallExpr(Context, Fn,
|
|
|
|
Args, NumArgs,
|
|
|
|
Context.BoolTy,
|
|
|
|
RParenLoc));
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-09-06 06:11:13 +08:00
|
|
|
const FunctionType *FuncT;
|
|
|
|
if (!Fn->getType()->isBlockPointerType()) {
|
|
|
|
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
|
|
|
|
// have type pointer to function".
|
|
|
|
const PointerType *PT = Fn->getType()->getAsPointerType();
|
|
|
|
if (PT == 0)
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
|
|
|
|
<< Fn->getType() << Fn->getSourceRange());
|
2008-09-06 06:11:13 +08:00
|
|
|
FuncT = PT->getPointeeType()->getAsFunctionType();
|
|
|
|
} else { // This is a block call.
|
|
|
|
FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()->
|
|
|
|
getAsFunctionType();
|
|
|
|
}
|
2007-12-28 13:29:59 +08:00
|
|
|
if (FuncT == 0)
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
|
|
|
|
<< Fn->getType() << Fn->getSourceRange());
|
|
|
|
|
2007-12-28 13:29:59 +08:00
|
|
|
// We know the result type of the call, set it.
|
2008-10-29 10:00:59 +08:00
|
|
|
TheCall->setType(FuncT->getResultType().getNonReferenceType());
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2009-02-27 07:50:07 +08:00
|
|
|
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) {
|
2009-02-19 11:04:26 +08:00
|
|
|
if (ConvertArgumentsForCall(&*TheCall, Fn, FDecl, Proto, Args, NumArgs,
|
2008-12-22 13:46:06 +08:00
|
|
|
RParenLoc))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2007-12-28 13:29:59 +08:00
|
|
|
} else {
|
2009-02-27 07:50:07 +08:00
|
|
|
assert(isa<FunctionNoProtoType>(FuncT) && "Unknown FunctionType!");
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2007-08-29 07:30:39 +08:00
|
|
|
// Promote the arguments (C99 6.5.2.2p6).
|
2007-12-28 13:29:59 +08:00
|
|
|
for (unsigned i = 0; i != NumArgs; i++) {
|
|
|
|
Expr *Arg = Args[i];
|
|
|
|
DefaultArgumentPromotion(Arg);
|
|
|
|
TheCall->setArg(i, Arg);
|
2007-08-29 07:30:39 +08:00
|
|
|
}
|
2007-04-27 04:39:23 +08:00
|
|
|
}
|
2007-12-28 13:29:59 +08:00
|
|
|
|
2008-12-22 13:46:06 +08:00
|
|
|
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl))
|
|
|
|
if (!Method->isStatic())
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(LParenLoc, diag::err_member_call_without_object)
|
|
|
|
<< Fn->getSourceRange());
|
2008-12-22 13:46:06 +08:00
|
|
|
|
2007-08-11 04:18:51 +08:00
|
|
|
// Do special checking on direct calls to functions.
|
2008-05-15 03:38:39 +08:00
|
|
|
if (FDecl)
|
|
|
|
return CheckFunctionCall(FDecl, TheCall.take());
|
2007-08-11 04:18:51 +08:00
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
return Owned(TheCall.take());
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2009-01-20 06:31:54 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
|
|
|
|
SourceLocation RParenLoc, ExprArg InitExpr) {
|
2007-09-16 11:34:24 +08:00
|
|
|
assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
|
2007-07-19 09:06:55 +08:00
|
|
|
QualType literalType = QualType::getFromOpaquePtr(Ty);
|
2007-07-20 05:32:11 +08:00
|
|
|
// FIXME: put back this assert when initializers are worked out.
|
2007-09-16 11:34:24 +08:00
|
|
|
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
|
2009-01-20 06:31:54 +08:00
|
|
|
Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
|
2007-12-05 15:24:19 +08:00
|
|
|
|
2008-05-20 13:22:08 +08:00
|
|
|
if (literalType->isArrayType()) {
|
2008-08-04 15:31:14 +08:00
|
|
|
if (literalType->isVariableArrayType())
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init)
|
|
|
|
<< SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()));
|
2009-01-20 03:26:10 +08:00
|
|
|
} else if (DiagnoseIncompleteType(LParenLoc, literalType,
|
|
|
|
diag::err_typecheck_decl_incomplete_type,
|
|
|
|
SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())))
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2008-05-20 13:22:08 +08:00
|
|
|
|
2009-01-20 06:31:54 +08:00
|
|
|
if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
|
2009-01-14 23:45:31 +08:00
|
|
|
DeclarationName(), /*FIXME:DirectInit=*/false))
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2008-01-15 02:19:28 +08:00
|
|
|
|
2008-12-05 07:50:19 +08:00
|
|
|
bool isFileScope = getCurFunctionOrMethodDecl() == 0;
|
2008-01-15 02:19:28 +08:00
|
|
|
if (isFileScope) { // 6.5.2.5p3
|
2008-01-11 06:15:12 +08:00
|
|
|
if (CheckForConstantInitializer(literalExpr, literalType))
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2008-01-11 06:15:12 +08:00
|
|
|
}
|
2009-01-20 06:31:54 +08:00
|
|
|
InitExpr.release();
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType,
|
2009-01-21 08:14:39 +08:00
|
|
|
literalExpr, isFileScope));
|
2007-07-19 09:06:55 +08:00
|
|
|
}
|
|
|
|
|
2009-01-20 06:31:54 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
|
|
|
|
InitListDesignations &Designators,
|
|
|
|
SourceLocation RBraceLoc) {
|
|
|
|
unsigned NumInit = initlist.size();
|
|
|
|
Expr **InitList = reinterpret_cast<Expr**>(initlist.release());
|
2007-08-31 12:56:16 +08:00
|
|
|
|
2007-09-16 02:49:24 +08:00
|
|
|
// Semantic analysis for initializers is done by ActOnDeclarator() and
|
2009-02-19 11:04:26 +08:00
|
|
|
// CheckInitializer() - it requires knowledge of the object being intialized.
|
2009-01-20 06:31:54 +08:00
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit,
|
2009-01-29 05:54:33 +08:00
|
|
|
RBraceLoc);
|
2008-04-02 12:24:33 +08:00
|
|
|
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
|
2009-01-20 06:31:54 +08:00
|
|
|
return Owned(E);
|
2007-07-19 09:06:55 +08:00
|
|
|
}
|
|
|
|
|
2008-08-17 04:27:34 +08:00
|
|
|
/// CheckCastTypes - Check type constraints for casting between types.
|
2008-08-20 11:55:42 +08:00
|
|
|
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
|
2008-08-17 04:27:34 +08:00
|
|
|
UsualUnaryConversions(castExpr);
|
|
|
|
|
|
|
|
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
|
|
|
|
// type needs to be scalar.
|
|
|
|
if (castType->isVoidType()) {
|
|
|
|
// Cast to void allows any expr type.
|
2008-12-06 07:32:09 +08:00
|
|
|
} else if (castType->isDependentType() || castExpr->isTypeDependent()) {
|
|
|
|
// We can't check any more until template instantiation time.
|
2008-08-17 04:27:34 +08:00
|
|
|
} else if (!castType->isScalarType() && !castType->isVectorType()) {
|
2009-01-15 12:51:39 +08:00
|
|
|
if (Context.getCanonicalType(castType).getUnqualifiedType() ==
|
|
|
|
Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) &&
|
|
|
|
(castType->isStructureType() || castType->isUnionType())) {
|
|
|
|
// GCC struct/union extension: allow cast to self.
|
|
|
|
Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar)
|
|
|
|
<< castType << castExpr->getSourceRange();
|
|
|
|
} else if (castType->isUnionType()) {
|
|
|
|
// GCC cast to union extension
|
|
|
|
RecordDecl *RD = castType->getAsRecordType()->getDecl();
|
|
|
|
RecordDecl::field_iterator Field, FieldEnd;
|
|
|
|
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
|
|
|
|
Field != FieldEnd; ++Field) {
|
|
|
|
if (Context.getCanonicalType(Field->getType()).getUnqualifiedType() ==
|
|
|
|
Context.getCanonicalType(castExpr->getType()).getUnqualifiedType()) {
|
|
|
|
Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union)
|
|
|
|
<< castExpr->getSourceRange();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Field == FieldEnd)
|
|
|
|
return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type)
|
|
|
|
<< castExpr->getType() << castExpr->getSourceRange();
|
|
|
|
} else {
|
2008-08-17 04:27:34 +08:00
|
|
|
// Reject any other conversions to non-scalar types.
|
2008-11-19 13:08:23 +08:00
|
|
|
return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< castType << castExpr->getSourceRange();
|
2008-08-17 04:27:34 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
} else if (!castExpr->getType()->isScalarType() &&
|
2008-08-17 04:27:34 +08:00
|
|
|
!castExpr->getType()->isVectorType()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
return Diag(castExpr->getLocStart(),
|
|
|
|
diag::err_typecheck_expect_scalar_operand)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< castExpr->getType() << castExpr->getSourceRange();
|
2008-08-17 04:27:34 +08:00
|
|
|
} else if (castExpr->getType()->isVectorType()) {
|
|
|
|
if (CheckVectorCast(TyR, castExpr->getType(), castType))
|
|
|
|
return true;
|
|
|
|
} else if (castType->isVectorType()) {
|
|
|
|
if (CheckVectorCast(TyR, castType, castExpr->getType()))
|
|
|
|
return true;
|
2009-03-04 23:11:40 +08:00
|
|
|
} else if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) {
|
|
|
|
return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast);
|
2008-08-17 04:27:34 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-12-20 08:44:32 +08:00
|
|
|
bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) {
|
2007-11-27 13:51:55 +08:00
|
|
|
assert(VectorTy->isVectorType() && "Not a vector type!");
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-11-27 13:51:55 +08:00
|
|
|
if (Ty->isVectorType() || Ty->isIntegerType()) {
|
2008-03-06 02:54:05 +08:00
|
|
|
if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty))
|
2007-11-27 13:51:55 +08:00
|
|
|
return Diag(R.getBegin(),
|
2009-02-19 11:04:26 +08:00
|
|
|
Ty->isVectorType() ?
|
2007-11-27 13:51:55 +08:00
|
|
|
diag::err_invalid_conversion_between_vectors :
|
2008-11-19 13:08:23 +08:00
|
|
|
diag::err_invalid_conversion_between_vector_and_integer)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< VectorTy << Ty << R;
|
2007-11-27 13:51:55 +08:00
|
|
|
} else
|
|
|
|
return Diag(R.getBegin(),
|
2008-11-19 13:08:23 +08:00
|
|
|
diag::err_invalid_conversion_between_vector_and_scalar)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< VectorTy << Ty << R;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-11-27 13:51:55 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-01-20 06:31:54 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
|
|
|
|
SourceLocation RParenLoc, ExprArg Op) {
|
|
|
|
assert((Ty != 0) && (Op.get() != 0) &&
|
|
|
|
"ActOnCastExpr(): missing type or expr");
|
2007-07-17 07:25:18 +08:00
|
|
|
|
2009-01-20 06:31:54 +08:00
|
|
|
Expr *castExpr = static_cast<Expr*>(Op.release());
|
2007-07-17 07:25:18 +08:00
|
|
|
QualType castType = QualType::getFromOpaquePtr(Ty);
|
|
|
|
|
2008-08-17 04:27:34 +08:00
|
|
|
if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr))
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) CStyleCastExpr(castType, castExpr, castType,
|
2009-02-19 11:04:26 +08:00
|
|
|
LParenLoc, RParenLoc));
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension.
|
|
|
|
/// In that case, lhs = cond.
|
2009-02-18 12:38:20 +08:00
|
|
|
/// C99 6.5.15
|
|
|
|
QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
|
|
|
|
SourceLocation QuestionLoc) {
|
2009-02-18 12:28:32 +08:00
|
|
|
UsualUnaryConversions(Cond);
|
|
|
|
UsualUnaryConversions(LHS);
|
|
|
|
UsualUnaryConversions(RHS);
|
|
|
|
QualType CondTy = Cond->getType();
|
|
|
|
QualType LHSTy = LHS->getType();
|
|
|
|
QualType RHSTy = RHS->getType();
|
2007-07-17 05:54:35 +08:00
|
|
|
|
2007-05-17 03:47:19 +08:00
|
|
|
// first, check the condition.
|
2009-02-18 12:28:32 +08:00
|
|
|
if (!Cond->isTypeDependent()) {
|
|
|
|
if (!CondTy->isScalarType()) { // C99 6.5.15p2
|
|
|
|
Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar)
|
|
|
|
<< CondTy;
|
2008-12-06 07:32:09 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2007-05-17 03:47:19 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-01-07 06:42:25 +08:00
|
|
|
// Now check the two expressions.
|
2009-02-18 12:28:32 +08:00
|
|
|
if ((LHS && LHS->isTypeDependent()) || (RHS && RHS->isTypeDependent()))
|
2008-12-06 07:32:09 +08:00
|
|
|
return Context.DependentTy;
|
|
|
|
|
2008-01-07 06:42:25 +08:00
|
|
|
// If both operands have arithmetic type, do the usual arithmetic conversions
|
|
|
|
// to find a common type: C99 6.5.15p3,5.
|
2009-02-18 12:28:32 +08:00
|
|
|
if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) {
|
|
|
|
UsualArithmeticConversions(LHS, RHS);
|
|
|
|
return LHS->getType();
|
2007-07-17 08:58:39 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-01-07 06:42:25 +08:00
|
|
|
// If both operands are the same structure or union type, the result is that
|
|
|
|
// type.
|
2009-02-18 12:28:32 +08:00
|
|
|
if (const RecordType *LHSRT = LHSTy->getAsRecordType()) { // C99 6.5.15p3
|
|
|
|
if (const RecordType *RHSRT = RHSTy->getAsRecordType())
|
2007-11-26 09:40:58 +08:00
|
|
|
if (LHSRT->getDecl() == RHSRT->getDecl())
|
2009-02-19 11:04:26 +08:00
|
|
|
// "If both the operands have structure or union type, the result has
|
2008-01-07 06:42:25 +08:00
|
|
|
// that type." This implies that CV qualifiers are dropped.
|
2009-02-18 12:28:32 +08:00
|
|
|
return LHSTy.getUnqualifiedType();
|
2007-05-17 03:47:19 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-01-07 06:42:25 +08:00
|
|
|
// C99 6.5.15p5: "If both operands have void type, the result has void type."
|
2008-05-13 05:44:38 +08:00
|
|
|
// The following || allows only one side to be void (a GCC-ism).
|
2009-02-18 12:28:32 +08:00
|
|
|
if (LHSTy->isVoidType() || RHSTy->isVoidType()) {
|
|
|
|
if (!LHSTy->isVoidType())
|
|
|
|
Diag(RHS->getLocStart(), diag::ext_typecheck_cond_one_void)
|
|
|
|
<< RHS->getSourceRange();
|
|
|
|
if (!RHSTy->isVoidType())
|
|
|
|
Diag(LHS->getLocStart(), diag::ext_typecheck_cond_one_void)
|
|
|
|
<< LHS->getSourceRange();
|
|
|
|
ImpCastExprToType(LHS, Context.VoidTy);
|
|
|
|
ImpCastExprToType(RHS, Context.VoidTy);
|
2008-06-05 03:47:51 +08:00
|
|
|
return Context.VoidTy;
|
2008-05-13 05:44:38 +08:00
|
|
|
}
|
2008-01-08 09:11:38 +08:00
|
|
|
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
|
|
|
|
// the type of the other operand."
|
2009-02-18 12:28:32 +08:00
|
|
|
if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() ||
|
|
|
|
Context.isObjCObjectPointerType(LHSTy)) &&
|
|
|
|
RHS->isNullPointerConstant(Context)) {
|
|
|
|
ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
|
|
|
|
return LHSTy;
|
2008-01-08 09:11:38 +08:00
|
|
|
}
|
2009-02-18 12:28:32 +08:00
|
|
|
if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() ||
|
|
|
|
Context.isObjCObjectPointerType(RHSTy)) &&
|
|
|
|
LHS->isNullPointerConstant(Context)) {
|
|
|
|
ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
|
|
|
|
return RHSTy;
|
2008-01-08 09:11:38 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-01-07 06:50:31 +08:00
|
|
|
// Handle the case where both operands are pointers before we handle null
|
|
|
|
// pointer constants in case both operands are null pointer constants.
|
2009-02-18 12:28:32 +08:00
|
|
|
if (const PointerType *LHSPT = LHSTy->getAsPointerType()) { // C99 6.5.15p3,6
|
|
|
|
if (const PointerType *RHSPT = RHSTy->getAsPointerType()) {
|
2007-08-01 05:27:01 +08:00
|
|
|
// get the "pointed to" types
|
|
|
|
QualType lhptee = LHSPT->getPointeeType();
|
|
|
|
QualType rhptee = RHSPT->getPointeeType();
|
|
|
|
|
|
|
|
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
|
|
|
|
if (lhptee->isVoidType() &&
|
2008-04-02 14:59:01 +08:00
|
|
|
rhptee->isIncompleteOrObjectType()) {
|
2008-02-21 04:55:12 +08:00
|
|
|
// Figure out necessary qualifiers (C99 6.5.15p6)
|
|
|
|
QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers());
|
2008-02-11 06:59:36 +08:00
|
|
|
QualType destType = Context.getPointerType(destPointee);
|
2009-02-18 12:28:32 +08:00
|
|
|
ImpCastExprToType(LHS, destType); // add qualifiers if necessary
|
|
|
|
ImpCastExprToType(RHS, destType); // promote to void*
|
2008-02-11 06:59:36 +08:00
|
|
|
return destType;
|
|
|
|
}
|
2008-04-02 14:59:01 +08:00
|
|
|
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
|
2008-02-21 04:55:12 +08:00
|
|
|
QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers());
|
2008-02-11 06:59:36 +08:00
|
|
|
QualType destType = Context.getPointerType(destPointee);
|
2009-02-18 12:28:32 +08:00
|
|
|
ImpCastExprToType(LHS, destType); // add qualifiers if necessary
|
|
|
|
ImpCastExprToType(RHS, destType); // promote to void*
|
2008-02-11 06:59:36 +08:00
|
|
|
return destType;
|
|
|
|
}
|
2007-08-01 05:27:01 +08:00
|
|
|
|
2009-02-18 12:38:20 +08:00
|
|
|
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
|
2009-02-19 12:44:58 +08:00
|
|
|
// Two identical pointer types are always compatible.
|
2009-02-18 12:38:20 +08:00
|
|
|
return LHSTy;
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-18 12:28:32 +08:00
|
|
|
QualType compositeType = LHSTy;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-12 07:12:46 +08:00
|
|
|
// If either type is an Objective-C object type then check
|
|
|
|
// compatibility according to Objective-C.
|
2009-02-19 11:04:26 +08:00
|
|
|
if (Context.isObjCObjectPointerType(LHSTy) ||
|
2009-02-18 12:28:32 +08:00
|
|
|
Context.isObjCObjectPointerType(RHSTy)) {
|
2008-09-12 07:12:46 +08:00
|
|
|
// If both operands are interfaces and either operand can be
|
|
|
|
// assigned to the other, use that type as the composite
|
|
|
|
// type. This allows
|
|
|
|
// xxx ? (A*) a : (B*) b
|
|
|
|
// where B is a subclass of A.
|
|
|
|
//
|
|
|
|
// Additionally, as for assignment, if either type is 'id'
|
|
|
|
// allow silent coercion. Finally, if the types are
|
|
|
|
// incompatible then make sure to use 'id' as the composite
|
|
|
|
// type so the result is acceptable for sending messages to.
|
|
|
|
|
2009-02-13 03:05:07 +08:00
|
|
|
// FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
|
2009-02-19 11:04:26 +08:00
|
|
|
// It could return the composite type.
|
2008-09-12 07:12:46 +08:00
|
|
|
const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
|
|
|
|
const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
|
|
|
|
if (LHSIface && RHSIface &&
|
|
|
|
Context.canAssignObjCInterfaces(LHSIface, RHSIface)) {
|
2009-02-18 12:28:32 +08:00
|
|
|
compositeType = LHSTy;
|
2008-09-12 07:12:46 +08:00
|
|
|
} else if (LHSIface && RHSIface &&
|
2008-11-26 14:43:45 +08:00
|
|
|
Context.canAssignObjCInterfaces(RHSIface, LHSIface)) {
|
2009-02-18 12:28:32 +08:00
|
|
|
compositeType = RHSTy;
|
2009-02-19 11:04:26 +08:00
|
|
|
} else if (Context.isObjCIdStructType(lhptee) ||
|
|
|
|
Context.isObjCIdStructType(rhptee)) {
|
2008-09-12 07:12:46 +08:00
|
|
|
compositeType = Context.getObjCIdType();
|
|
|
|
} else {
|
2009-02-18 12:28:32 +08:00
|
|
|
Diag(QuestionLoc, diag::ext_typecheck_comparison_of_distinct_pointers)
|
2009-02-19 11:04:26 +08:00
|
|
|
<< LHSTy << RHSTy
|
2009-02-18 12:28:32 +08:00
|
|
|
<< LHS->getSourceRange() << RHS->getSourceRange();
|
2008-09-12 07:12:46 +08:00
|
|
|
QualType incompatTy = Context.getObjCIdType();
|
2009-02-18 12:28:32 +08:00
|
|
|
ImpCastExprToType(LHS, incompatTy);
|
|
|
|
ImpCastExprToType(RHS, incompatTy);
|
2009-02-19 11:04:26 +08:00
|
|
|
return incompatTy;
|
2008-09-12 07:12:46 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
} else if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
|
2008-09-12 07:12:46 +08:00
|
|
|
rhptee.getUnqualifiedType())) {
|
2009-02-18 12:28:32 +08:00
|
|
|
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
|
|
|
|
<< LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
|
2008-09-12 07:12:46 +08:00
|
|
|
// In this situation, we assume void* type. No especially good
|
|
|
|
// reason, but this is what gcc does, and we do have to pick
|
|
|
|
// to get a consistent AST.
|
|
|
|
QualType incompatTy = Context.getPointerType(Context.VoidTy);
|
2009-02-18 12:28:32 +08:00
|
|
|
ImpCastExprToType(LHS, incompatTy);
|
|
|
|
ImpCastExprToType(RHS, incompatTy);
|
2008-08-26 08:41:39 +08:00
|
|
|
return incompatTy;
|
2007-08-01 05:27:01 +08:00
|
|
|
}
|
|
|
|
// The pointer types are compatible.
|
2007-08-31 01:45:32 +08:00
|
|
|
// C99 6.5.15p6: If both operands are pointers to compatible types *or* to
|
|
|
|
// differently qualified versions of compatible types, the result type is
|
|
|
|
// a pointer to an appropriately qualified version of the *composite*
|
|
|
|
// type.
|
2008-05-17 04:37:07 +08:00
|
|
|
// FIXME: Need to calculate the composite type.
|
2008-02-11 06:59:36 +08:00
|
|
|
// FIXME: Need to add qualifiers
|
2009-02-18 12:28:32 +08:00
|
|
|
ImpCastExprToType(LHS, compositeType);
|
|
|
|
ImpCastExprToType(RHS, compositeType);
|
2008-05-17 04:37:07 +08:00
|
|
|
return compositeType;
|
2007-05-17 03:47:19 +08:00
|
|
|
}
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-18 12:38:20 +08:00
|
|
|
// Selection between block pointer types is ok as long as they are the same.
|
|
|
|
if (LHSTy->isBlockPointerType() && RHSTy->isBlockPointerType() &&
|
|
|
|
Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy))
|
|
|
|
return LHSTy;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-12 07:12:46 +08:00
|
|
|
// Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type
|
|
|
|
// evaluates to "struct objc_object *" (and is handled above when comparing
|
2009-02-19 11:04:26 +08:00
|
|
|
// id with statically typed objects).
|
|
|
|
if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) {
|
2008-09-12 07:12:46 +08:00
|
|
|
// GCC allows qualified id and any Objective-C type to devolve to
|
|
|
|
// id. Currently localizing to here until clear this should be
|
|
|
|
// part of ObjCQualifiedIdTypesAreCompatible.
|
2009-02-18 12:28:32 +08:00
|
|
|
if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) ||
|
2009-02-19 11:04:26 +08:00
|
|
|
(LHSTy->isObjCQualifiedIdType() &&
|
2009-02-18 12:28:32 +08:00
|
|
|
Context.isObjCObjectPointerType(RHSTy)) ||
|
|
|
|
(RHSTy->isObjCQualifiedIdType() &&
|
|
|
|
Context.isObjCObjectPointerType(LHSTy))) {
|
2008-09-12 07:12:46 +08:00
|
|
|
// FIXME: This is not the correct composite type. This only
|
|
|
|
// happens to work because id can more or less be used anywhere,
|
|
|
|
// however this may change the type of method sends.
|
|
|
|
// FIXME: gcc adds some type-checking of the arguments and emits
|
|
|
|
// (confusing) incompatible comparison warnings in some
|
|
|
|
// cases. Investigate.
|
|
|
|
QualType compositeType = Context.getObjCIdType();
|
2009-02-18 12:28:32 +08:00
|
|
|
ImpCastExprToType(LHS, compositeType);
|
|
|
|
ImpCastExprToType(RHS, compositeType);
|
2008-09-12 07:12:46 +08:00
|
|
|
return compositeType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-07 06:42:25 +08:00
|
|
|
// Otherwise, the operands are not compatible.
|
2009-02-18 12:28:32 +08:00
|
|
|
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
|
|
|
|
<< LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
|
2007-05-17 03:47:19 +08:00
|
|
|
return QualType();
|
2007-05-16 04:29:32 +08:00
|
|
|
}
|
|
|
|
|
2007-09-16 11:34:24 +08:00
|
|
|
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
|
2006-11-10 13:29:30 +08:00
|
|
|
/// in the case of a the GNU conditional expr extension.
|
2009-01-20 06:31:54 +08:00
|
|
|
Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
|
|
|
|
SourceLocation ColonLoc,
|
|
|
|
ExprArg Cond, ExprArg LHS,
|
|
|
|
ExprArg RHS) {
|
|
|
|
Expr *CondExpr = (Expr *) Cond.get();
|
|
|
|
Expr *LHSExpr = (Expr *) LHS.get(), *RHSExpr = (Expr *) RHS.get();
|
2007-11-26 09:40:58 +08:00
|
|
|
|
|
|
|
// If this is the gnu "x ?: y" extension, analyze the types as though the LHS
|
|
|
|
// was the condition.
|
|
|
|
bool isLHSNull = LHSExpr == 0;
|
|
|
|
if (isLHSNull)
|
|
|
|
LHSExpr = CondExpr;
|
2009-01-20 06:31:54 +08:00
|
|
|
|
|
|
|
QualType result = CheckConditionalOperands(CondExpr, LHSExpr,
|
2007-07-17 05:39:03 +08:00
|
|
|
RHSExpr, QuestionLoc);
|
2007-05-16 04:29:32 +08:00
|
|
|
if (result.isNull())
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
Cond.release();
|
|
|
|
LHS.release();
|
|
|
|
RHS.release();
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) ConditionalOperator(CondExpr,
|
2009-01-21 08:14:39 +08:00
|
|
|
isLHSNull ? 0 : LHSExpr,
|
|
|
|
RHSExpr, result));
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2007-03-24 06:27:02 +08:00
|
|
|
|
2007-05-12 06:18:03 +08:00
|
|
|
// CheckPointerTypesForAssignment - This is a very tricky routine (despite
|
2009-02-19 11:04:26 +08:00
|
|
|
// being closely modeled after the C99 spec:-). The odd characteristic of this
|
2007-05-12 06:18:03 +08:00
|
|
|
// routine is it effectively iqnores the qualifiers on the top level pointee.
|
|
|
|
// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
|
|
|
|
// FIXME: add a couple examples in this comment.
|
2009-02-19 11:04:26 +08:00
|
|
|
Sema::AssignConvertType
|
2007-06-07 02:38:38 +08:00
|
|
|
Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
|
2007-05-12 06:18:03 +08:00
|
|
|
QualType lhptee, rhptee;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-05-11 12:00:31 +08:00
|
|
|
// get the "pointed to" type (ignoring qualifiers at the top level)
|
2007-08-01 05:27:01 +08:00
|
|
|
lhptee = lhsType->getAsPointerType()->getPointeeType();
|
|
|
|
rhptee = rhsType->getAsPointerType()->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-05-11 12:00:31 +08:00
|
|
|
// make sure we operate on the canonical type
|
2008-07-27 06:17:49 +08:00
|
|
|
lhptee = Context.getCanonicalType(lhptee);
|
|
|
|
rhptee = Context.getCanonicalType(rhptee);
|
2007-05-12 06:18:03 +08:00
|
|
|
|
2008-01-05 02:04:52 +08:00
|
|
|
AssignConvertType ConvTy = Compatible;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
|
|
|
// C99 6.5.16.1p1: This following citation is common to constraints
|
|
|
|
// 3 & 4 (below). ...and the type *pointed to* by the left has all the
|
|
|
|
// qualifiers of the type *pointed to* by the right;
|
2009-02-18 02:27:45 +08:00
|
|
|
// FIXME: Handle ExtQualType
|
2008-10-22 07:43:52 +08:00
|
|
|
if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
|
2008-01-05 02:04:52 +08:00
|
|
|
ConvTy = CompatiblePointerDiscardsQualifiers;
|
2007-05-12 06:18:03 +08:00
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
// C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or
|
|
|
|
// incomplete type and the other is a pointer to a qualified or unqualified
|
2007-05-12 06:18:03 +08:00
|
|
|
// version of void...
|
2008-01-04 06:56:36 +08:00
|
|
|
if (lhptee->isVoidType()) {
|
2008-04-02 14:59:01 +08:00
|
|
|
if (rhptee->isIncompleteOrObjectType())
|
2008-01-05 02:04:52 +08:00
|
|
|
return ConvTy;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-01-04 06:56:36 +08:00
|
|
|
// As an extension, we allow cast to/from void* to function pointer.
|
2008-04-02 14:59:01 +08:00
|
|
|
assert(rhptee->isFunctionType());
|
|
|
|
return FunctionVoidPointer;
|
2008-01-04 06:56:36 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-01-04 06:56:36 +08:00
|
|
|
if (rhptee->isVoidType()) {
|
2008-04-02 14:59:01 +08:00
|
|
|
if (lhptee->isIncompleteOrObjectType())
|
2008-01-05 02:04:52 +08:00
|
|
|
return ConvTy;
|
2008-01-04 06:56:36 +08:00
|
|
|
|
|
|
|
// As an extension, we allow cast to/from void* to function pointer.
|
2008-04-02 14:59:01 +08:00
|
|
|
assert(lhptee->isFunctionType());
|
|
|
|
return FunctionVoidPointer;
|
2008-01-04 06:56:36 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
|
2007-05-12 06:18:03 +08:00
|
|
|
// unqualified versions of compatible types, ...
|
2009-02-19 11:04:26 +08:00
|
|
|
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
|
2008-01-04 06:56:36 +08:00
|
|
|
rhptee.getUnqualifiedType()))
|
|
|
|
return IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
|
2008-01-05 02:04:52 +08:00
|
|
|
return ConvTy;
|
2007-05-11 12:00:31 +08:00
|
|
|
}
|
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
/// CheckBlockPointerTypesForAssignment - This routine determines whether two
|
|
|
|
/// block pointer types are compatible or whether a block and normal pointer
|
|
|
|
/// are compatible. It is more restrict than comparing two function pointer
|
|
|
|
// types.
|
2009-02-19 11:04:26 +08:00
|
|
|
Sema::AssignConvertType
|
|
|
|
Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
|
2008-09-04 23:10:53 +08:00
|
|
|
QualType rhsType) {
|
|
|
|
QualType lhptee, rhptee;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
// get the "pointed to" type (ignoring qualifiers at the top level)
|
|
|
|
lhptee = lhsType->getAsBlockPointerType()->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
rhptee = rhsType->getAsBlockPointerType()->getPointeeType();
|
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
// make sure we operate on the canonical type
|
|
|
|
lhptee = Context.getCanonicalType(lhptee);
|
|
|
|
rhptee = Context.getCanonicalType(rhptee);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
AssignConvertType ConvTy = Compatible;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
// For blocks we enforce that qualifiers are identical.
|
|
|
|
if (lhptee.getCVRQualifiers() != rhptee.getCVRQualifiers())
|
|
|
|
ConvTy = CompatiblePointerDiscardsQualifiers;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
if (!Context.typesAreBlockCompatible(lhptee, rhptee))
|
2009-02-19 11:04:26 +08:00
|
|
|
return IncompatibleBlockPointer;
|
2008-09-04 23:10:53 +08:00
|
|
|
return ConvTy;
|
|
|
|
}
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
|
|
|
|
/// has code to accommodate several GCC extensions when type checking
|
2007-05-04 05:03:48 +08:00
|
|
|
/// pointers. Here are some objectionable examples that GCC considers warnings:
|
|
|
|
///
|
|
|
|
/// int a, *pint;
|
|
|
|
/// short *pshort;
|
|
|
|
/// struct foo *pfoo;
|
|
|
|
///
|
|
|
|
/// pint = pshort; // warning: assignment from incompatible pointer type
|
|
|
|
/// a = pint; // warning: assignment makes integer from pointer without a cast
|
|
|
|
/// pint = a; // warning: assignment makes pointer from integer without a cast
|
|
|
|
/// pint = pfoo; // warning: assignment from incompatible pointer type
|
|
|
|
///
|
|
|
|
/// As a result, the code for dealing with pointers is more complex than the
|
2009-02-19 11:04:26 +08:00
|
|
|
/// C99 spec dictates.
|
2007-05-04 05:03:48 +08:00
|
|
|
///
|
2008-01-05 02:04:52 +08:00
|
|
|
Sema::AssignConvertType
|
2007-06-07 02:38:38 +08:00
|
|
|
Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
2008-01-05 07:18:45 +08:00
|
|
|
// Get canonical types. We're not formatting these types, just comparing
|
|
|
|
// them.
|
2008-07-27 06:17:49 +08:00
|
|
|
lhsType = Context.getCanonicalType(lhsType).getUnqualifiedType();
|
|
|
|
rhsType = Context.getCanonicalType(rhsType).getUnqualifiedType();
|
2008-05-31 02:07:22 +08:00
|
|
|
|
|
|
|
if (lhsType == rhsType)
|
2008-01-08 01:51:46 +08:00
|
|
|
return Compatible; // Common case: fast path an exact match.
|
2007-07-25 05:46:40 +08:00
|
|
|
|
2008-10-28 08:22:11 +08:00
|
|
|
// If the left-hand side is a reference type, then we are in a
|
|
|
|
// (rare!) case where we've allowed the use of references in C,
|
|
|
|
// e.g., as a parameter type in a built-in function. In this case,
|
|
|
|
// just make sure that the type referenced is compatible with the
|
|
|
|
// right-hand side type. The caller is responsible for adjusting
|
|
|
|
// lhsType so that the resulting expression does not have reference
|
|
|
|
// type.
|
|
|
|
if (const ReferenceType *lhsTypeRef = lhsType->getAsReferenceType()) {
|
|
|
|
if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType))
|
2007-10-13 07:56:29 +08:00
|
|
|
return Compatible;
|
2008-01-05 07:18:45 +08:00
|
|
|
return Incompatible;
|
2007-12-20 01:45:58 +08:00
|
|
|
}
|
2008-05-31 02:07:22 +08:00
|
|
|
|
2008-04-07 13:30:13 +08:00
|
|
|
if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
|
|
|
|
if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
|
2007-12-20 01:45:58 +08:00
|
|
|
return Compatible;
|
2008-06-03 22:04:54 +08:00
|
|
|
// Relax integer conversions like we do for pointers below.
|
|
|
|
if (rhsType->isIntegerType())
|
|
|
|
return IntToPointer;
|
|
|
|
if (lhsType->isIntegerType())
|
|
|
|
return PointerToInt;
|
2008-10-15 06:18:38 +08:00
|
|
|
return IncompatibleObjCQualifiedId;
|
2007-12-20 01:45:58 +08:00
|
|
|
}
|
2008-01-05 07:32:24 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
if (lhsType->isVectorType() || rhsType->isVectorType()) {
|
2008-04-19 07:10:10 +08:00
|
|
|
// For ExtVector, allow vector splats; float -> <n x float>
|
2008-07-15 02:02:46 +08:00
|
|
|
if (const ExtVectorType *LV = lhsType->getAsExtVectorType())
|
|
|
|
if (LV->getElementType() == rhsType)
|
2008-01-05 07:32:24 +08:00
|
|
|
return Compatible;
|
2008-05-31 02:07:22 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
// If we are allowing lax vector conversions, and LHS and RHS are both
|
2009-02-19 11:04:26 +08:00
|
|
|
// vectors, the total size only needs to be the same. This is a bitcast;
|
2008-07-15 02:02:46 +08:00
|
|
|
// no bits are changed but the result type is different.
|
2008-01-05 07:32:24 +08:00
|
|
|
if (getLangOptions().LaxVectorConversions &&
|
|
|
|
lhsType->isVectorType() && rhsType->isVectorType()) {
|
2008-07-15 02:02:46 +08:00
|
|
|
if (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))
|
2009-01-31 07:17:46 +08:00
|
|
|
return IncompatibleVectors;
|
2008-01-05 07:32:24 +08:00
|
|
|
}
|
|
|
|
return Incompatible;
|
2009-02-19 11:04:26 +08:00
|
|
|
}
|
2008-05-31 02:07:22 +08:00
|
|
|
|
2008-01-05 07:32:24 +08:00
|
|
|
if (lhsType->isArithmeticType() && rhsType->isArithmeticType())
|
2007-06-07 02:38:38 +08:00
|
|
|
return Compatible;
|
2008-05-31 02:07:22 +08:00
|
|
|
|
2008-04-07 14:49:41 +08:00
|
|
|
if (isa<PointerType>(lhsType)) {
|
2007-06-07 02:38:38 +08:00
|
|
|
if (rhsType->isIntegerType())
|
2008-01-05 02:22:42 +08:00
|
|
|
return IntToPointer;
|
2008-05-31 02:07:22 +08:00
|
|
|
|
2008-04-07 14:49:41 +08:00
|
|
|
if (isa<PointerType>(rhsType))
|
2007-06-07 02:38:38 +08:00
|
|
|
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-30 02:10:17 +08:00
|
|
|
if (rhsType->getAsBlockPointerType()) {
|
2008-09-06 06:11:13 +08:00
|
|
|
if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
|
2008-11-27 08:44:28 +08:00
|
|
|
return Compatible;
|
2008-09-30 02:10:17 +08:00
|
|
|
|
|
|
|
// Treat block pointers as objects.
|
|
|
|
if (getLangOptions().ObjC1 &&
|
|
|
|
lhsType == Context.getCanonicalType(Context.getObjCIdType()))
|
|
|
|
return Compatible;
|
|
|
|
}
|
2008-09-04 23:10:53 +08:00
|
|
|
return Incompatible;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isa<BlockPointerType>(lhsType)) {
|
|
|
|
if (rhsType->isIntegerType())
|
2009-02-25 12:20:42 +08:00
|
|
|
return IntToBlockPointer;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-30 02:10:17 +08:00
|
|
|
// Treat block pointers as objects.
|
|
|
|
if (getLangOptions().ObjC1 &&
|
|
|
|
rhsType == Context.getCanonicalType(Context.getObjCIdType()))
|
|
|
|
return Compatible;
|
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
if (rhsType->isBlockPointerType())
|
|
|
|
return CheckBlockPointerTypesForAssignment(lhsType, rhsType);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
|
|
|
|
if (RHSPT->getPointeeType()->isVoidType())
|
2008-11-27 08:44:28 +08:00
|
|
|
return Compatible;
|
2008-09-04 23:10:53 +08:00
|
|
|
}
|
2008-01-05 07:18:45 +08:00
|
|
|
return Incompatible;
|
|
|
|
}
|
|
|
|
|
2008-04-07 14:49:41 +08:00
|
|
|
if (isa<PointerType>(rhsType)) {
|
2007-06-07 02:38:38 +08:00
|
|
|
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
|
2008-05-31 02:07:22 +08:00
|
|
|
if (lhsType == Context.BoolTy)
|
|
|
|
return Compatible;
|
|
|
|
|
|
|
|
if (lhsType->isIntegerType())
|
2008-01-05 02:22:42 +08:00
|
|
|
return PointerToInt;
|
2007-06-07 02:38:38 +08:00
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
if (isa<PointerType>(lhsType))
|
2007-06-07 02:38:38 +08:00
|
|
|
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
|
|
|
if (isa<BlockPointerType>(lhsType) &&
|
2008-09-04 23:10:53 +08:00
|
|
|
rhsType->getAsPointerType()->getPointeeType()->isVoidType())
|
2008-11-27 08:44:28 +08:00
|
|
|
return Compatible;
|
2008-01-05 07:18:45 +08:00
|
|
|
return Incompatible;
|
|
|
|
}
|
2008-05-31 02:07:22 +08:00
|
|
|
|
2008-01-05 07:18:45 +08:00
|
|
|
if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
|
2008-04-07 14:49:41 +08:00
|
|
|
if (Context.typesAreCompatible(lhsType, rhsType))
|
2007-06-07 02:38:38 +08:00
|
|
|
return Compatible;
|
2007-05-30 14:30:29 +08:00
|
|
|
}
|
2007-06-07 02:38:38 +08:00
|
|
|
return Incompatible;
|
2007-05-03 05:58:15 +08:00
|
|
|
}
|
|
|
|
|
2008-01-05 02:04:52 +08:00
|
|
|
Sema::AssignConvertType
|
2007-07-14 07:32:42 +08:00
|
|
|
Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
|
2008-10-22 07:43:52 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
if (!lhsType->isRecordType()) {
|
|
|
|
// C++ 5.17p3: If the left operand is not of class type, the
|
|
|
|
// expression is implicitly converted (C++ 4) to the
|
|
|
|
// cv-unqualified type of the left operand.
|
2008-12-20 01:40:08 +08:00
|
|
|
if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(),
|
|
|
|
"assigning"))
|
2008-10-22 07:43:52 +08:00
|
|
|
return Incompatible;
|
2008-10-24 12:54:22 +08:00
|
|
|
else
|
2008-10-22 07:43:52 +08:00
|
|
|
return Compatible;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Currently, we fall through and treat C++ classes like C
|
|
|
|
// structures.
|
|
|
|
}
|
|
|
|
|
2007-11-28 01:58:44 +08:00
|
|
|
// C99 6.5.16.1p1: the left operand is a pointer and the right is
|
|
|
|
// a null pointer constant.
|
2009-02-22 05:17:01 +08:00
|
|
|
if ((lhsType->isPointerType() ||
|
|
|
|
lhsType->isObjCQualifiedIdType() ||
|
2009-02-19 11:04:26 +08:00
|
|
|
lhsType->isBlockPointerType())
|
2008-01-04 02:46:52 +08:00
|
|
|
&& rExpr->isNullPointerConstant(Context)) {
|
2008-01-17 03:17:22 +08:00
|
|
|
ImpCastExprToType(rExpr, lhsType);
|
2007-11-28 01:58:44 +08:00
|
|
|
return Compatible;
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-10-16 10:55:40 +08:00
|
|
|
// This check seems unnatural, however it is necessary to ensure the proper
|
2007-07-14 07:32:42 +08:00
|
|
|
// conversion of functions/arrays. If the conversion were done for all
|
2007-09-16 02:49:24 +08:00
|
|
|
// DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary
|
2007-07-14 07:32:42 +08:00
|
|
|
// expressions that surpress this implicit conversion (&, sizeof).
|
2007-10-16 10:55:40 +08:00
|
|
|
//
|
2009-02-19 11:04:26 +08:00
|
|
|
// Suppress this for references: C++ 8.5.3p5.
|
2007-10-16 10:55:40 +08:00
|
|
|
if (!lhsType->isReferenceType())
|
|
|
|
DefaultFunctionArrayConversion(rExpr);
|
2007-08-25 06:33:52 +08:00
|
|
|
|
2008-01-05 02:04:52 +08:00
|
|
|
Sema::AssignConvertType result =
|
|
|
|
CheckAssignmentConstraints(lhsType, rExpr->getType());
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-25 06:33:52 +08:00
|
|
|
// C99 6.5.16.1p2: The value of the right operand is converted to the
|
|
|
|
// type of the assignment expression.
|
2008-10-28 08:22:11 +08:00
|
|
|
// CheckAssignmentConstraints allows the left-hand side to be a reference,
|
|
|
|
// so that we can use references in built-in functions even in C.
|
|
|
|
// The getNonReferenceType() call makes sure that the resulting expression
|
|
|
|
// does not have reference type.
|
2007-08-25 06:33:52 +08:00
|
|
|
if (rExpr->getType() != lhsType)
|
2008-10-28 08:22:11 +08:00
|
|
|
ImpCastExprToType(rExpr, lhsType.getNonReferenceType());
|
2007-08-25 06:33:52 +08:00
|
|
|
return result;
|
2007-07-14 07:32:42 +08:00
|
|
|
}
|
|
|
|
|
2008-01-05 02:04:52 +08:00
|
|
|
Sema::AssignConvertType
|
2007-07-14 07:32:42 +08:00
|
|
|
Sema::CheckCompoundAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
|
|
|
return CheckAssignmentConstraints(lhsType, rhsType);
|
|
|
|
}
|
|
|
|
|
2008-11-18 09:30:42 +08:00
|
|
|
QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::err_typecheck_invalid_operands)
|
2008-11-23 17:13:29 +08:00
|
|
|
<< lex->getType() << rex->getType()
|
2008-11-19 06:52:51 +08:00
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2007-12-12 13:47:28 +08:00
|
|
|
return QualType();
|
2007-05-29 22:23:36 +08:00
|
|
|
}
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
|
2007-07-14 00:58:59 +08:00
|
|
|
Expr *&rex) {
|
2009-02-19 11:04:26 +08:00
|
|
|
// For conversion purposes, we ignore any qualifiers.
|
2008-04-04 09:30:25 +08:00
|
|
|
// For example, "const float" and "float" are equivalent.
|
2008-07-27 06:17:49 +08:00
|
|
|
QualType lhsType =
|
|
|
|
Context.getCanonicalType(lex->getType()).getUnqualifiedType();
|
|
|
|
QualType rhsType =
|
|
|
|
Context.getCanonicalType(rex->getType()).getUnqualifiedType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
// If the vector types are identical, return.
|
2008-04-04 09:30:25 +08:00
|
|
|
if (lhsType == rhsType)
|
2007-07-10 05:31:10 +08:00
|
|
|
return lhsType;
|
2007-12-30 10:59:45 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
// Handle the case of a vector & extvector type of the same size and element
|
|
|
|
// type. It would be nice if we only had one vector type someday.
|
2009-01-31 07:17:46 +08:00
|
|
|
if (getLangOptions().LaxVectorConversions) {
|
|
|
|
// FIXME: Should we warn here?
|
|
|
|
if (const VectorType *LV = lhsType->getAsVectorType()) {
|
2008-07-15 02:02:46 +08:00
|
|
|
if (const VectorType *RV = rhsType->getAsVectorType())
|
|
|
|
if (LV->getElementType() == RV->getElementType() &&
|
2009-01-31 07:17:46 +08:00
|
|
|
LV->getNumElements() == RV->getNumElements()) {
|
2008-07-15 02:02:46 +08:00
|
|
|
return lhsType->isExtVectorType() ? lhsType : rhsType;
|
2009-01-31 07:17:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
// If the lhs is an extended vector and the rhs is a scalar of the same type
|
|
|
|
// or a literal, promote the rhs to the vector type.
|
2008-04-19 07:10:10 +08:00
|
|
|
if (const ExtVectorType *V = lhsType->getAsExtVectorType()) {
|
2008-07-15 02:02:46 +08:00
|
|
|
QualType eltType = V->getElementType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
|
|
|
if ((eltType->getAsBuiltinType() == rhsType->getAsBuiltinType()) ||
|
2008-07-15 02:02:46 +08:00
|
|
|
(eltType->isIntegerType() && isa<IntegerLiteral>(rex)) ||
|
|
|
|
(eltType->isFloatingType() && isa<FloatingLiteral>(rex))) {
|
2008-01-17 03:17:22 +08:00
|
|
|
ImpCastExprToType(rex, lhsType);
|
2007-12-30 10:59:45 +08:00
|
|
|
return lhsType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
// If the rhs is an extended vector and the lhs is a scalar of the same type,
|
2007-12-30 10:59:45 +08:00
|
|
|
// promote the lhs to the vector type.
|
2008-04-19 07:10:10 +08:00
|
|
|
if (const ExtVectorType *V = rhsType->getAsExtVectorType()) {
|
2008-07-15 02:02:46 +08:00
|
|
|
QualType eltType = V->getElementType();
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
if ((eltType->getAsBuiltinType() == lhsType->getAsBuiltinType()) ||
|
2008-07-15 02:02:46 +08:00
|
|
|
(eltType->isIntegerType() && isa<IntegerLiteral>(lex)) ||
|
|
|
|
(eltType->isFloatingType() && isa<FloatingLiteral>(lex))) {
|
2008-01-17 03:17:22 +08:00
|
|
|
ImpCastExprToType(lex, rhsType);
|
2007-12-30 10:59:45 +08:00
|
|
|
return rhsType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-10 05:31:10 +08:00
|
|
|
// You cannot convert between vector values of different size.
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::err_typecheck_vector_not_convertable)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lex->getType() << rex->getType()
|
2008-11-19 06:52:51 +08:00
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2007-07-10 05:31:10 +08:00
|
|
|
return QualType();
|
2009-02-07 08:15:38 +08:00
|
|
|
}
|
|
|
|
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
inline QualType Sema::CheckMultiplyDivideOperands(
|
2009-02-19 11:04:26 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
|
2007-04-21 07:42:24 +08:00
|
|
|
{
|
2009-01-06 06:42:10 +08:00
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
|
2008-11-18 09:30:42 +08:00
|
|
|
return CheckVectorOperands(Loc, lex, rex);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-25 03:07:16 +08:00
|
|
|
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-07-17 08:58:39 +08:00
|
|
|
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
|
2007-08-25 03:07:16 +08:00
|
|
|
return compType;
|
2008-11-18 09:30:42 +08:00
|
|
|
return InvalidOperands(Loc, lex, rex);
|
2007-03-31 07:47:58 +08:00
|
|
|
}
|
|
|
|
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
inline QualType Sema::CheckRemainderOperands(
|
2009-02-19 11:04:26 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
{
|
2009-01-06 06:55:36 +08:00
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
|
|
|
|
if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
|
|
|
|
return CheckVectorOperands(Loc, lex, rex);
|
|
|
|
return InvalidOperands(Loc, lex, rex);
|
|
|
|
}
|
2007-07-14 07:32:42 +08:00
|
|
|
|
2007-08-25 03:07:16 +08:00
|
|
|
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-07-17 08:58:39 +08:00
|
|
|
if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
|
2007-08-25 03:07:16 +08:00
|
|
|
return compType;
|
2008-11-18 09:30:42 +08:00
|
|
|
return InvalidOperands(Loc, lex, rex);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
|
2009-02-19 11:04:26 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
|
2007-04-24 08:23:05 +08:00
|
|
|
{
|
2007-07-17 06:23:01 +08:00
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
|
2008-11-18 09:30:42 +08:00
|
|
|
return CheckVectorOperands(Loc, lex, rex);
|
2007-07-14 00:58:59 +08:00
|
|
|
|
2007-08-25 03:07:16 +08:00
|
|
|
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
|
2008-05-19 02:08:51 +08:00
|
|
|
|
2007-04-28 02:30:00 +08:00
|
|
|
// handle the common case first (both operands are arithmetic).
|
2007-07-17 08:58:39 +08:00
|
|
|
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
|
2007-08-25 03:07:16 +08:00
|
|
|
return compType;
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
|
2008-05-19 02:08:51 +08:00
|
|
|
// Put any potential pointer into PExp
|
|
|
|
Expr* PExp = lex, *IExp = rex;
|
|
|
|
if (IExp->getType()->isPointerType())
|
|
|
|
std::swap(PExp, IExp);
|
|
|
|
|
|
|
|
if (const PointerType* PTy = PExp->getType()->getAsPointerType()) {
|
|
|
|
if (IExp->getType()->isIntegerType()) {
|
|
|
|
// Check for arithmetic on pointers to incomplete types
|
|
|
|
if (!PTy->getPointeeType()->isObjectType()) {
|
|
|
|
if (PTy->getPointeeType()->isVoidType()) {
|
2009-01-23 08:36:41 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// GNU extension: arithmetic on pointer to void
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(Loc, diag::ext_gnu_void_ptr)
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2009-01-20 03:26:10 +08:00
|
|
|
} else if (PTy->getPointeeType()->isFunctionType()) {
|
2009-01-23 08:36:41 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
|
|
|
|
<< lex->getType() << lex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// GNU extension: arithmetic on pointer to function
|
|
|
|
Diag(Loc, diag::ext_gnu_ptr_func_arith)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lex->getType() << lex->getSourceRange();
|
2009-01-20 03:26:10 +08:00
|
|
|
} else {
|
2009-02-19 11:04:26 +08:00
|
|
|
DiagnoseIncompleteType(Loc, PTy->getPointeeType(),
|
2009-01-20 03:26:10 +08:00
|
|
|
diag::err_typecheck_arithmetic_incomplete_type,
|
|
|
|
lex->getSourceRange(), SourceRange(),
|
|
|
|
lex->getType());
|
|
|
|
return QualType();
|
2008-05-19 02:08:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return PExp->getType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-18 09:30:42 +08:00
|
|
|
return InvalidOperands(Loc, lex, rex);
|
2007-03-22 05:08:52 +08:00
|
|
|
}
|
|
|
|
|
2008-04-07 13:30:13 +08:00
|
|
|
// C99 6.5.6
|
|
|
|
QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
|
2008-11-18 09:30:42 +08:00
|
|
|
SourceLocation Loc, bool isCompAssign) {
|
2007-07-17 06:23:01 +08:00
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
|
2008-11-18 09:30:42 +08:00
|
|
|
return CheckVectorOperands(Loc, lex, rex);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-25 03:07:16 +08:00
|
|
|
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// Enforce type constraints: C99 6.5.6p3.
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// Handle the common case first (both operands are arithmetic).
|
2007-07-17 08:58:39 +08:00
|
|
|
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
|
2007-08-25 03:07:16 +08:00
|
|
|
return compType;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// Either ptr - int or ptr - ptr.
|
|
|
|
if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
|
2008-01-30 02:58:14 +08:00
|
|
|
QualType lpointee = LHSPTy->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// The LHS must be an object type, not incomplete, function, etc.
|
2008-01-30 02:58:14 +08:00
|
|
|
if (!lpointee->isObjectType()) {
|
2007-12-10 05:53:25 +08:00
|
|
|
// Handle the GNU void* extension.
|
2008-01-30 02:58:14 +08:00
|
|
|
if (lpointee->isVoidType()) {
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(Loc, diag::ext_gnu_void_ptr)
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2009-01-23 08:36:41 +08:00
|
|
|
} else if (lpointee->isFunctionType()) {
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
|
|
|
|
<< lex->getType() << lex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// GNU extension: arithmetic on pointer to function
|
|
|
|
Diag(Loc, diag::ext_gnu_ptr_func_arith)
|
|
|
|
<< lex->getType() << lex->getSourceRange();
|
2007-12-10 05:53:25 +08:00
|
|
|
} else {
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(Loc, diag::err_typecheck_sub_ptr_object)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lex->getType() << lex->getSourceRange();
|
2007-12-10 05:53:25 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The result type of a pointer-int computation is the pointer type.
|
|
|
|
if (rex->getType()->isIntegerType())
|
|
|
|
return lex->getType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// Handle pointer-pointer subtractions.
|
|
|
|
if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) {
|
2008-02-08 09:19:44 +08:00
|
|
|
QualType rpointee = RHSPTy->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// RHS must be an object type, unless void (GNU).
|
2008-01-30 02:58:14 +08:00
|
|
|
if (!rpointee->isObjectType()) {
|
2007-12-10 05:53:25 +08:00
|
|
|
// Handle the GNU void* extension.
|
2008-01-30 02:58:14 +08:00
|
|
|
if (rpointee->isVoidType()) {
|
|
|
|
if (!lpointee->isVoidType())
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(Loc, diag::ext_gnu_void_ptr)
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2009-01-24 03:03:35 +08:00
|
|
|
} else if (rpointee->isFunctionType()) {
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
|
|
|
|
<< rex->getType() << rex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-01-24 03:03:35 +08:00
|
|
|
// GNU extension: arithmetic on pointer to function
|
|
|
|
if (!lpointee->isFunctionType())
|
|
|
|
Diag(Loc, diag::ext_gnu_ptr_func_arith)
|
|
|
|
<< lex->getType() << lex->getSourceRange();
|
2007-12-10 05:53:25 +08:00
|
|
|
} else {
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(Loc, diag::err_typecheck_sub_ptr_object)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< rex->getType() << rex->getSourceRange();
|
2007-12-10 05:53:25 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// Pointee types must be compatible.
|
2008-09-02 13:09:35 +08:00
|
|
|
if (!Context.typesAreCompatible(
|
2009-02-19 11:04:26 +08:00
|
|
|
Context.getCanonicalType(lpointee).getUnqualifiedType(),
|
2008-09-02 13:09:35 +08:00
|
|
|
Context.getCanonicalType(rpointee).getUnqualifiedType())) {
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lex->getType() << rex->getType()
|
2008-11-19 06:52:51 +08:00
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2007-12-10 05:53:25 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
return Context.getPointerDiffType();
|
|
|
|
}
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-11-18 09:30:42 +08:00
|
|
|
return InvalidOperands(Loc, lex, rex);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
}
|
2007-04-24 08:23:05 +08:00
|
|
|
|
2008-04-07 13:30:13 +08:00
|
|
|
// C99 6.5.7
|
2008-11-18 09:30:42 +08:00
|
|
|
QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
|
2008-04-07 13:30:13 +08:00
|
|
|
bool isCompAssign) {
|
2007-12-12 13:47:28 +08:00
|
|
|
// C99 6.5.7p2: Each of the operands shall have integer type.
|
|
|
|
if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType())
|
2008-11-18 09:30:42 +08:00
|
|
|
return InvalidOperands(Loc, lex, rex);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-12 13:47:28 +08:00
|
|
|
// Shifts don't perform usual arithmetic conversions, they just do integer
|
|
|
|
// promotions on each operand. C99 6.5.7p3
|
2007-12-13 15:28:16 +08:00
|
|
|
if (!isCompAssign)
|
|
|
|
UsualUnaryConversions(lex);
|
2007-12-12 13:47:28 +08:00
|
|
|
UsualUnaryConversions(rex);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-12 13:47:28 +08:00
|
|
|
// "The type of the result is that of the promoted left operand."
|
|
|
|
return lex->getType();
|
2007-03-22 05:08:52 +08:00
|
|
|
}
|
|
|
|
|
2008-04-07 13:30:13 +08:00
|
|
|
// C99 6.5.8
|
2008-11-18 09:30:42 +08:00
|
|
|
QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
|
2008-04-07 13:30:13 +08:00
|
|
|
bool isRelational) {
|
2008-07-15 02:02:46 +08:00
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
|
2008-11-18 09:30:42 +08:00
|
|
|
return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-26 09:18:55 +08:00
|
|
|
// C99 6.5.8p3 / C99 6.5.9p4
|
2007-08-11 02:26:40 +08:00
|
|
|
if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
|
|
|
|
UsualArithmeticConversions(lex, rex);
|
|
|
|
else {
|
|
|
|
UsualUnaryConversions(lex);
|
|
|
|
UsualUnaryConversions(rex);
|
|
|
|
}
|
2007-07-17 05:54:35 +08:00
|
|
|
QualType lType = lex->getType();
|
|
|
|
QualType rType = rex->getType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-10-30 01:13:39 +08:00
|
|
|
// For non-floating point types, check for self-comparisons of the form
|
|
|
|
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
|
|
|
|
// often indicate logic errors in the program.
|
2007-10-30 00:58:49 +08:00
|
|
|
if (!lType->isFloatingType()) {
|
2008-01-18 00:57:34 +08:00
|
|
|
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens()))
|
|
|
|
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens()))
|
2007-10-30 00:58:49 +08:00
|
|
|
if (DRL->getDecl() == DRR->getDecl())
|
2009-02-19 11:04:26 +08:00
|
|
|
Diag(Loc, diag::warn_selfcomparison);
|
2007-10-30 00:58:49 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-11-19 11:25:36 +08:00
|
|
|
// The result of comparisons is 'bool' in C++, 'int' in C.
|
|
|
|
QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy : Context.IntTy;
|
|
|
|
|
2007-08-26 09:18:55 +08:00
|
|
|
if (isRelational) {
|
|
|
|
if (lType->isRealType() && rType->isRealType())
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2007-08-26 09:18:55 +08:00
|
|
|
} else {
|
2007-10-30 01:13:39 +08:00
|
|
|
// Check for comparisons of floating point operands using != and ==.
|
|
|
|
if (lType->isFloatingType()) {
|
|
|
|
assert (rType->isFloatingType());
|
2008-11-18 09:30:42 +08:00
|
|
|
CheckFloatComparison(Loc,lex,rex);
|
2007-10-30 00:40:01 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-26 09:18:55 +08:00
|
|
|
if (lType->isArithmeticType() && rType->isArithmeticType())
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2007-08-26 09:18:55 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-26 09:10:14 +08:00
|
|
|
bool LHSIsNull = lex->isNullPointerConstant(Context);
|
|
|
|
bool RHSIsNull = rex->isNullPointerConstant(Context);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-26 09:18:55 +08:00
|
|
|
// All of the following pointer related warnings are GCC extensions, except
|
|
|
|
// when handling null pointer constants. One day, we can consider making them
|
|
|
|
// errors (when -pedantic-errors is enabled).
|
2007-08-27 12:08:11 +08:00
|
|
|
if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2
|
2008-04-03 13:07:25 +08:00
|
|
|
QualType LCanPointeeTy =
|
2008-07-27 06:17:49 +08:00
|
|
|
Context.getCanonicalType(lType->getAsPointerType()->getPointeeType());
|
2008-04-03 13:07:25 +08:00
|
|
|
QualType RCanPointeeTy =
|
2008-07-27 06:17:49 +08:00
|
|
|
Context.getCanonicalType(rType->getAsPointerType()->getPointeeType());
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-11-13 22:57:38 +08:00
|
|
|
if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2
|
2008-04-03 13:07:25 +08:00
|
|
|
!LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() &&
|
|
|
|
!Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
|
2008-08-22 08:56:42 +08:00
|
|
|
RCanPointeeTy.getUnqualifiedType()) &&
|
2009-02-13 01:52:19 +08:00
|
|
|
!Context.areComparableObjCPointerTypes(lType, rType)) {
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2007-06-14 05:41:08 +08:00
|
|
|
}
|
2008-01-17 03:17:22 +08:00
|
|
|
ImpCastExprToType(rex, lType); // promote the pointer to pointer
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2007-08-17 05:48:38 +08:00
|
|
|
}
|
2008-09-04 23:10:53 +08:00
|
|
|
// Handle block pointer types.
|
|
|
|
if (lType->isBlockPointerType() && rType->isBlockPointerType()) {
|
|
|
|
QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
|
|
|
|
QualType rpointee = rType->getAsBlockPointerType()->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
if (!LHSIsNull && !RHSIsNull &&
|
|
|
|
!Context.typesAreBlockCompatible(lpointee, rpointee)) {
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-09-28 09:11:11 +08:00
|
|
|
}
|
|
|
|
ImpCastExprToType(rex, lType); // promote the pointer to pointer
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-09-28 09:11:11 +08:00
|
|
|
}
|
|
|
|
// Allow block pointers to be compared with null pointer constants.
|
|
|
|
if ((lType->isBlockPointerType() && rType->isPointerType()) ||
|
|
|
|
(lType->isPointerType() && rType->isBlockPointerType())) {
|
|
|
|
if (!LHSIsNull && !RHSIsNull) {
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-09-04 23:10:53 +08:00
|
|
|
}
|
|
|
|
ImpCastExprToType(rex, lType); // promote the pointer to pointer
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-09-04 23:10:53 +08:00
|
|
|
}
|
|
|
|
|
2008-06-03 22:04:54 +08:00
|
|
|
if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
|
2008-10-27 18:33:19 +08:00
|
|
|
if (lType->isPointerType() || rType->isPointerType()) {
|
2008-11-18 03:49:16 +08:00
|
|
|
const PointerType *LPT = lType->getAsPointerType();
|
|
|
|
const PointerType *RPT = rType->getAsPointerType();
|
2009-02-19 11:04:26 +08:00
|
|
|
bool LPtrToVoid = LPT ?
|
2008-11-18 03:49:16 +08:00
|
|
|
Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false;
|
2009-02-19 11:04:26 +08:00
|
|
|
bool RPtrToVoid = RPT ?
|
2008-11-18 03:49:16 +08:00
|
|
|
Context.getCanonicalType(RPT->getPointeeType())->isVoidType() : false;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-11-18 03:49:16 +08:00
|
|
|
if (!LPtrToVoid && !RPtrToVoid &&
|
|
|
|
!Context.typesAreCompatible(lType, rType)) {
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-10-27 18:33:19 +08:00
|
|
|
ImpCastExprToType(rex, lType);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-10-27 18:33:19 +08:00
|
|
|
}
|
2008-10-24 07:30:52 +08:00
|
|
|
ImpCastExprToType(rex, lType);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-10-21 02:19:10 +08:00
|
|
|
}
|
2008-06-03 22:04:54 +08:00
|
|
|
if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
|
|
|
|
ImpCastExprToType(rex, lType);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-10-15 06:18:38 +08:00
|
|
|
} else {
|
|
|
|
if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) {
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::warn_incompatible_qualified_id_operands)
|
2008-11-24 13:29:24 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-10-24 07:30:52 +08:00
|
|
|
ImpCastExprToType(rex, lType);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-10-15 06:18:38 +08:00
|
|
|
}
|
2008-06-03 22:04:54 +08:00
|
|
|
}
|
2007-12-20 09:06:58 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) &&
|
2008-06-03 22:04:54 +08:00
|
|
|
rType->isIntegerType()) {
|
2007-08-26 09:10:14 +08:00
|
|
|
if (!RHSIsNull)
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-01-17 03:17:22 +08:00
|
|
|
ImpCastExprToType(rex, lType); // promote the integer to pointer
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2007-08-17 05:48:38 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
if (lType->isIntegerType() &&
|
2008-06-03 22:04:54 +08:00
|
|
|
(rType->isPointerType() || rType->isObjCQualifiedIdType())) {
|
2007-08-26 09:10:14 +08:00
|
|
|
if (!LHSIsNull)
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-01-17 03:17:22 +08:00
|
|
|
ImpCastExprToType(lex, rType); // promote the integer to pointer
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2007-05-15 10:32:35 +08:00
|
|
|
}
|
2008-09-05 00:56:14 +08:00
|
|
|
// Handle block pointers.
|
|
|
|
if (lType->isBlockPointerType() && rType->isIntegerType()) {
|
|
|
|
if (!RHSIsNull)
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-09-05 00:56:14 +08:00
|
|
|
ImpCastExprToType(rex, lType); // promote the integer to pointer
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-09-05 00:56:14 +08:00
|
|
|
}
|
|
|
|
if (lType->isIntegerType() && rType->isBlockPointerType()) {
|
|
|
|
if (!LHSIsNull)
|
2008-11-19 06:52:51 +08:00
|
|
|
Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-09-05 00:56:14 +08:00
|
|
|
ImpCastExprToType(lex, rType); // promote the integer to pointer
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-09-05 00:56:14 +08:00
|
|
|
}
|
2008-11-18 09:30:42 +08:00
|
|
|
return InvalidOperands(Loc, lex, rex);
|
2007-03-22 05:08:52 +08:00
|
|
|
}
|
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
/// CheckVectorCompareOperands - vector comparisons are a clang extension that
|
2009-02-19 11:04:26 +08:00
|
|
|
/// operates on extended vector types. Instead of producing an IntTy result,
|
2008-07-15 02:02:46 +08:00
|
|
|
/// like a scalar comparison, a vector comparison produces a vector of integer
|
|
|
|
/// types.
|
|
|
|
QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
|
2008-11-18 09:30:42 +08:00
|
|
|
SourceLocation Loc,
|
2008-07-15 02:02:46 +08:00
|
|
|
bool isRelational) {
|
|
|
|
// Check to make sure we're operating on vectors of the same type and width,
|
|
|
|
// Allowing one side to be a scalar of element type.
|
2008-11-18 09:30:42 +08:00
|
|
|
QualType vType = CheckVectorOperands(Loc, lex, rex);
|
2008-07-15 02:02:46 +08:00
|
|
|
if (vType.isNull())
|
|
|
|
return vType;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
QualType lType = lex->getType();
|
|
|
|
QualType rType = rex->getType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
// For non-floating point types, check for self-comparisons of the form
|
|
|
|
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
|
|
|
|
// often indicate logic errors in the program.
|
|
|
|
if (!lType->isFloatingType()) {
|
|
|
|
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens()))
|
|
|
|
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens()))
|
|
|
|
if (DRL->getDecl() == DRR->getDecl())
|
2009-02-19 11:04:26 +08:00
|
|
|
Diag(Loc, diag::warn_selfcomparison);
|
2008-07-15 02:02:46 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
// Check for comparisons of floating point operands using != and ==.
|
|
|
|
if (!isRelational && lType->isFloatingType()) {
|
|
|
|
assert (rType->isFloatingType());
|
2008-11-18 09:30:42 +08:00
|
|
|
CheckFloatComparison(Loc,lex,rex);
|
2008-07-15 02:02:46 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
// Return the type for the comparison, which is the same as vector type for
|
|
|
|
// integer vectors, or an integer type of identical size and number of
|
|
|
|
// elements for floating point vectors.
|
|
|
|
if (lType->isIntegerType())
|
|
|
|
return lType;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
const VectorType *VTy = lType->getAsVectorType();
|
|
|
|
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
|
2009-01-18 11:20:47 +08:00
|
|
|
if (TypeSize == Context.getTypeSize(Context.IntTy))
|
2008-07-15 02:02:46 +08:00
|
|
|
return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
|
2009-01-18 11:20:47 +08:00
|
|
|
else if (TypeSize == Context.getTypeSize(Context.LongTy))
|
|
|
|
return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
|
2009-01-18 11:20:47 +08:00
|
|
|
"Unhandled vector element size in vector compare");
|
2008-07-15 02:02:46 +08:00
|
|
|
return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
|
|
|
|
}
|
|
|
|
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
inline QualType Sema::CheckBitwiseOperands(
|
2009-02-19 11:04:26 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
|
2007-04-24 08:23:05 +08:00
|
|
|
{
|
2007-07-17 06:23:01 +08:00
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
|
2008-11-18 09:30:42 +08:00
|
|
|
return CheckVectorOperands(Loc, lex, rex);
|
2007-07-14 07:32:42 +08:00
|
|
|
|
2007-08-25 03:07:16 +08:00
|
|
|
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-07-17 08:58:39 +08:00
|
|
|
if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
|
2007-08-25 03:07:16 +08:00
|
|
|
return compType;
|
2008-11-18 09:30:42 +08:00
|
|
|
return InvalidOperands(Loc, lex, rex);
|
2007-03-22 05:08:52 +08:00
|
|
|
}
|
|
|
|
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
|
2009-02-19 11:04:26 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc)
|
2007-04-24 08:23:05 +08:00
|
|
|
{
|
2007-07-17 05:54:35 +08:00
|
|
|
UsualUnaryConversions(lex);
|
|
|
|
UsualUnaryConversions(rex);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-05-14 04:16:47 +08:00
|
|
|
if (lex->getType()->isScalarType() && rex->getType()->isScalarType())
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
return Context.IntTy;
|
2008-11-18 09:30:42 +08:00
|
|
|
return InvalidOperands(Loc, lex, rex);
|
2007-04-27 04:39:23 +08:00
|
|
|
}
|
|
|
|
|
2009-01-13 03:55:42 +08:00
|
|
|
/// IsReadonlyProperty - Verify that otherwise a valid l-value expression
|
|
|
|
/// is a read-only property; return true if so. A readonly property expression
|
|
|
|
/// depends on various declarations and thus must be treated specially.
|
|
|
|
///
|
2009-02-19 11:04:26 +08:00
|
|
|
static bool IsReadonlyProperty(Expr *E, Sema &S)
|
2009-01-13 03:55:42 +08:00
|
|
|
{
|
|
|
|
if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
|
|
|
|
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
|
|
|
|
if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
|
|
|
|
QualType BaseType = PropExpr->getBase()->getType();
|
|
|
|
if (const PointerType *PTy = BaseType->getAsPointerType())
|
2009-02-19 11:04:26 +08:00
|
|
|
if (const ObjCInterfaceType *IFTy =
|
2009-01-13 03:55:42 +08:00
|
|
|
PTy->getPointeeType()->getAsObjCInterfaceType())
|
|
|
|
if (ObjCInterfaceDecl *IFace = IFTy->getDecl())
|
|
|
|
if (S.isPropertyReadonly(PDecl, IFace))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-11-18 09:22:49 +08:00
|
|
|
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
|
|
|
|
/// emit an error and return true. If so, return false.
|
|
|
|
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
|
2009-01-13 03:55:42 +08:00
|
|
|
Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context);
|
|
|
|
if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
|
|
|
|
IsLV = Expr::MLV_ReadonlyProperty;
|
2008-11-18 09:22:49 +08:00
|
|
|
if (IsLV == Expr::MLV_Valid)
|
|
|
|
return false;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-11-18 09:22:49 +08:00
|
|
|
unsigned Diag = 0;
|
|
|
|
bool NeedType = false;
|
|
|
|
switch (IsLV) { // C99 6.5.16p2
|
|
|
|
default: assert(0 && "Unknown result from isModifiableLvalue!");
|
|
|
|
case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break;
|
2009-02-19 11:04:26 +08:00
|
|
|
case Expr::MLV_ArrayType:
|
2008-11-18 09:22:49 +08:00
|
|
|
Diag = diag::err_typecheck_array_not_modifiable_lvalue;
|
|
|
|
NeedType = true;
|
|
|
|
break;
|
2009-02-19 11:04:26 +08:00
|
|
|
case Expr::MLV_NotObjectType:
|
2008-11-18 09:22:49 +08:00
|
|
|
Diag = diag::err_typecheck_non_object_not_modifiable_lvalue;
|
|
|
|
NeedType = true;
|
|
|
|
break;
|
2008-11-18 03:51:54 +08:00
|
|
|
case Expr::MLV_LValueCast:
|
2008-11-18 09:22:49 +08:00
|
|
|
Diag = diag::err_typecheck_lvalue_casts_not_supported;
|
|
|
|
break;
|
2008-01-05 02:04:52 +08:00
|
|
|
case Expr::MLV_InvalidExpression:
|
2008-11-18 09:22:49 +08:00
|
|
|
Diag = diag::err_typecheck_expression_not_modifiable_lvalue;
|
|
|
|
break;
|
2008-01-05 02:04:52 +08:00
|
|
|
case Expr::MLV_IncompleteType:
|
|
|
|
case Expr::MLV_IncompleteVoidType:
|
2009-02-19 11:04:26 +08:00
|
|
|
return S.DiagnoseIncompleteType(Loc, E->getType(),
|
2009-01-20 03:26:10 +08:00
|
|
|
diag::err_typecheck_incomplete_type_not_modifiable_lvalue,
|
|
|
|
E->getSourceRange());
|
2008-01-05 02:04:52 +08:00
|
|
|
case Expr::MLV_DuplicateVectorComponents:
|
2008-11-18 09:22:49 +08:00
|
|
|
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
|
|
|
|
break;
|
2008-09-26 22:41:28 +08:00
|
|
|
case Expr::MLV_NotBlockQualified:
|
2008-11-18 09:22:49 +08:00
|
|
|
Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
|
|
|
|
break;
|
2008-11-23 02:39:36 +08:00
|
|
|
case Expr::MLV_ReadonlyProperty:
|
|
|
|
Diag = diag::error_readonly_property_assignment;
|
|
|
|
break;
|
2008-11-23 04:25:50 +08:00
|
|
|
case Expr::MLV_NoSetterProperty:
|
|
|
|
Diag = diag::error_nosetter_property_assignment;
|
|
|
|
break;
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
}
|
2008-01-05 02:04:52 +08:00
|
|
|
|
2008-11-18 09:22:49 +08:00
|
|
|
if (NeedType)
|
2008-11-24 14:25:27 +08:00
|
|
|
S.Diag(Loc, Diag) << E->getType() << E->getSourceRange();
|
2008-11-18 09:22:49 +08:00
|
|
|
else
|
2008-11-19 13:27:50 +08:00
|
|
|
S.Diag(Loc, Diag) << E->getSourceRange();
|
2008-11-18 09:22:49 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// C99 6.5.16.1
|
2008-11-18 09:30:42 +08:00
|
|
|
QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
|
|
|
|
SourceLocation Loc,
|
|
|
|
QualType CompoundType) {
|
|
|
|
// Verify that LHS is a modifiable lvalue, and emit error if not.
|
|
|
|
if (CheckForModifiableLvalue(LHS, Loc, *this))
|
2008-11-18 09:22:49 +08:00
|
|
|
return QualType();
|
2008-11-18 09:30:42 +08:00
|
|
|
|
|
|
|
QualType LHSType = LHS->getType();
|
|
|
|
QualType RHSType = CompoundType.isNull() ? RHS->getType() : CompoundType;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-01-05 02:04:52 +08:00
|
|
|
AssignConvertType ConvTy;
|
2008-11-18 09:30:42 +08:00
|
|
|
if (CompoundType.isNull()) {
|
2008-08-22 02:04:13 +08:00
|
|
|
// Simple assignment "x = y".
|
2008-11-18 09:30:42 +08:00
|
|
|
ConvTy = CheckSingleAssignmentConstraints(LHSType, RHS);
|
2009-01-14 07:34:40 +08:00
|
|
|
// Special case of NSObject attributes on c-style pointer types.
|
|
|
|
if (ConvTy == IncompatiblePointer &&
|
|
|
|
((Context.isObjCNSObjectType(LHSType) &&
|
|
|
|
Context.isObjCObjectPointerType(RHSType)) ||
|
|
|
|
(Context.isObjCNSObjectType(RHSType) &&
|
|
|
|
Context.isObjCObjectPointerType(LHSType))))
|
|
|
|
ConvTy = Compatible;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-08-22 02:04:13 +08:00
|
|
|
// If the RHS is a unary plus or minus, check to see if they = and + are
|
|
|
|
// right next to each other. If so, the user may have typo'd "x =+ 4"
|
|
|
|
// instead of "x += 4".
|
2008-11-18 09:30:42 +08:00
|
|
|
Expr *RHSCheck = RHS;
|
2008-08-22 02:04:13 +08:00
|
|
|
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RHSCheck))
|
|
|
|
RHSCheck = ICE->getSubExpr();
|
|
|
|
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(RHSCheck)) {
|
|
|
|
if ((UO->getOpcode() == UnaryOperator::Plus ||
|
|
|
|
UO->getOpcode() == UnaryOperator::Minus) &&
|
2008-11-18 09:30:42 +08:00
|
|
|
Loc.isFileID() && UO->getOperatorLoc().isFileID() &&
|
2008-08-22 02:04:13 +08:00
|
|
|
// Only if the two operators are exactly adjacent.
|
2008-11-18 09:30:42 +08:00
|
|
|
Loc.getFileLocWithOffset(1) == UO->getOperatorLoc())
|
2008-11-20 14:06:08 +08:00
|
|
|
Diag(Loc, diag::warn_not_compound_assign)
|
|
|
|
<< (UO->getOpcode() == UnaryOperator::Plus ? "+" : "-")
|
|
|
|
<< SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc());
|
2008-08-22 02:04:13 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Compound assignment "x += y"
|
2008-11-18 09:30:42 +08:00
|
|
|
ConvTy = CheckCompoundAssignmentConstraints(LHSType, RHSType);
|
2008-08-22 02:04:13 +08:00
|
|
|
}
|
2007-07-31 20:34:36 +08:00
|
|
|
|
2008-11-18 09:30:42 +08:00
|
|
|
if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType,
|
|
|
|
RHS, "assigning"))
|
2008-01-05 02:04:52 +08:00
|
|
|
return QualType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-06-07 02:38:38 +08:00
|
|
|
// C99 6.5.16p3: The type of an assignment expression is the type of the
|
|
|
|
// left operand unless the left operand has qualified type, in which case
|
2009-02-19 11:04:26 +08:00
|
|
|
// it is the unqualified version of the type of the left operand.
|
2007-06-07 02:38:38 +08:00
|
|
|
// C99 6.5.16.1p2: In simple assignment, the value of the right operand
|
|
|
|
// is converted to the type of the assignment expression (above).
|
2007-08-31 01:45:32 +08:00
|
|
|
// C++ 5.17p1: the type of the assignment expression is that of its left
|
|
|
|
// oprdu.
|
2008-11-18 09:30:42 +08:00
|
|
|
return LHSType.getUnqualifiedType();
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
}
|
|
|
|
|
2008-11-18 09:30:42 +08:00
|
|
|
// C99 6.5.17
|
|
|
|
QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) {
|
|
|
|
// FIXME: what is required for LHS?
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-26 04:54:07 +08:00
|
|
|
// Comma performs lvalue conversion (C99 6.3.2.1), but not unary conversions.
|
2008-11-18 09:30:42 +08:00
|
|
|
DefaultFunctionArrayConversion(RHS);
|
|
|
|
return RHS->getType();
|
2007-03-22 05:08:52 +08:00
|
|
|
}
|
|
|
|
|
2007-07-14 00:58:59 +08:00
|
|
|
/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine
|
|
|
|
/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions.
|
2008-12-20 17:35:34 +08:00
|
|
|
QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
|
|
|
|
bool isInc) {
|
2009-02-26 22:39:58 +08:00
|
|
|
if (Op->isTypeDependent())
|
|
|
|
return Context.DependentTy;
|
|
|
|
|
2008-11-21 15:05:48 +08:00
|
|
|
QualType ResType = Op->getType();
|
|
|
|
assert(!ResType.isNull() && "no type for increment/decrement expression");
|
2007-04-06 05:15:20 +08:00
|
|
|
|
2008-12-20 17:35:34 +08:00
|
|
|
if (getLangOptions().CPlusPlus && ResType->isBooleanType()) {
|
|
|
|
// Decrement of bool is not allowed.
|
|
|
|
if (!isInc) {
|
|
|
|
Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
// Increment of bool sets it to true, but is deprecated.
|
|
|
|
Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
|
|
|
|
} else if (ResType->isRealType()) {
|
2008-11-21 15:05:48 +08:00
|
|
|
// OK!
|
|
|
|
} else if (const PointerType *PT = ResType->getAsPointerType()) {
|
|
|
|
// C99 6.5.2.4p2, 6.5.6p2
|
|
|
|
if (PT->getPointeeType()->isObjectType()) {
|
|
|
|
// Pointer to object is ok!
|
|
|
|
} else if (PT->getPointeeType()->isVoidType()) {
|
2009-01-23 08:36:41 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
|
|
|
|
<< Op->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pointer to void is a GNU extension in C.
|
2008-11-21 15:05:48 +08:00
|
|
|
Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
|
2009-01-20 03:26:10 +08:00
|
|
|
} else if (PT->getPointeeType()->isFunctionType()) {
|
2009-01-23 08:36:41 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
|
|
|
|
<< Op->getType() << Op->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< ResType << Op->getSourceRange();
|
2007-08-25 01:20:07 +08:00
|
|
|
return QualType();
|
2009-01-20 03:26:10 +08:00
|
|
|
} else {
|
2009-02-19 11:04:26 +08:00
|
|
|
DiagnoseIncompleteType(OpLoc, PT->getPointeeType(),
|
2009-01-20 03:26:10 +08:00
|
|
|
diag::err_typecheck_arithmetic_incomplete_type,
|
|
|
|
Op->getSourceRange(), SourceRange(),
|
|
|
|
ResType);
|
|
|
|
return QualType();
|
2007-08-25 01:20:07 +08:00
|
|
|
}
|
2008-11-21 15:05:48 +08:00
|
|
|
} else if (ResType->isComplexType()) {
|
|
|
|
// C99 does not support ++/-- on complex types, we allow as an extension.
|
|
|
|
Diag(OpLoc, diag::ext_integer_increment_complex)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< ResType << Op->getSourceRange();
|
2008-11-21 15:05:48 +08:00
|
|
|
} else {
|
|
|
|
Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< ResType << Op->getSourceRange();
|
2008-11-21 15:05:48 +08:00
|
|
|
return QualType();
|
2007-04-04 07:13:13 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
// At this point, we know we have a real, complex or pointer type.
|
2007-08-24 05:37:33 +08:00
|
|
|
// Now make sure the operand is a modifiable lvalue.
|
2008-11-21 15:05:48 +08:00
|
|
|
if (CheckForModifiableLvalue(Op, OpLoc, *this))
|
2007-05-07 08:24:15 +08:00
|
|
|
return QualType();
|
2008-11-21 15:05:48 +08:00
|
|
|
return ResType;
|
2007-03-22 05:08:52 +08:00
|
|
|
}
|
|
|
|
|
2008-02-01 15:15:58 +08:00
|
|
|
/// getPrimaryDecl - Helper function for CheckAddressOfOperand().
|
2007-04-20 07:00:49 +08:00
|
|
|
/// This routine allows us to typecheck complex/recursive expressions
|
2008-08-05 04:02:37 +08:00
|
|
|
/// where the declaration is needed for type checking. We only need to
|
|
|
|
/// handle cases when the expression references a function designator
|
|
|
|
/// or is an lvalue. Here are some examples:
|
|
|
|
/// - &(x) => x
|
|
|
|
/// - &*****f => f for f a function designator.
|
|
|
|
/// - &s.xx => s
|
|
|
|
/// - &s.zz[1].yy -> s, if zz is an array
|
|
|
|
/// - *(x + 1) -> x, if x is an array
|
|
|
|
/// - &"123"[2] -> 0
|
|
|
|
/// - & __real__ x -> x
|
2008-10-22 00:13:35 +08:00
|
|
|
static NamedDecl *getPrimaryDecl(Expr *E) {
|
2008-04-02 12:24:33 +08:00
|
|
|
switch (E->getStmtClass()) {
|
2007-04-20 07:00:49 +08:00
|
|
|
case Stmt::DeclRefExprClass:
|
2009-01-06 13:10:23 +08:00
|
|
|
case Stmt::QualifiedDeclRefExprClass:
|
2008-04-02 12:24:33 +08:00
|
|
|
return cast<DeclRefExpr>(E)->getDecl();
|
2007-04-20 07:00:49 +08:00
|
|
|
case Stmt::MemberExprClass:
|
2007-11-17 01:46:48 +08:00
|
|
|
// Fields cannot be declared with a 'register' storage class.
|
|
|
|
// &X->f is always ok, even if X is declared register.
|
2008-04-02 12:24:33 +08:00
|
|
|
if (cast<MemberExpr>(E)->isArrow())
|
2007-11-17 01:46:48 +08:00
|
|
|
return 0;
|
2008-04-02 12:24:33 +08:00
|
|
|
return getPrimaryDecl(cast<MemberExpr>(E)->getBase());
|
2008-02-01 15:15:58 +08:00
|
|
|
case Stmt::ArraySubscriptExprClass: {
|
2008-08-05 04:02:37 +08:00
|
|
|
// &X[4] and &4[X] refers to X if X is not a pointer.
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-10-22 00:13:35 +08:00
|
|
|
NamedDecl *D = getPrimaryDecl(cast<ArraySubscriptExpr>(E)->getBase());
|
2008-10-22 05:22:32 +08:00
|
|
|
ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D);
|
2008-02-02 00:01:31 +08:00
|
|
|
if (!VD || VD->getType()->isPointerType())
|
2008-02-01 15:15:58 +08:00
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return VD;
|
|
|
|
}
|
2008-08-05 04:02:37 +08:00
|
|
|
case Stmt::UnaryOperatorClass: {
|
|
|
|
UnaryOperator *UO = cast<UnaryOperator>(E);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-08-05 04:02:37 +08:00
|
|
|
switch(UO->getOpcode()) {
|
|
|
|
case UnaryOperator::Deref: {
|
|
|
|
// *(X + 1) refers to X if X is not a pointer.
|
2008-10-22 00:13:35 +08:00
|
|
|
if (NamedDecl *D = getPrimaryDecl(UO->getSubExpr())) {
|
|
|
|
ValueDecl *VD = dyn_cast<ValueDecl>(D);
|
|
|
|
if (!VD || VD->getType()->isPointerType())
|
|
|
|
return 0;
|
|
|
|
return VD;
|
|
|
|
}
|
|
|
|
return 0;
|
2008-08-05 04:02:37 +08:00
|
|
|
}
|
|
|
|
case UnaryOperator::Real:
|
|
|
|
case UnaryOperator::Imag:
|
|
|
|
case UnaryOperator::Extension:
|
|
|
|
return getPrimaryDecl(UO->getSubExpr());
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case Stmt::BinaryOperatorClass: {
|
|
|
|
BinaryOperator *BO = cast<BinaryOperator>(E);
|
|
|
|
|
|
|
|
// Handle cases involving pointer arithmetic. The result of an
|
|
|
|
// Assign or AddAssign is not an lvalue so they can be ignored.
|
|
|
|
|
|
|
|
// (x + n) or (n + x) => x
|
|
|
|
if (BO->getOpcode() == BinaryOperator::Add) {
|
|
|
|
if (BO->getLHS()->getType()->isPointerType()) {
|
|
|
|
return getPrimaryDecl(BO->getLHS());
|
|
|
|
} else if (BO->getRHS()->getType()->isPointerType()) {
|
|
|
|
return getPrimaryDecl(BO->getRHS());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2007-04-20 07:00:49 +08:00
|
|
|
case Stmt::ParenExprClass:
|
2008-04-02 12:24:33 +08:00
|
|
|
return getPrimaryDecl(cast<ParenExpr>(E)->getSubExpr());
|
2007-11-17 01:46:48 +08:00
|
|
|
case Stmt::ImplicitCastExprClass:
|
|
|
|
// &X[4] when X is an array, has an implicit cast from array to pointer.
|
2008-04-02 12:24:33 +08:00
|
|
|
return getPrimaryDecl(cast<ImplicitCastExpr>(E)->getSubExpr());
|
2007-04-20 07:00:49 +08:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// CheckAddressOfOperand - The operand of & must be either a function
|
2009-02-19 11:04:26 +08:00
|
|
|
/// designator or an lvalue designating an object. If it is an lvalue, the
|
2007-04-20 07:00:49 +08:00
|
|
|
/// object cannot be declared with storage class register or be a bit field.
|
2009-02-19 11:04:26 +08:00
|
|
|
/// Note: The usual conversions are *not* applied to the operand of the &
|
2007-05-17 03:47:19 +08:00
|
|
|
/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
|
2009-02-19 11:04:26 +08:00
|
|
|
/// In C++, the operand might be an overloaded function name, in which case
|
2008-11-11 04:40:00 +08:00
|
|
|
/// we allow the '&' but retain the overloaded-function type.
|
2007-05-07 08:24:15 +08:00
|
|
|
QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
|
2008-12-18 06:52:20 +08:00
|
|
|
if (op->isTypeDependent())
|
|
|
|
return Context.DependentTy;
|
|
|
|
|
2008-01-14 01:10:08 +08:00
|
|
|
if (getLangOptions().C99) {
|
|
|
|
// Implement C99-only parts of addressof rules.
|
|
|
|
if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) {
|
|
|
|
if (uOp->getOpcode() == UnaryOperator::Deref)
|
|
|
|
// Per C99 6.5.3.2, the address of a deref always returns a valid result
|
|
|
|
// (assuming the deref expression is valid).
|
|
|
|
return uOp->getSubExpr()->getType();
|
|
|
|
}
|
|
|
|
// Technically, there should be a check for array subscript
|
|
|
|
// expressions here, but the result of one is always an lvalue anyway.
|
|
|
|
}
|
2008-10-22 00:13:35 +08:00
|
|
|
NamedDecl *dcl = getPrimaryDecl(op);
|
2008-07-27 05:30:36 +08:00
|
|
|
Expr::isLvalueResult lval = op->isLvalue(Context);
|
2008-12-17 06:59:47 +08:00
|
|
|
|
2007-05-28 07:58:33 +08:00
|
|
|
if (lval != Expr::LV_Valid) { // C99 6.5.3.2p1
|
2007-11-17 01:46:48 +08:00
|
|
|
if (!dcl || !isa<FunctionDecl>(dcl)) {// allow function designators
|
|
|
|
// FIXME: emit more specific diag...
|
2008-11-19 13:27:50 +08:00
|
|
|
Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
|
|
|
|
<< op->getSourceRange();
|
2007-05-07 08:24:15 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2008-03-01 07:30:25 +08:00
|
|
|
} else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(op)) { // C99 6.5.3.2p1
|
2008-12-21 07:49:58 +08:00
|
|
|
if (FieldDecl *Field = dyn_cast<FieldDecl>(MemExpr->getMemberDecl())) {
|
|
|
|
if (Field->isBitField()) {
|
|
|
|
Diag(OpLoc, diag::err_typecheck_address_of)
|
|
|
|
<< "bit-field" << op->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
2008-03-01 07:30:25 +08:00
|
|
|
}
|
|
|
|
// Check for Apple extension for accessing vector components.
|
2009-02-16 06:45:20 +08:00
|
|
|
} else if (isa<ExtVectorElementExpr>(op) || (isa<ArraySubscriptExpr>(op) &&
|
|
|
|
cast<ArraySubscriptExpr>(op)->getBase()->getType()->isVectorType())){
|
2008-11-20 14:06:08 +08:00
|
|
|
Diag(OpLoc, diag::err_typecheck_address_of)
|
2009-02-16 06:45:20 +08:00
|
|
|
<< "vector element" << op->getSourceRange();
|
2008-03-01 07:30:25 +08:00
|
|
|
return QualType();
|
|
|
|
} else if (dcl) { // C99 6.5.3.2p1
|
2009-02-19 11:04:26 +08:00
|
|
|
// We have an lvalue with a decl. Make sure the decl is not declared
|
2007-04-20 07:00:49 +08:00
|
|
|
// with the register storage-class specifier.
|
|
|
|
if (const VarDecl *vd = dyn_cast<VarDecl>(dcl)) {
|
2007-05-07 08:24:15 +08:00
|
|
|
if (vd->getStorageClass() == VarDecl::Register) {
|
2008-11-20 14:06:08 +08:00
|
|
|
Diag(OpLoc, diag::err_typecheck_address_of)
|
|
|
|
<< "register variable" << op->getSourceRange();
|
2007-05-07 08:24:15 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2008-12-11 05:26:49 +08:00
|
|
|
} else if (isa<OverloadedFunctionDecl>(dcl)) {
|
2008-11-11 04:40:00 +08:00
|
|
|
return Context.OverloadTy;
|
2008-12-11 05:26:49 +08:00
|
|
|
} else if (isa<FieldDecl>(dcl)) {
|
|
|
|
// Okay: we can take the address of a field.
|
2009-02-04 04:19:35 +08:00
|
|
|
// Could be a pointer to member, though, if there is an explicit
|
|
|
|
// scope qualifier for the class.
|
|
|
|
if (isa<QualifiedDeclRefExpr>(op)) {
|
|
|
|
DeclContext *Ctx = dcl->getDeclContext();
|
|
|
|
if (Ctx && Ctx->isRecord())
|
|
|
|
return Context.getMemberPointerType(op->getType(),
|
|
|
|
Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
|
|
|
|
}
|
2008-12-17 06:58:26 +08:00
|
|
|
} else if (isa<FunctionDecl>(dcl)) {
|
|
|
|
// Okay: we can take the address of a function.
|
2009-02-05 05:23:32 +08:00
|
|
|
// As above.
|
|
|
|
if (isa<QualifiedDeclRefExpr>(op)) {
|
|
|
|
DeclContext *Ctx = dcl->getDeclContext();
|
|
|
|
if (Ctx && Ctx->isRecord())
|
|
|
|
return Context.getMemberPointerType(op->getType(),
|
|
|
|
Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
|
|
|
|
}
|
2008-12-11 05:26:49 +08:00
|
|
|
}
|
2008-12-17 06:58:26 +08:00
|
|
|
else
|
2007-04-26 03:01:39 +08:00
|
|
|
assert(0 && "Unknown/unexpected decl type");
|
2007-04-20 07:00:49 +08:00
|
|
|
}
|
2009-02-05 05:23:32 +08:00
|
|
|
|
2007-04-20 07:00:49 +08:00
|
|
|
// If the operand has type "type", the result has type "pointer to type".
|
2007-05-07 08:24:15 +08:00
|
|
|
return Context.getPointerType(op->getType());
|
2007-04-20 07:00:49 +08:00
|
|
|
}
|
|
|
|
|
2008-11-23 17:13:29 +08:00
|
|
|
QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) {
|
2009-02-26 22:39:58 +08:00
|
|
|
if (Op->isTypeDependent())
|
|
|
|
return Context.DependentTy;
|
|
|
|
|
2008-11-23 17:13:29 +08:00
|
|
|
UsualUnaryConversions(Op);
|
|
|
|
QualType Ty = Op->getType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-11-23 17:13:29 +08:00
|
|
|
// Note that per both C89 and C99, this is always legal, even if ptype is an
|
|
|
|
// incomplete type or void. It would be possible to warn about dereferencing
|
|
|
|
// a void pointer, but it's completely well-defined, and such a warning is
|
|
|
|
// unlikely to catch any mistakes.
|
|
|
|
if (const PointerType *PT = Ty->getAsPointerType())
|
2008-01-14 01:10:08 +08:00
|
|
|
return PT->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-11-20 14:06:08 +08:00
|
|
|
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
|
2008-11-23 17:13:29 +08:00
|
|
|
<< Ty << Op->getSourceRange();
|
2007-05-07 08:24:15 +08:00
|
|
|
return QualType();
|
2007-04-24 08:23:05 +08:00
|
|
|
}
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
|
|
|
|
static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode(
|
|
|
|
tok::TokenKind Kind) {
|
|
|
|
BinaryOperator::Opcode Opc;
|
|
|
|
switch (Kind) {
|
|
|
|
default: assert(0 && "Unknown binop!");
|
2009-02-07 08:15:38 +08:00
|
|
|
case tok::periodstar: Opc = BinaryOperator::PtrMemD; break;
|
|
|
|
case tok::arrowstar: Opc = BinaryOperator::PtrMemI; break;
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
case tok::star: Opc = BinaryOperator::Mul; break;
|
|
|
|
case tok::slash: Opc = BinaryOperator::Div; break;
|
|
|
|
case tok::percent: Opc = BinaryOperator::Rem; break;
|
|
|
|
case tok::plus: Opc = BinaryOperator::Add; break;
|
|
|
|
case tok::minus: Opc = BinaryOperator::Sub; break;
|
|
|
|
case tok::lessless: Opc = BinaryOperator::Shl; break;
|
|
|
|
case tok::greatergreater: Opc = BinaryOperator::Shr; break;
|
|
|
|
case tok::lessequal: Opc = BinaryOperator::LE; break;
|
|
|
|
case tok::less: Opc = BinaryOperator::LT; break;
|
|
|
|
case tok::greaterequal: Opc = BinaryOperator::GE; break;
|
|
|
|
case tok::greater: Opc = BinaryOperator::GT; break;
|
|
|
|
case tok::exclaimequal: Opc = BinaryOperator::NE; break;
|
|
|
|
case tok::equalequal: Opc = BinaryOperator::EQ; break;
|
|
|
|
case tok::amp: Opc = BinaryOperator::And; break;
|
|
|
|
case tok::caret: Opc = BinaryOperator::Xor; break;
|
|
|
|
case tok::pipe: Opc = BinaryOperator::Or; break;
|
|
|
|
case tok::ampamp: Opc = BinaryOperator::LAnd; break;
|
|
|
|
case tok::pipepipe: Opc = BinaryOperator::LOr; break;
|
|
|
|
case tok::equal: Opc = BinaryOperator::Assign; break;
|
|
|
|
case tok::starequal: Opc = BinaryOperator::MulAssign; break;
|
|
|
|
case tok::slashequal: Opc = BinaryOperator::DivAssign; break;
|
|
|
|
case tok::percentequal: Opc = BinaryOperator::RemAssign; break;
|
|
|
|
case tok::plusequal: Opc = BinaryOperator::AddAssign; break;
|
|
|
|
case tok::minusequal: Opc = BinaryOperator::SubAssign; break;
|
|
|
|
case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break;
|
|
|
|
case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break;
|
|
|
|
case tok::ampequal: Opc = BinaryOperator::AndAssign; break;
|
|
|
|
case tok::caretequal: Opc = BinaryOperator::XorAssign; break;
|
|
|
|
case tok::pipeequal: Opc = BinaryOperator::OrAssign; break;
|
|
|
|
case tok::comma: Opc = BinaryOperator::Comma; break;
|
|
|
|
}
|
|
|
|
return Opc;
|
|
|
|
}
|
|
|
|
|
2007-05-07 08:24:15 +08:00
|
|
|
static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode(
|
|
|
|
tok::TokenKind Kind) {
|
|
|
|
UnaryOperator::Opcode Opc;
|
|
|
|
switch (Kind) {
|
|
|
|
default: assert(0 && "Unknown unary op!");
|
|
|
|
case tok::plusplus: Opc = UnaryOperator::PreInc; break;
|
|
|
|
case tok::minusminus: Opc = UnaryOperator::PreDec; break;
|
|
|
|
case tok::amp: Opc = UnaryOperator::AddrOf; break;
|
|
|
|
case tok::star: Opc = UnaryOperator::Deref; break;
|
|
|
|
case tok::plus: Opc = UnaryOperator::Plus; break;
|
|
|
|
case tok::minus: Opc = UnaryOperator::Minus; break;
|
|
|
|
case tok::tilde: Opc = UnaryOperator::Not; break;
|
|
|
|
case tok::exclaim: Opc = UnaryOperator::LNot; break;
|
|
|
|
case tok::kw___real: Opc = UnaryOperator::Real; break;
|
|
|
|
case tok::kw___imag: Opc = UnaryOperator::Imag; break;
|
2007-06-09 06:16:53 +08:00
|
|
|
case tok::kw___extension__: Opc = UnaryOperator::Extension; break;
|
2007-05-07 08:24:15 +08:00
|
|
|
}
|
|
|
|
return Opc;
|
|
|
|
}
|
|
|
|
|
2008-11-07 07:29:22 +08:00
|
|
|
/// CreateBuiltinBinOp - Creates a new built-in binary operation with
|
|
|
|
/// operator @p Opc at location @c TokLoc. This routine only supports
|
|
|
|
/// built-in operations; ActOnBinOp handles overloaded operators.
|
2009-01-20 06:31:54 +08:00
|
|
|
Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
|
|
|
unsigned Op,
|
|
|
|
Expr *lhs, Expr *rhs) {
|
2007-06-28 11:53:10 +08:00
|
|
|
QualType ResultTy; // Result type of the binary operator.
|
|
|
|
QualType CompTy; // Computation type for compound assignments (e.g. '+=')
|
2008-11-07 07:29:22 +08:00
|
|
|
BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)Op;
|
|
|
|
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
switch (Opc) {
|
|
|
|
default:
|
|
|
|
assert(0 && "Unknown binary expr!");
|
|
|
|
case BinaryOperator::Assign:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType());
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
2009-02-07 08:15:38 +08:00
|
|
|
case BinaryOperator::PtrMemD:
|
|
|
|
case BinaryOperator::PtrMemI:
|
|
|
|
ResultTy = CheckPointerToMemberOperands(lhs, rhs, OpLoc,
|
|
|
|
Opc == BinaryOperator::PtrMemI);
|
|
|
|
break;
|
|
|
|
case BinaryOperator::Mul:
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
case BinaryOperator::Div:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::Rem:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::Add:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckAdditionOperands(lhs, rhs, OpLoc);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::Sub:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
2009-02-07 08:15:38 +08:00
|
|
|
case BinaryOperator::Shl:
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
case BinaryOperator::Shr:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckShiftOperands(lhs, rhs, OpLoc);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::LE:
|
|
|
|
case BinaryOperator::LT:
|
|
|
|
case BinaryOperator::GE:
|
|
|
|
case BinaryOperator::GT:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, true);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::EQ:
|
|
|
|
case BinaryOperator::NE:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, false);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::And:
|
|
|
|
case BinaryOperator::Xor:
|
|
|
|
case BinaryOperator::Or:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::LAnd:
|
|
|
|
case BinaryOperator::LOr:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::MulAssign:
|
|
|
|
case BinaryOperator::DivAssign:
|
2008-11-07 07:29:22 +08:00
|
|
|
CompTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true);
|
2007-06-28 11:53:10 +08:00
|
|
|
if (!CompTy.isNull())
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::RemAssign:
|
2008-11-07 07:29:22 +08:00
|
|
|
CompTy = CheckRemainderOperands(lhs, rhs, OpLoc, true);
|
2007-06-28 11:53:10 +08:00
|
|
|
if (!CompTy.isNull())
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::AddAssign:
|
2008-11-07 07:29:22 +08:00
|
|
|
CompTy = CheckAdditionOperands(lhs, rhs, OpLoc, true);
|
2007-06-28 11:53:10 +08:00
|
|
|
if (!CompTy.isNull())
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::SubAssign:
|
2008-11-07 07:29:22 +08:00
|
|
|
CompTy = CheckSubtractionOperands(lhs, rhs, OpLoc, true);
|
2007-06-28 11:53:10 +08:00
|
|
|
if (!CompTy.isNull())
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::ShlAssign:
|
|
|
|
case BinaryOperator::ShrAssign:
|
2008-11-07 07:29:22 +08:00
|
|
|
CompTy = CheckShiftOperands(lhs, rhs, OpLoc, true);
|
2007-06-28 11:53:10 +08:00
|
|
|
if (!CompTy.isNull())
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::AndAssign:
|
|
|
|
case BinaryOperator::XorAssign:
|
|
|
|
case BinaryOperator::OrAssign:
|
2008-11-07 07:29:22 +08:00
|
|
|
CompTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true);
|
2007-06-28 11:53:10 +08:00
|
|
|
if (!CompTy.isNull())
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompTy);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
case BinaryOperator::Comma:
|
2008-11-07 07:29:22 +08:00
|
|
|
ResultTy = CheckCommaOperands(lhs, rhs, OpLoc);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
break;
|
|
|
|
}
|
2007-06-28 11:53:10 +08:00
|
|
|
if (ResultTy.isNull())
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2009-01-21 08:14:39 +08:00
|
|
|
if (CompTy.isNull())
|
|
|
|
return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, OpLoc));
|
|
|
|
else
|
|
|
|
return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy,
|
2009-02-19 11:04:26 +08:00
|
|
|
CompTy, OpLoc));
|
2008-11-07 07:29:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Binary Operators. 'Tok' is the token for the operator.
|
2009-01-20 06:31:54 +08:00
|
|
|
Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
|
|
|
|
tok::TokenKind Kind,
|
|
|
|
ExprArg LHS, ExprArg RHS) {
|
2008-11-07 07:29:22 +08:00
|
|
|
BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind);
|
2009-01-20 06:31:54 +08:00
|
|
|
Expr *lhs = (Expr *)LHS.release(), *rhs = (Expr*)RHS.release();
|
2008-11-07 07:29:22 +08:00
|
|
|
|
|
|
|
assert((lhs != 0) && "ActOnBinOp(): missing left expression");
|
|
|
|
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
|
|
|
|
|
2008-12-06 07:32:09 +08:00
|
|
|
// If either expression is type-dependent, just build the AST.
|
|
|
|
// FIXME: We'll need to perform some caching of the result of name
|
|
|
|
// lookup for operator+.
|
|
|
|
if (lhs->isTypeDependent() || rhs->isTypeDependent()) {
|
2009-01-21 08:14:39 +08:00
|
|
|
if (Opc > BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign)
|
|
|
|
return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc,
|
2009-01-20 06:31:54 +08:00
|
|
|
Context.DependentTy,
|
|
|
|
Context.DependentTy, TokLoc));
|
2009-01-21 08:14:39 +08:00
|
|
|
else
|
2009-02-07 08:15:38 +08:00
|
|
|
return Owned(new (Context) BinaryOperator(lhs, rhs, Opc,
|
|
|
|
Context.DependentTy, TokLoc));
|
2008-12-06 07:32:09 +08:00
|
|
|
}
|
|
|
|
|
2009-02-07 08:15:38 +08:00
|
|
|
if (getLangOptions().CPlusPlus && Opc != BinaryOperator::PtrMemD &&
|
2008-11-07 07:29:22 +08:00
|
|
|
(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType() ||
|
|
|
|
rhs->getType()->isRecordType() || rhs->getType()->isEnumeralType())) {
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
// If this is one of the assignment operators, we only perform
|
|
|
|
// overload resolution if the left-hand side is a class or
|
|
|
|
// enumeration type (C++ [expr.ass]p3).
|
|
|
|
if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign &&
|
|
|
|
!(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType())) {
|
|
|
|
return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
|
|
|
|
}
|
2009-01-20 06:31:54 +08:00
|
|
|
|
2008-11-07 07:29:22 +08:00
|
|
|
// Determine which overloaded operator we're dealing with.
|
|
|
|
static const OverloadedOperatorKind OverOps[] = {
|
2009-02-07 08:15:38 +08:00
|
|
|
// Overloading .* is not possible.
|
|
|
|
static_cast<OverloadedOperatorKind>(0), OO_ArrowStar,
|
2008-11-07 07:29:22 +08:00
|
|
|
OO_Star, OO_Slash, OO_Percent,
|
|
|
|
OO_Plus, OO_Minus,
|
|
|
|
OO_LessLess, OO_GreaterGreater,
|
|
|
|
OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
|
|
|
|
OO_EqualEqual, OO_ExclaimEqual,
|
|
|
|
OO_Amp,
|
|
|
|
OO_Caret,
|
|
|
|
OO_Pipe,
|
|
|
|
OO_AmpAmp,
|
|
|
|
OO_PipePipe,
|
|
|
|
OO_Equal, OO_StarEqual,
|
|
|
|
OO_SlashEqual, OO_PercentEqual,
|
|
|
|
OO_PlusEqual, OO_MinusEqual,
|
|
|
|
OO_LessLessEqual, OO_GreaterGreaterEqual,
|
|
|
|
OO_AmpEqual, OO_CaretEqual,
|
|
|
|
OO_PipeEqual,
|
|
|
|
OO_Comma
|
|
|
|
};
|
|
|
|
OverloadedOperatorKind OverOp = OverOps[Opc];
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
// Add the appropriate overloaded operators (C++ [over.match.oper])
|
2008-11-19 07:14:02 +08:00
|
|
|
// to the candidate set.
|
2008-11-19 23:42:04 +08:00
|
|
|
OverloadCandidateSet CandidateSet;
|
2008-11-07 07:29:22 +08:00
|
|
|
Expr *Args[2] = { lhs, rhs };
|
2009-02-05 00:44:47 +08:00
|
|
|
if (AddOperatorCandidates(OverOp, S, TokLoc, Args, 2, CandidateSet))
|
|
|
|
return ExprError();
|
2008-11-07 07:29:22 +08:00
|
|
|
|
|
|
|
// Perform overload resolution.
|
|
|
|
OverloadCandidateSet::iterator Best;
|
|
|
|
switch (BestViableFunction(CandidateSet, Best)) {
|
|
|
|
case OR_Success: {
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
// We found a built-in operator or an overloaded operator.
|
2008-11-07 07:29:22 +08:00
|
|
|
FunctionDecl *FnDecl = Best->Function;
|
|
|
|
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
if (FnDecl) {
|
|
|
|
// We matched an overloaded operator. Build a call to that
|
|
|
|
// operator.
|
|
|
|
|
|
|
|
// Convert the arguments.
|
2008-11-19 07:14:02 +08:00
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
|
|
|
|
if (PerformObjectArgumentInitialization(lhs, Method) ||
|
|
|
|
PerformCopyInitialization(rhs, FnDecl->getParamDecl(0)->getType(),
|
|
|
|
"passing"))
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2008-11-19 07:14:02 +08:00
|
|
|
} else {
|
|
|
|
// Convert the arguments.
|
|
|
|
if (PerformCopyInitialization(lhs, FnDecl->getParamDecl(0)->getType(),
|
|
|
|
"passing") ||
|
|
|
|
PerformCopyInitialization(rhs, FnDecl->getParamDecl(1)->getType(),
|
|
|
|
"passing"))
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2008-11-19 07:14:02 +08: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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
|
|
|
|
// Determine the result type
|
2009-01-20 06:31:54 +08:00
|
|
|
QualType ResultTy
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
= FnDecl->getType()->getAsFunctionType()->getResultType();
|
|
|
|
ResultTy = ResultTy.getNonReferenceType();
|
2009-01-20 06:31:54 +08: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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
// Build the actual expression node.
|
2009-01-21 08:14:39 +08:00
|
|
|
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
|
|
|
|
SourceLocation());
|
2008-11-15 00:09:21 +08:00
|
|
|
UsualUnaryConversions(FnExpr);
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
|
2009-01-21 08:14:39 +08:00
|
|
|
ResultTy, TokLoc));
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
} else {
|
|
|
|
// We matched a built-in operator. Convert the arguments, then
|
|
|
|
// break out so that we will build the appropriate built-in
|
|
|
|
// operator node.
|
2009-01-14 23:45:31 +08:00
|
|
|
if (PerformImplicitConversion(lhs, Best->BuiltinTypes.ParamTypes[0],
|
|
|
|
Best->Conversions[0], "passing") ||
|
|
|
|
PerformImplicitConversion(rhs, Best->BuiltinTypes.ParamTypes[1],
|
|
|
|
Best->Conversions[1], "passing"))
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
|
|
|
|
break;
|
2009-01-20 06:31:54 +08:00
|
|
|
}
|
2008-11-07 07:29:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case OR_No_Viable_Function:
|
|
|
|
// No viable function; fall through to handling this as a
|
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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
// built-in operator, which will produce an error message for us.
|
2008-11-07 07:29:22 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OR_Ambiguous:
|
2008-11-19 13:08:23 +08:00
|
|
|
Diag(TokLoc, diag::err_ovl_ambiguous_oper)
|
|
|
|
<< BinaryOperator::getOpcodeStr(Opc)
|
|
|
|
<< lhs->getSourceRange() << rhs->getSourceRange();
|
2008-11-07 07:29:22 +08:00
|
|
|
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2009-02-19 05:56:37 +08:00
|
|
|
|
|
|
|
case OR_Deleted:
|
|
|
|
Diag(TokLoc, diag::err_ovl_deleted_oper)
|
|
|
|
<< Best->Function->isDeleted()
|
|
|
|
<< BinaryOperator::getOpcodeStr(Opc)
|
|
|
|
<< lhs->getSourceRange() << rhs->getSourceRange();
|
|
|
|
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
|
|
|
return ExprError();
|
2008-11-07 07:29:22 +08: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.
llvm-svn: 59148
2008-11-13 01:17:38 +08:00
|
|
|
// Either we found no viable overloaded operator or we matched a
|
|
|
|
// built-in operator. In either case, fall through to trying to
|
|
|
|
// build a built-in operation.
|
2009-01-20 06:31:54 +08:00
|
|
|
}
|
|
|
|
|
2008-11-07 07:29:22 +08:00
|
|
|
// Build a built-in binary operation.
|
|
|
|
return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
}
|
|
|
|
|
2007-05-07 08:24:15 +08:00
|
|
|
// Unary Operators. 'Tok' is the token for the operator.
|
2009-01-19 08:08:26 +08:00
|
|
|
Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
|
|
|
|
tok::TokenKind Op, ExprArg input) {
|
|
|
|
// FIXME: Input is modified later, but smart pointer not reassigned.
|
|
|
|
Expr *Input = (Expr*)input.get();
|
2007-05-07 08:24:15 +08:00
|
|
|
UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
|
2008-11-19 23:42:04 +08:00
|
|
|
|
|
|
|
if (getLangOptions().CPlusPlus &&
|
2009-02-19 11:04:26 +08:00
|
|
|
(Input->getType()->isRecordType()
|
2008-11-19 23:42:04 +08:00
|
|
|
|| Input->getType()->isEnumeralType())) {
|
|
|
|
// Determine which overloaded operator we're dealing with.
|
|
|
|
static const OverloadedOperatorKind OverOps[] = {
|
|
|
|
OO_None, OO_None,
|
|
|
|
OO_PlusPlus, OO_MinusMinus,
|
|
|
|
OO_Amp, OO_Star,
|
|
|
|
OO_Plus, OO_Minus,
|
|
|
|
OO_Tilde, OO_Exclaim,
|
|
|
|
OO_None, OO_None,
|
2009-02-19 11:04:26 +08:00
|
|
|
OO_None,
|
2008-11-19 23:42:04 +08:00
|
|
|
OO_None
|
|
|
|
};
|
|
|
|
OverloadedOperatorKind OverOp = OverOps[Opc];
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
// Add the appropriate overloaded operators (C++ [over.match.oper])
|
2008-11-19 23:42:04 +08:00
|
|
|
// to the candidate set.
|
|
|
|
OverloadCandidateSet CandidateSet;
|
2009-02-05 00:44:47 +08:00
|
|
|
if (OverOp != OO_None &&
|
|
|
|
AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet))
|
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
|
|
|
|
// Perform overload resolution.
|
|
|
|
OverloadCandidateSet::iterator Best;
|
|
|
|
switch (BestViableFunction(CandidateSet, Best)) {
|
|
|
|
case OR_Success: {
|
|
|
|
// We found a built-in operator or an overloaded operator.
|
|
|
|
FunctionDecl *FnDecl = Best->Function;
|
|
|
|
|
|
|
|
if (FnDecl) {
|
|
|
|
// We matched an overloaded operator. Build a call to that
|
|
|
|
// operator.
|
|
|
|
|
|
|
|
// Convert the arguments.
|
|
|
|
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
|
|
|
|
if (PerformObjectArgumentInitialization(Input, Method))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
} else {
|
|
|
|
// Convert the arguments.
|
2009-02-19 11:04:26 +08:00
|
|
|
if (PerformCopyInitialization(Input,
|
2008-11-19 23:42:04 +08:00
|
|
|
FnDecl->getParamDecl(0)->getType(),
|
|
|
|
"passing"))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the result type
|
2009-01-19 08:08:26 +08:00
|
|
|
QualType ResultTy
|
2008-11-19 23:42:04 +08:00
|
|
|
= FnDecl->getType()->getAsFunctionType()->getResultType();
|
|
|
|
ResultTy = ResultTy.getNonReferenceType();
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2008-11-19 23:42:04 +08:00
|
|
|
// Build the actual expression node.
|
2009-02-19 11:04:26 +08:00
|
|
|
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
|
2009-01-21 08:14:39 +08:00
|
|
|
SourceLocation());
|
2008-11-19 23:42:04 +08:00
|
|
|
UsualUnaryConversions(FnExpr);
|
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
input.release();
|
2009-02-19 11:04:26 +08:00
|
|
|
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, &Input,
|
|
|
|
1, ResultTy, OpLoc));
|
2008-11-19 23:42:04 +08:00
|
|
|
} else {
|
|
|
|
// We matched a built-in operator. Convert the arguments, then
|
|
|
|
// break out so that we will build the appropriate built-in
|
|
|
|
// operator node.
|
2009-01-14 23:45:31 +08:00
|
|
|
if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
|
|
|
|
Best->Conversions[0], "passing"))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
|
|
|
|
break;
|
2009-01-19 08:08:26 +08:00
|
|
|
}
|
2008-11-19 23:42:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case OR_No_Viable_Function:
|
|
|
|
// No viable function; fall through to handling this as a
|
|
|
|
// built-in operator, which will produce an error message for us.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OR_Ambiguous:
|
|
|
|
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
|
|
|
|
<< UnaryOperator::getOpcodeStr(Opc)
|
|
|
|
<< Input->getSourceRange();
|
|
|
|
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
2009-02-19 05:56:37 +08:00
|
|
|
|
|
|
|
case OR_Deleted:
|
|
|
|
Diag(OpLoc, diag::err_ovl_deleted_oper)
|
|
|
|
<< Best->Function->isDeleted()
|
|
|
|
<< UnaryOperator::getOpcodeStr(Opc)
|
|
|
|
<< Input->getSourceRange();
|
|
|
|
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
|
|
|
return ExprError();
|
2008-11-19 23:42:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Either we found no viable overloaded operator or we matched a
|
|
|
|
// built-in operator. In either case, fall through to trying to
|
2009-01-19 08:08:26 +08:00
|
|
|
// build a built-in operation.
|
2008-11-19 23:42:04 +08:00
|
|
|
}
|
|
|
|
|
2007-05-07 08:24:15 +08:00
|
|
|
QualType resultType;
|
|
|
|
switch (Opc) {
|
|
|
|
default:
|
|
|
|
assert(0 && "Unimplemented unary expr!");
|
|
|
|
case UnaryOperator::PreInc:
|
|
|
|
case UnaryOperator::PreDec:
|
2008-12-20 17:35:34 +08:00
|
|
|
resultType = CheckIncrementDecrementOperand(Input, OpLoc,
|
|
|
|
Opc == UnaryOperator::PreInc);
|
2007-05-07 08:24:15 +08:00
|
|
|
break;
|
2009-02-19 11:04:26 +08:00
|
|
|
case UnaryOperator::AddrOf:
|
2007-06-09 06:32:33 +08:00
|
|
|
resultType = CheckAddressOfOperand(Input, OpLoc);
|
2007-05-07 08:24:15 +08:00
|
|
|
break;
|
2009-02-19 11:04:26 +08:00
|
|
|
case UnaryOperator::Deref:
|
2007-12-18 12:06:57 +08:00
|
|
|
DefaultFunctionArrayConversion(Input);
|
2007-06-09 06:32:33 +08:00
|
|
|
resultType = CheckIndirectionOperand(Input, OpLoc);
|
2007-05-07 08:24:15 +08:00
|
|
|
break;
|
|
|
|
case UnaryOperator::Plus:
|
|
|
|
case UnaryOperator::Minus:
|
2007-07-17 05:54:35 +08:00
|
|
|
UsualUnaryConversions(Input);
|
|
|
|
resultType = Input->getType();
|
2009-02-26 22:39:58 +08:00
|
|
|
if (resultType->isDependentType())
|
|
|
|
break;
|
2008-11-19 23:42:04 +08:00
|
|
|
if (resultType->isArithmeticType()) // C99 6.5.3.3p1
|
|
|
|
break;
|
|
|
|
else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6-7
|
|
|
|
resultType->isEnumeralType())
|
|
|
|
break;
|
|
|
|
else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6
|
|
|
|
Opc == UnaryOperator::Plus &&
|
|
|
|
resultType->isPointerType())
|
|
|
|
break;
|
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
|
|
|
|
<< resultType << Input->getSourceRange());
|
2007-05-07 08:24:15 +08:00
|
|
|
case UnaryOperator::Not: // bitwise complement
|
2007-07-17 05:54:35 +08:00
|
|
|
UsualUnaryConversions(Input);
|
|
|
|
resultType = Input->getType();
|
2009-02-26 22:39:58 +08:00
|
|
|
if (resultType->isDependentType())
|
|
|
|
break;
|
2008-07-26 07:52:49 +08:00
|
|
|
// C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
|
|
|
|
if (resultType->isComplexType() || resultType->isComplexIntegerType())
|
|
|
|
// C99 does not support '~' for complex conjugation.
|
2008-11-20 14:06:08 +08:00
|
|
|
Diag(OpLoc, diag::ext_integer_complement_complex)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< resultType << Input->getSourceRange();
|
2008-07-26 07:52:49 +08:00
|
|
|
else if (!resultType->isIntegerType())
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
|
|
|
|
<< resultType << Input->getSourceRange());
|
2007-05-07 08:24:15 +08:00
|
|
|
break;
|
|
|
|
case UnaryOperator::LNot: // logical negation
|
2007-06-05 06:22:31 +08:00
|
|
|
// Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
|
2007-07-17 05:54:35 +08:00
|
|
|
DefaultFunctionArrayConversion(Input);
|
|
|
|
resultType = Input->getType();
|
2009-02-26 22:39:58 +08:00
|
|
|
if (resultType->isDependentType())
|
|
|
|
break;
|
2007-05-07 08:24:15 +08:00
|
|
|
if (!resultType->isScalarType()) // C99 6.5.3.3p1
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
|
|
|
|
<< resultType << Input->getSourceRange());
|
2007-06-03 03:11:33 +08:00
|
|
|
// LNot always has type int. C99 6.5.3.3p5.
|
2009-01-19 08:08:26 +08:00
|
|
|
// In C++, it's bool. C++ 5.3.1p8
|
|
|
|
resultType = getLangOptions().CPlusPlus ? Context.BoolTy : Context.IntTy;
|
2007-05-07 08:24:15 +08:00
|
|
|
break;
|
2007-08-25 05:16:53 +08:00
|
|
|
case UnaryOperator::Real:
|
|
|
|
case UnaryOperator::Imag:
|
2009-02-17 16:12:06 +08:00
|
|
|
resultType = CheckRealImagOperand(Input, OpLoc, Opc == UnaryOperator::Real);
|
2007-08-25 05:16:53 +08:00
|
|
|
break;
|
2007-06-09 06:32:33 +08:00
|
|
|
case UnaryOperator::Extension:
|
|
|
|
resultType = Input->getType();
|
2007-05-15 10:32:35 +08:00
|
|
|
break;
|
2007-05-07 08:24:15 +08:00
|
|
|
}
|
|
|
|
if (resultType.isNull())
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError();
|
|
|
|
input.release();
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc));
|
2007-05-07 08:24:15 +08:00
|
|
|
}
|
2007-05-28 14:56:27 +08:00
|
|
|
|
2007-09-16 22:56:35 +08:00
|
|
|
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
|
2009-02-19 11:04:26 +08:00
|
|
|
Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
|
2007-05-28 14:56:27 +08:00
|
|
|
SourceLocation LabLoc,
|
|
|
|
IdentifierInfo *LabelII) {
|
|
|
|
// Look up the record for this label identifier.
|
2009-03-01 00:48:43 +08:00
|
|
|
llvm::DenseMap<IdentifierInfo*, Action::StmtTy*>::iterator I =
|
|
|
|
ActiveScope->LabelMap.find(LabelII);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-01 00:48:43 +08:00
|
|
|
LabelStmt *LabelDecl;
|
|
|
|
|
2008-08-05 00:51:22 +08:00
|
|
|
// If we haven't seen this label yet, create a forward reference. It
|
|
|
|
// will be validated and/or cleaned up in ActOnFinishFunctionBody.
|
2009-03-01 00:48:43 +08:00
|
|
|
if (I == ActiveScope->LabelMap.end()) {
|
2009-01-21 08:14:39 +08:00
|
|
|
LabelDecl = new (Context) LabelStmt(LabLoc, LabelII, 0);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-01 00:48:43 +08:00
|
|
|
ActiveScope->LabelMap.insert(std::make_pair(LabelII, LabelDecl));
|
|
|
|
} else
|
|
|
|
LabelDecl = static_cast<LabelStmt *>(I->second);
|
|
|
|
|
2007-05-28 14:56:27 +08:00
|
|
|
// Create the AST node. The address of a label always has type 'void*'.
|
2009-01-21 08:14:39 +08:00
|
|
|
return new (Context) AddrLabelExpr(OpLoc, LabLoc, LabelDecl,
|
|
|
|
Context.getPointerType(Context.VoidTy));
|
2007-05-28 14:56:27 +08:00
|
|
|
}
|
|
|
|
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ExprResult Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtTy *substmt,
|
2007-07-25 00:58:17 +08:00
|
|
|
SourceLocation RPLoc) { // "({..})"
|
|
|
|
Stmt *SubStmt = static_cast<Stmt*>(substmt);
|
|
|
|
assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!");
|
|
|
|
CompoundStmt *Compound = cast<CompoundStmt>(SubStmt);
|
|
|
|
|
2009-01-25 07:09:00 +08:00
|
|
|
bool isFileScope = getCurFunctionOrMethodDecl() == 0;
|
|
|
|
if (isFileScope) {
|
|
|
|
return Diag(LPLoc, diag::err_stmtexpr_file_scope);
|
|
|
|
}
|
|
|
|
|
2007-07-25 00:58:17 +08:00
|
|
|
// FIXME: there are a variety of strange constraints to enforce here, for
|
|
|
|
// example, it is not possible to goto into a stmt expression apparently.
|
|
|
|
// More semantic analysis is needed.
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-07-25 00:58:17 +08:00
|
|
|
// FIXME: the last statement in the compount stmt has its value used. We
|
|
|
|
// should not warn about it being unused.
|
|
|
|
|
|
|
|
// If there are sub stmts in the compound stmt, take the type of the last one
|
|
|
|
// as the type of the stmtexpr.
|
|
|
|
QualType Ty = Context.VoidTy;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-27 03:51:01 +08:00
|
|
|
if (!Compound->body_empty()) {
|
|
|
|
Stmt *LastStmt = Compound->body_back();
|
|
|
|
// If LastStmt is a label, skip down through into the body.
|
|
|
|
while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt))
|
|
|
|
LastStmt = Label->getSubStmt();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-07-27 03:51:01 +08:00
|
|
|
if (Expr *LastExpr = dyn_cast<Expr>(LastStmt))
|
2007-07-25 00:58:17 +08:00
|
|
|
Ty = LastExpr->getType();
|
2008-07-27 03:51:01 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-01-21 08:14:39 +08:00
|
|
|
return new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc);
|
2007-07-25 00:58:17 +08:00
|
|
|
}
|
2007-08-02 06:05:33 +08:00
|
|
|
|
2008-12-23 08:26:44 +08:00
|
|
|
Sema::ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
|
|
|
|
SourceLocation BuiltinLoc,
|
2007-08-31 01:45:32 +08:00
|
|
|
SourceLocation TypeLoc,
|
|
|
|
TypeTy *argty,
|
|
|
|
OffsetOfComponent *CompPtr,
|
|
|
|
unsigned NumComponents,
|
|
|
|
SourceLocation RPLoc) {
|
|
|
|
QualType ArgTy = QualType::getFromOpaquePtr(argty);
|
|
|
|
assert(!ArgTy.isNull() && "Missing type argument!");
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
bool Dependent = ArgTy->isDependentType();
|
|
|
|
|
2007-08-31 01:45:32 +08:00
|
|
|
// We must have at least one component that refers to the type, and the first
|
|
|
|
// one is known to be a field designator. Verify that the ArgTy represents
|
|
|
|
// a struct/union/class.
|
2009-02-26 22:39:58 +08:00
|
|
|
if (!Dependent && !ArgTy->isRecordType())
|
2008-11-24 14:25:27 +08:00
|
|
|
return Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-27 14:44:11 +08:00
|
|
|
// Otherwise, create a null pointer as the base, and iteratively process
|
|
|
|
// the offsetof designators.
|
|
|
|
QualType ArgTyPtr = Context.getPointerType(ArgTy);
|
|
|
|
Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr);
|
|
|
|
Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref,
|
|
|
|
ArgTy, SourceLocation());
|
2009-01-26 09:33:06 +08:00
|
|
|
|
2007-09-01 05:49:13 +08:00
|
|
|
// offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
|
|
|
|
// GCC extension, diagnose them.
|
2009-02-27 14:44:11 +08:00
|
|
|
// FIXME: This diagnostic isn't actually visible because the location is in
|
|
|
|
// a system header!
|
2007-09-01 05:49:13 +08:00
|
|
|
if (NumComponents != 1)
|
2008-11-19 13:27:50 +08:00
|
|
|
Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
|
|
|
|
<< SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
if (!Dependent) {
|
|
|
|
// FIXME: Dependent case loses a lot of information here. And probably
|
|
|
|
// leaks like a sieve.
|
|
|
|
for (unsigned i = 0; i != NumComponents; ++i) {
|
|
|
|
const OffsetOfComponent &OC = CompPtr[i];
|
|
|
|
if (OC.isBrackets) {
|
|
|
|
// Offset of an array sub-field. TODO: Should we allow vector elements?
|
|
|
|
const ArrayType *AT = Context.getAsArrayType(Res->getType());
|
|
|
|
if (!AT) {
|
|
|
|
Res->Destroy(Context);
|
|
|
|
return Diag(OC.LocEnd, diag::err_offsetof_array_type)
|
|
|
|
<< Res->getType();
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
// FIXME: C++: Verify that operator[] isn't overloaded.
|
2007-08-31 01:59:59 +08:00
|
|
|
|
2009-02-27 14:44:11 +08:00
|
|
|
// Promote the array so it looks more like a normal array subscript
|
|
|
|
// expression.
|
|
|
|
DefaultFunctionArrayConversion(Res);
|
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
// C99 6.5.2.1p1
|
|
|
|
Expr *Idx = static_cast<Expr*>(OC.U.E);
|
|
|
|
if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType())
|
|
|
|
return Diag(Idx->getLocStart(), diag::err_typecheck_subscript)
|
|
|
|
<< Idx->getSourceRange();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(),
|
|
|
|
OC.LocEnd);
|
|
|
|
continue;
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
const RecordType *RC = Res->getType()->getAsRecordType();
|
|
|
|
if (!RC) {
|
|
|
|
Res->Destroy(Context);
|
|
|
|
return Diag(OC.LocEnd, diag::err_offsetof_record_type)
|
|
|
|
<< Res->getType();
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
// Get the decl corresponding to this.
|
|
|
|
RecordDecl *RD = RC->getDecl();
|
|
|
|
FieldDecl *MemberDecl
|
|
|
|
= dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo,
|
|
|
|
LookupMemberName)
|
|
|
|
.getAsDecl());
|
|
|
|
if (!MemberDecl)
|
|
|
|
return Diag(BuiltinLoc, diag::err_typecheck_no_member)
|
|
|
|
<< OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd);
|
|
|
|
|
|
|
|
// FIXME: C++: Verify that MemberDecl isn't a static field.
|
|
|
|
// FIXME: Verify that MemberDecl isn't a bitfield.
|
|
|
|
// MemberDecl->getType() doesn't get the right qualifiers, but it doesn't
|
|
|
|
// matter here.
|
|
|
|
Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
|
2009-01-21 08:14:39 +08:00
|
|
|
MemberDecl->getType().getNonReferenceType());
|
2009-02-26 22:39:58 +08:00
|
|
|
}
|
2007-08-31 01:45:32 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
|
|
|
return new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf,
|
2009-01-21 08:14:39 +08:00
|
|
|
Context.getSizeType(), BuiltinLoc);
|
2007-08-31 01:45:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
Sema::ExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
|
2007-08-02 06:05:33 +08:00
|
|
|
TypeTy *arg1, TypeTy *arg2,
|
|
|
|
SourceLocation RPLoc) {
|
|
|
|
QualType argT1 = QualType::getFromOpaquePtr(arg1);
|
|
|
|
QualType argT2 = QualType::getFromOpaquePtr(arg2);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-02 06:05:33 +08:00
|
|
|
assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)");
|
2009-02-19 11:04:26 +08:00
|
|
|
|
|
|
|
return new (Context) TypesCompatibleExpr(Context.IntTy, BuiltinLoc, argT1,
|
2009-01-21 08:14:39 +08:00
|
|
|
argT2, RPLoc);
|
2007-08-02 06:05:33 +08:00
|
|
|
}
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond,
|
2007-08-04 05:21:27 +08:00
|
|
|
ExprTy *expr1, ExprTy *expr2,
|
|
|
|
SourceLocation RPLoc) {
|
|
|
|
Expr *CondExpr = static_cast<Expr*>(cond);
|
|
|
|
Expr *LHSExpr = static_cast<Expr*>(expr1);
|
|
|
|
Expr *RHSExpr = static_cast<Expr*>(expr2);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-08-04 05:21:27 +08:00
|
|
|
assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
|
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
QualType resType;
|
|
|
|
if (CondExpr->isValueDependent()) {
|
|
|
|
resType = Context.DependentTy;
|
|
|
|
} else {
|
|
|
|
// The conditional expression is required to be a constant expression.
|
|
|
|
llvm::APSInt condEval(32);
|
|
|
|
SourceLocation ExpLoc;
|
|
|
|
if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc))
|
|
|
|
return Diag(ExpLoc, diag::err_typecheck_choose_expr_requires_constant)
|
|
|
|
<< CondExpr->getSourceRange();
|
|
|
|
|
|
|
|
// If the condition is > zero, then the AST type is the same as the LSHExpr.
|
|
|
|
resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType();
|
|
|
|
}
|
2007-08-04 05:21:27 +08:00
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
return new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
|
2009-01-21 08:14:39 +08:00
|
|
|
resType, RPLoc);
|
2007-08-04 05:21:27 +08:00
|
|
|
}
|
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Clang Extensions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// ActOnBlockStart - This callback is invoked when a block literal is started.
|
2008-10-10 09:28:17 +08:00
|
|
|
void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
|
2008-09-04 02:15:37 +08:00
|
|
|
// Analyze block parameters.
|
|
|
|
BlockSemaInfo *BSI = new BlockSemaInfo();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// Add BSI to CurBlock.
|
|
|
|
BSI->PrevBlockInfo = CurBlock;
|
|
|
|
CurBlock = BSI;
|
2009-03-01 00:48:43 +08:00
|
|
|
ActiveScope = BlockScope;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
BSI->ReturnType = 0;
|
|
|
|
BSI->TheScope = BlockScope;
|
2009-02-20 06:01:56 +08:00
|
|
|
BSI->hasBlockDeclRefExprs = false;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-10-10 09:28:17 +08:00
|
|
|
BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc);
|
2008-12-12 00:49:14 +08:00
|
|
|
PushDeclContext(BlockScope, BSI->TheDecl);
|
2008-10-10 09:28:17 +08:00
|
|
|
}
|
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
|
|
|
|
assert(ParamInfo.getIdentifier() == 0 && "block-id should have no identifier!");
|
|
|
|
|
|
|
|
if (ParamInfo.getNumTypeObjects() == 0
|
|
|
|
|| ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
|
|
|
|
QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
|
|
|
|
|
|
|
|
// The type is entirely optional as well, if none, use DependentTy.
|
|
|
|
if (T.isNull())
|
|
|
|
T = Context.DependentTy;
|
|
|
|
|
|
|
|
// The parameter list is optional, if there was none, assume ().
|
|
|
|
if (!T->isFunctionType())
|
|
|
|
T = Context.getFunctionType(T, NULL, 0, 0, 0);
|
|
|
|
|
|
|
|
CurBlock->hasPrototype = true;
|
|
|
|
CurBlock->isVariadic = false;
|
|
|
|
Type *RetTy = T.getTypePtr()->getAsFunctionType()->getResultType()
|
|
|
|
.getTypePtr();
|
|
|
|
|
|
|
|
if (!RetTy->isDependentType())
|
|
|
|
CurBlock->ReturnType = RetTy;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// Analyze arguments to block.
|
|
|
|
assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function &&
|
|
|
|
"Not a function declarator!");
|
|
|
|
DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-10-10 09:28:17 +08:00
|
|
|
CurBlock->hasPrototype = FTI.hasPrototype;
|
|
|
|
CurBlock->isVariadic = true;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes
|
|
|
|
// no arguments, not a function that takes a single void argument.
|
|
|
|
if (FTI.hasPrototype &&
|
|
|
|
FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
|
|
|
|
(!((ParmVarDecl *)FTI.ArgInfo[0].Param)->getType().getCVRQualifiers() &&
|
|
|
|
((ParmVarDecl *)FTI.ArgInfo[0].Param)->getType()->isVoidType())) {
|
|
|
|
// empty arg list, don't push any params.
|
2008-10-10 09:28:17 +08:00
|
|
|
CurBlock->isVariadic = false;
|
2008-09-04 02:15:37 +08:00
|
|
|
} else if (FTI.hasPrototype) {
|
|
|
|
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
|
2008-10-10 09:28:17 +08:00
|
|
|
CurBlock->Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
|
|
|
|
CurBlock->isVariadic = FTI.isVariadic;
|
2009-02-05 06:31:32 +08:00
|
|
|
QualType T = GetTypeForDeclarator (ParamInfo, CurScope);
|
|
|
|
|
|
|
|
Type* RetTy = T.getTypePtr()->getAsFunctionType()->getResultType()
|
|
|
|
.getTypePtr();
|
|
|
|
|
|
|
|
if (!RetTy->isDependentType())
|
|
|
|
CurBlock->ReturnType = RetTy;
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2008-10-10 09:28:17 +08:00
|
|
|
CurBlock->TheDecl->setArgs(&CurBlock->Params[0], CurBlock->Params.size());
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-10-10 09:28:17 +08:00
|
|
|
for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
|
|
|
|
E = CurBlock->TheDecl->param_end(); AI != E; ++AI)
|
|
|
|
// If this has an identifier, add it to the scope stack.
|
|
|
|
if ((*AI)->getIdentifier())
|
|
|
|
PushOnScopeChains(*AI, CurBlock->TheScope);
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ActOnBlockError - If there is an error parsing a block, this callback
|
|
|
|
/// is invoked to pop the information about the block from the action impl.
|
|
|
|
void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
|
|
|
|
// Ensure that CurBlock is deleted.
|
|
|
|
llvm::OwningPtr<BlockSemaInfo> CC(CurBlock);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// Pop off CurBlock, handle nested blocks.
|
|
|
|
CurBlock = CurBlock->PrevBlockInfo;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// FIXME: Delete the ParmVarDecl objects as well???
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ActOnBlockStmtExpr - This is called when the body of a block statement
|
|
|
|
/// literal was successfully completed. ^(int x){...}
|
|
|
|
Sema::ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *body,
|
|
|
|
Scope *CurScope) {
|
|
|
|
// Ensure that CurBlock is deleted.
|
|
|
|
llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
|
2009-02-07 09:47:29 +08:00
|
|
|
ExprOwningPtr<CompoundStmt> Body(this, static_cast<CompoundStmt*>(body));
|
2008-09-04 02:15:37 +08:00
|
|
|
|
2008-10-10 09:28:17 +08:00
|
|
|
PopDeclContext();
|
|
|
|
|
2009-03-01 05:01:15 +08:00
|
|
|
// Before poping CurBlock, set ActiveScope to this scopes parent.
|
|
|
|
ActiveScope = CurBlock->TheScope->getParent();
|
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// Pop off CurBlock, handle nested blocks.
|
|
|
|
CurBlock = CurBlock->PrevBlockInfo;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
QualType RetTy = Context.VoidTy;
|
|
|
|
if (BSI->ReturnType)
|
|
|
|
RetTy = QualType(BSI->ReturnType, 0);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
llvm::SmallVector<QualType, 8> ArgTypes;
|
|
|
|
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
|
|
|
|
ArgTypes.push_back(BSI->Params[i]->getType());
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
QualType BlockTy;
|
|
|
|
if (!BSI->hasPrototype)
|
2009-02-27 07:50:07 +08:00
|
|
|
BlockTy = Context.getFunctionNoProtoType(RetTy);
|
2008-09-04 02:15:37 +08:00
|
|
|
else
|
|
|
|
BlockTy = Context.getFunctionType(RetTy, &ArgTypes[0], ArgTypes.size(),
|
2008-10-27 00:43:14 +08:00
|
|
|
BSI->isVariadic, 0);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
BlockTy = Context.getBlockPointerType(BlockTy);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-10-09 02:44:00 +08:00
|
|
|
BSI->TheDecl->setBody(Body.take());
|
2009-02-20 06:01:56 +08:00
|
|
|
return new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs);
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
|
|
|
|
2007-10-16 04:28:48 +08:00
|
|
|
Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
|
|
|
|
ExprTy *expr, TypeTy *type,
|
2008-01-05 02:04:52 +08:00
|
|
|
SourceLocation RPLoc) {
|
2007-10-16 04:28:48 +08:00
|
|
|
Expr *E = static_cast<Expr*>(expr);
|
|
|
|
QualType T = QualType::getFromOpaquePtr(type);
|
|
|
|
|
|
|
|
InitBuiltinVaListType();
|
2008-08-10 07:32:40 +08:00
|
|
|
|
|
|
|
// Get the va_list type
|
|
|
|
QualType VaListType = Context.getBuiltinVaListType();
|
|
|
|
// Deal with implicit array decay; for example, on x86-64,
|
|
|
|
// va_list is an array, but it's supposed to decay to
|
|
|
|
// a pointer for va_arg.
|
|
|
|
if (VaListType->isArrayType())
|
|
|
|
VaListType = Context.getArrayDecayedType(VaListType);
|
2008-08-21 06:17:17 +08:00
|
|
|
// Make sure the input expression also decays appropriately.
|
|
|
|
UsualUnaryConversions(E);
|
2008-08-10 07:32:40 +08:00
|
|
|
|
|
|
|
if (CheckAssignmentConstraints(VaListType, E->getType()) != Compatible)
|
2007-10-16 04:28:48 +08:00
|
|
|
return Diag(E->getLocStart(),
|
2008-11-20 14:06:08 +08:00
|
|
|
diag::err_first_argument_to_va_arg_not_of_type_va_list)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< E->getType() << E->getSourceRange();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-10-16 04:28:48 +08:00
|
|
|
// FIXME: Warn if a non-POD type is passed in.
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-01-21 08:14:39 +08:00
|
|
|
return new (Context) VAArgExpr(BuiltinLoc, E, T.getNonReferenceType(), RPLoc);
|
2007-10-16 04:28:48 +08:00
|
|
|
}
|
|
|
|
|
2008-11-29 12:51:27 +08:00
|
|
|
Sema::ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
|
|
|
|
// The type of __null will be int or long, depending on the size of
|
|
|
|
// pointers on the target.
|
|
|
|
QualType Ty;
|
|
|
|
if (Context.Target.getPointerWidth(0) == Context.Target.getIntWidth())
|
|
|
|
Ty = Context.IntTy;
|
|
|
|
else
|
|
|
|
Ty = Context.LongTy;
|
|
|
|
|
2009-01-21 08:14:39 +08:00
|
|
|
return new (Context) GNUNullExpr(Ty, TokenLoc);
|
2008-11-29 12:51:27 +08:00
|
|
|
}
|
|
|
|
|
2008-01-05 02:04:52 +08:00
|
|
|
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
SourceLocation Loc,
|
|
|
|
QualType DstType, QualType SrcType,
|
|
|
|
Expr *SrcExpr, const char *Flavor) {
|
|
|
|
// Decode the result (notice that AST's are still created for extensions).
|
|
|
|
bool isInvalid = false;
|
|
|
|
unsigned DiagKind;
|
|
|
|
switch (ConvTy) {
|
|
|
|
default: assert(0 && "Unknown conversion type");
|
|
|
|
case Compatible: return false;
|
2008-01-05 02:22:42 +08:00
|
|
|
case PointerToInt:
|
2008-01-05 02:04:52 +08:00
|
|
|
DiagKind = diag::ext_typecheck_convert_pointer_int;
|
|
|
|
break;
|
2008-01-05 02:22:42 +08:00
|
|
|
case IntToPointer:
|
|
|
|
DiagKind = diag::ext_typecheck_convert_int_pointer;
|
|
|
|
break;
|
2008-01-05 02:04:52 +08:00
|
|
|
case IncompatiblePointer:
|
|
|
|
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
|
|
|
|
break;
|
|
|
|
case FunctionVoidPointer:
|
|
|
|
DiagKind = diag::ext_typecheck_convert_pointer_void_func;
|
|
|
|
break;
|
|
|
|
case CompatiblePointerDiscardsQualifiers:
|
2008-09-12 08:47:35 +08:00
|
|
|
// If the qualifiers lost were because we were applying the
|
|
|
|
// (deprecated) C++ conversion from a string literal to a char*
|
|
|
|
// (or wchar_t*), then there was no error (C++ 4.2p2). FIXME:
|
|
|
|
// Ideally, this check would be performed in
|
|
|
|
// CheckPointerTypesForAssignment. However, that would require a
|
|
|
|
// bit of refactoring (so that the second argument is an
|
|
|
|
// expression, rather than a type), which should be done as part
|
|
|
|
// of a larger effort to fix CheckPointerTypesForAssignment for
|
|
|
|
// C++ semantics.
|
|
|
|
if (getLangOptions().CPlusPlus &&
|
|
|
|
IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType))
|
|
|
|
return false;
|
2008-01-05 02:04:52 +08:00
|
|
|
DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
|
|
|
|
break;
|
2008-09-04 23:10:53 +08:00
|
|
|
case IntToBlockPointer:
|
|
|
|
DiagKind = diag::err_int_to_block_pointer;
|
|
|
|
break;
|
|
|
|
case IncompatibleBlockPointer:
|
2008-09-25 07:31:10 +08:00
|
|
|
DiagKind = diag::ext_typecheck_convert_incompatible_block_pointer;
|
2008-09-04 23:10:53 +08:00
|
|
|
break;
|
2008-10-15 06:18:38 +08:00
|
|
|
case IncompatibleObjCQualifiedId:
|
2009-02-19 11:04:26 +08:00
|
|
|
// FIXME: Diagnose the problem in ObjCQualifiedIdTypesAreCompatible, since
|
2008-10-15 06:18:38 +08:00
|
|
|
// it can give a more specific diagnostic.
|
|
|
|
DiagKind = diag::warn_incompatible_qualified_id;
|
|
|
|
break;
|
2009-01-31 07:17:46 +08:00
|
|
|
case IncompatibleVectors:
|
|
|
|
DiagKind = diag::warn_incompatible_vectors;
|
|
|
|
break;
|
2008-01-05 02:04:52 +08:00
|
|
|
case Incompatible:
|
|
|
|
DiagKind = diag::err_typecheck_convert_incompatible;
|
|
|
|
isInvalid = true;
|
|
|
|
break;
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-11-24 13:29:24 +08:00
|
|
|
Diag(Loc, DiagKind) << DstType << SrcType << Flavor
|
|
|
|
<< SrcExpr->getSourceRange();
|
2008-01-05 02:04:52 +08:00
|
|
|
return isInvalid;
|
|
|
|
}
|
2008-12-01 03:50:32 +08:00
|
|
|
|
|
|
|
bool Sema::VerifyIntegerConstantExpression(const Expr* E, llvm::APSInt *Result)
|
|
|
|
{
|
|
|
|
Expr::EvalResult EvalResult;
|
|
|
|
|
2009-02-19 11:04:26 +08:00
|
|
|
if (!E->Evaluate(EvalResult, Context) || !EvalResult.Val.isInt() ||
|
2008-12-01 03:50:32 +08:00
|
|
|
EvalResult.HasSideEffects) {
|
|
|
|
Diag(E->getExprLoc(), diag::err_expr_not_ice) << E->getSourceRange();
|
|
|
|
|
|
|
|
if (EvalResult.Diag) {
|
|
|
|
// We only show the note if it's not the usual "invalid subexpression"
|
|
|
|
// or if it's actually in a subexpression.
|
|
|
|
if (EvalResult.Diag != diag::note_invalid_subexpr_in_ice ||
|
|
|
|
E->IgnoreParens() != EvalResult.DiagExpr->IgnoreParens())
|
|
|
|
Diag(EvalResult.DiagLoc, EvalResult.Diag);
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-12-01 03:50:32 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EvalResult.Diag) {
|
2009-02-19 11:04:26 +08:00
|
|
|
Diag(E->getExprLoc(), diag::ext_expr_not_ice) <<
|
2008-12-01 03:50:32 +08:00
|
|
|
E->getSourceRange();
|
|
|
|
|
|
|
|
// Print the reason it's not a constant.
|
|
|
|
if (Diags.getDiagnosticLevel(diag::ext_expr_not_ice) != Diagnostic::Ignored)
|
|
|
|
Diag(EvalResult.DiagLoc, EvalResult.Diag);
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-12-01 03:50:32 +08:00
|
|
|
if (Result)
|
|
|
|
*Result = EvalResult.Val.getInt();
|
|
|
|
return false;
|
|
|
|
}
|