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"
|
2009-11-18 15:57:50 +08:00
|
|
|
#include "Lookup.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"
|
2009-08-27 06:59:12 +08:00
|
|
|
#include "clang/AST/DeclTemplate.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-08-27 06:59:12 +08:00
|
|
|
#include "clang/Basic/PartialDiagnostic.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"
|
2009-08-27 06:59:12 +08:00
|
|
|
#include "clang/Lex/LiteralSupport.h"
|
|
|
|
#include "clang/Lex/Preprocessor.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"
|
2009-11-11 03:49:08 +08:00
|
|
|
#include "clang/Parse/Template.h"
|
2006-11-10 13:03:26 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-08-18 00:35:33 +08:00
|
|
|
|
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.
|
|
|
|
///
|
2009-10-26 06:31:57 +08:00
|
|
|
/// If IgnoreDeprecated is set to true, this should not want about deprecated
|
|
|
|
/// decls.
|
|
|
|
///
|
2009-02-19 05:56:37 +08:00
|
|
|
/// \returns true if there was an error (this declaration cannot be
|
|
|
|
/// referenced), false otherwise.
|
2009-10-26 06:31:57 +08:00
|
|
|
///
|
2009-11-04 10:18:39 +08:00
|
|
|
bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
|
2009-02-16 06:43:40 +08:00
|
|
|
// See if the decl is deprecated.
|
2009-06-30 10:34:44 +08:00
|
|
|
if (D->getAttr<DeprecatedAttr>()) {
|
2009-11-04 10:18:39 +08:00
|
|
|
EmitDeprecationWarning(D, Loc);
|
2009-02-16 06:43:40 +08:00
|
|
|
}
|
|
|
|
|
2009-10-26 01:21:40 +08:00
|
|
|
// See if the decl is unavailable
|
|
|
|
if (D->getAttr<UnavailableAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unavailable) << D->getDeclName();
|
|
|
|
Diag(D->getLocation(), diag::note_unavailable_here) << 0;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
return false;
|
2009-02-16 06:43:40 +08:00
|
|
|
}
|
|
|
|
|
2009-05-14 02:09:35 +08:00
|
|
|
/// DiagnoseSentinelCalls - This routine checks on method dispatch calls
|
2009-09-09 23:08:12 +08:00
|
|
|
/// (and other functions in future), which have been declared with sentinel
|
2009-05-14 02:09:35 +08:00
|
|
|
/// attribute. It warns if call does not have the sentinel argument.
|
|
|
|
///
|
|
|
|
void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
|
2009-09-09 23:08:12 +08:00
|
|
|
Expr **Args, unsigned NumArgs) {
|
2009-06-30 10:34:44 +08:00
|
|
|
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!attr)
|
2009-05-14 07:20:50 +08:00
|
|
|
return;
|
|
|
|
int sentinelPos = attr->getSentinel();
|
|
|
|
int nullPos = attr->getNullPos();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME. ObjCMethodDecl and FunctionDecl need be derived from the same common
|
|
|
|
// base class. Then we won't be needing two versions of the same code.
|
2009-05-14 07:20:50 +08:00
|
|
|
unsigned int i = 0;
|
2009-05-15 02:00:00 +08:00
|
|
|
bool warnNotEnoughArgs = false;
|
|
|
|
int isMethod = 0;
|
|
|
|
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
|
|
|
// skip over named parameters.
|
|
|
|
ObjCMethodDecl::param_iterator P, E = MD->param_end();
|
|
|
|
for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) {
|
|
|
|
if (nullPos)
|
|
|
|
--nullPos;
|
|
|
|
else
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
warnNotEnoughArgs = (P != E || i >= NumArgs);
|
|
|
|
isMethod = 1;
|
2009-08-05 05:02:39 +08:00
|
|
|
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
2009-05-15 02:00:00 +08:00
|
|
|
// skip over named parameters.
|
|
|
|
ObjCMethodDecl::param_iterator P, E = FD->param_end();
|
|
|
|
for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) {
|
|
|
|
if (nullPos)
|
|
|
|
--nullPos;
|
|
|
|
else
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
warnNotEnoughArgs = (P != E || i >= NumArgs);
|
2009-08-05 05:02:39 +08:00
|
|
|
} else if (VarDecl *V = dyn_cast<VarDecl>(D)) {
|
2009-05-16 04:33:25 +08:00
|
|
|
// block or function pointer call.
|
|
|
|
QualType Ty = V->getType();
|
|
|
|
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
const FunctionType *FT = Ty->isFunctionPointerType()
|
2009-09-22 07:43:11 +08:00
|
|
|
? Ty->getAs<PointerType>()->getPointeeType()->getAs<FunctionType>()
|
|
|
|
: Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
|
2009-05-16 04:33:25 +08:00
|
|
|
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) {
|
|
|
|
unsigned NumArgsInProto = Proto->getNumArgs();
|
|
|
|
unsigned k;
|
|
|
|
for (k = 0; (k != NumArgsInProto && i < NumArgs); k++) {
|
|
|
|
if (nullPos)
|
|
|
|
--nullPos;
|
|
|
|
else
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
warnNotEnoughArgs = (k != NumArgsInProto || i >= NumArgs);
|
|
|
|
}
|
|
|
|
if (Ty->isBlockPointerType())
|
|
|
|
isMethod = 2;
|
2009-08-05 05:02:39 +08:00
|
|
|
} else
|
2009-05-16 04:33:25 +08:00
|
|
|
return;
|
2009-08-05 05:02:39 +08:00
|
|
|
} else
|
2009-05-15 02:00:00 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (warnNotEnoughArgs) {
|
2009-05-14 07:20:50 +08:00
|
|
|
Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
|
2009-05-15 02:00:00 +08:00
|
|
|
Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
|
2009-05-14 07:20:50 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
int sentinel = i;
|
|
|
|
while (sentinelPos > 0 && i < NumArgs-1) {
|
|
|
|
--sentinelPos;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
if (sentinelPos > 0) {
|
|
|
|
Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
|
2009-05-15 02:00:00 +08:00
|
|
|
Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
|
2009-05-14 07:20:50 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (i < NumArgs-1) {
|
|
|
|
++i;
|
|
|
|
++sentinel;
|
|
|
|
}
|
|
|
|
Expr *sentinelExpr = Args[sentinel];
|
|
|
|
if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
|
2009-09-25 12:25:58 +08:00
|
|
|
!sentinelExpr->isNullPointerConstant(Context,
|
|
|
|
Expr::NPC_ValueDependentIsNull))) {
|
2009-05-16 04:33:25 +08:00
|
|
|
Diag(Loc, diag::warn_missing_sentinel) << isMethod;
|
2009-05-15 02:00:00 +08:00
|
|
|
Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
|
2009-05-14 07:20:50 +08:00
|
|
|
}
|
|
|
|
return;
|
2009-05-14 02:09:35 +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())
|
2009-09-09 23:08:12 +08:00
|
|
|
ImpCastExprToType(E, Context.getPointerType(Ty),
|
2009-09-02 04:37:18 +08:00
|
|
|
CastExpr::CK_FunctionToPointerDecay);
|
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)
|
2009-08-08 07:48:20 +08:00
|
|
|
ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
|
|
|
|
CastExpr::CK_ArrayToPointerDecay);
|
2008-07-26 05:33:13 +08:00
|
|
|
}
|
2008-07-26 05:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// UsualUnaryConversions - Performs various conversions that are common to most
|
2009-09-09 23:08:12 +08:00
|
|
|
/// operators (C99 6.3). The conversions of array and function types are
|
2008-07-26 05:10:04 +08:00
|
|
|
/// 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");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-02 04:41:21 +08:00
|
|
|
// C99 6.3.1.1p2:
|
|
|
|
//
|
|
|
|
// The following may be used in an expression wherever an int or
|
|
|
|
// unsigned int may be used:
|
|
|
|
// - an object or expression with an integer type whose integer
|
|
|
|
// conversion rank is less than or equal to the rank of int
|
|
|
|
// and unsigned int.
|
|
|
|
// - A bit-field of type _Bool, int, signed int, or unsigned int.
|
|
|
|
//
|
|
|
|
// If an int can represent all values of the original type, the
|
|
|
|
// value is converted to an int; otherwise, it is converted to an
|
|
|
|
// unsigned int. These are called the integer promotions. All
|
|
|
|
// other types are unchanged by the integer promotions.
|
2009-08-20 12:21:42 +08:00
|
|
|
QualType PTy = Context.isPromotableBitField(Expr);
|
|
|
|
if (!PTy.isNull()) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(Expr, PTy, CastExpr::CK_IntegralCast);
|
2009-08-20 12:21:42 +08:00
|
|
|
return Expr;
|
|
|
|
}
|
2009-05-02 04:41:21 +08:00
|
|
|
if (Ty->isPromotableIntegerType()) {
|
2009-08-19 15:44:53 +08:00
|
|
|
QualType PT = Context.getPromotedIntegerType(Ty);
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(Expr, PT, CastExpr::CK_IntegralCast);
|
2009-05-02 04:41:21 +08:00
|
|
|
return Expr;
|
2009-08-20 12:21:42 +08:00
|
|
|
}
|
|
|
|
|
2009-05-02 04:41:21 +08:00
|
|
|
DefaultFunctionArrayConversion(Expr);
|
2008-07-26 05:10:04 +08:00
|
|
|
return Expr;
|
|
|
|
}
|
|
|
|
|
2008-07-26 06:25:12 +08:00
|
|
|
/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
|
2009-09-09 23:08:12 +08:00
|
|
|
/// do not have a prototype. Arguments that have type float are promoted to
|
2008-07-26 06:25:12 +08:00
|
|
|
/// double. All other argument types are converted by UsualUnaryConversions().
|
|
|
|
void Sema::DefaultArgumentPromotion(Expr *&Expr) {
|
|
|
|
QualType Ty = Expr->getType();
|
|
|
|
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 06:25:12 +08:00
|
|
|
// If this is a 'float' (CVR qualified or typedef) promote to double.
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
|
2008-07-26 06:25:12 +08:00
|
|
|
if (BT->getKind() == BuiltinType::Float)
|
2009-10-20 16:27:19 +08:00
|
|
|
return ImpCastExprToType(Expr, Context.DoubleTy,
|
|
|
|
CastExpr::CK_FloatingCast);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-26 06:25:12 +08:00
|
|
|
UsualUnaryConversions(Expr);
|
|
|
|
}
|
|
|
|
|
2009-04-12 16:11:20 +08:00
|
|
|
/// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
|
|
|
|
/// will warn if the resulting type is not a POD type, and rejects ObjC
|
|
|
|
/// interfaces passed by value. This returns true if the argument type is
|
|
|
|
/// completely illegal.
|
|
|
|
bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
|
2009-01-17 00:48:51 +08:00
|
|
|
DefaultArgumentPromotion(Expr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 16:11:20 +08:00
|
|
|
if (Expr->getType()->isObjCInterfaceType()) {
|
|
|
|
Diag(Expr->getLocStart(),
|
|
|
|
diag::err_cannot_pass_objc_interface_to_vararg)
|
|
|
|
<< Expr->getType() << CT;
|
|
|
|
return true;
|
2009-01-17 00:48:51 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 16:11:20 +08:00
|
|
|
if (!Expr->getType()->isPODType())
|
|
|
|
Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg)
|
|
|
|
<< Expr->getType() << CT;
|
|
|
|
|
|
|
|
return false;
|
2009-01-17 00:48:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
2009-09-09 23:08:12 +08:00
|
|
|
/// routine returns the first non-arithmetic type found. The client is
|
2008-07-26 05:10:04 +08:00
|
|
|
/// 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) {
|
2009-03-28 09:22:36 +08:00
|
|
|
if (!isCompAssign)
|
2008-07-26 05:10:04 +08:00
|
|
|
UsualUnaryConversions(lhsExpr);
|
2009-03-28 09:22:36 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// For conversion purposes, we ignore any qualifiers.
|
2008-07-26 05:10:04 +08:00
|
|
|
// For example, "const float" and "float" are equivalent.
|
2008-07-27 06:17:49 +08:00
|
|
|
QualType lhs =
|
|
|
|
Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType();
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType rhs =
|
2008-07-27 06:17:49 +08:00
|
|
|
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;
|
|
|
|
|
2009-05-02 08:36:19 +08:00
|
|
|
// Perform bitfield promotions.
|
2009-08-20 12:21:42 +08:00
|
|
|
QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr);
|
2009-05-02 08:36:19 +08:00
|
|
|
if (!LHSBitfieldPromoteTy.isNull())
|
|
|
|
lhs = LHSBitfieldPromoteTy;
|
2009-08-20 12:21:42 +08:00
|
|
|
QualType RHSBitfieldPromoteTy = Context.isPromotableBitField(rhsExpr);
|
2009-05-02 08:36:19 +08:00
|
|
|
if (!RHSBitfieldPromoteTy.isNull())
|
|
|
|
rhs = RHSBitfieldPromoteTy;
|
|
|
|
|
2009-08-19 15:44:53 +08:00
|
|
|
QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs);
|
2009-03-28 09:22:36 +08:00
|
|
|
if (!isCompAssign)
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(lhsExpr, destType, CastExpr::CK_Unknown);
|
|
|
|
ImpCastExprToType(rhsExpr, destType, CastExpr::CK_Unknown);
|
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
|
|
|
return destType;
|
|
|
|
}
|
|
|
|
|
2008-07-26 05:10:04 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// 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-09-09 23:08:12 +08:00
|
|
|
|
2006-11-10 13:03:26 +08:00
|
|
|
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
|
2009-09-09 23:08:12 +08:00
|
|
|
return Owned(StringLiteral::Create(Context, Literal.GetString(),
|
2009-02-18 14:40:38 +08:00
|
|
|
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).
|
|
|
|
///
|
2009-04-22 06:26:47 +08:00
|
|
|
/// This also keeps the 'hasBlockDeclRefExprs' in the BlockSemaInfo records
|
|
|
|
/// up-to-date.
|
|
|
|
///
|
2008-10-20 13:16:36 +08:00
|
|
|
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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:16:36 +08:00
|
|
|
// 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))
|
2009-04-22 06:26:47 +08:00
|
|
|
if (!Var->hasLocalStorage())
|
|
|
|
return false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-22 06:26:47 +08:00
|
|
|
// Blocks that have these can't be constant.
|
|
|
|
CurBlock->hasBlockDeclRefExprs = true;
|
|
|
|
|
|
|
|
// If we have nested blocks, the decl may be declared in an outer block (in
|
|
|
|
// which case that outer block doesn't get "hasBlockDeclRefExprs") or it may
|
|
|
|
// be defined outside all of the current blocks (in which case the blocks do
|
|
|
|
// all get the bit). Walk the nesting chain.
|
|
|
|
for (BlockSemaInfo *NextBlock = CurBlock->PrevBlockInfo; NextBlock;
|
|
|
|
NextBlock = NextBlock->PrevBlockInfo) {
|
|
|
|
// If we found the defining block for the variable, don't mark the block as
|
|
|
|
// having a reference outside it.
|
|
|
|
if (NextBlock->TheDecl == VD->getDeclContext())
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-22 06:26:47 +08:00
|
|
|
// Otherwise, the DeclRef from the inner block causes the outer one to need
|
|
|
|
// a snapshot as well.
|
|
|
|
NextBlock->hasBlockDeclRefExprs = true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-20 13:16:36 +08:00
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
|
|
|
|
2008-10-20 13:16:36 +08:00
|
|
|
|
|
|
|
|
2009-10-24 02:54:35 +08:00
|
|
|
/// BuildDeclRefExpr - Build a DeclRefExpr.
|
2009-06-24 08:10:43 +08:00
|
|
|
Sema::OwningExprResult
|
2009-02-04 04:19:35 +08:00
|
|
|
Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
|
|
|
|
bool TypeDependent, bool ValueDependent,
|
|
|
|
const CXXScopeSpec *SS) {
|
2009-06-27 03:16:07 +08:00
|
|
|
if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
|
|
|
|
Diag(Loc,
|
2009-09-09 23:08:12 +08:00
|
|
|
diag::err_auto_variable_cannot_appear_in_own_initializer)
|
2009-06-27 03:16:07 +08:00
|
|
|
<< D->getDeclName();
|
|
|
|
return ExprError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-24 08:10:43 +08:00
|
|
|
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
|
|
|
|
if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
|
|
|
|
if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
|
2009-06-24 08:10:43 +08:00
|
|
|
<< D->getIdentifier() << FD->getDeclName();
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(D->getLocation(), diag::note_local_variable_declared_here)
|
2009-06-24 08:10:43 +08:00
|
|
|
<< D->getIdentifier();
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
MarkDeclarationReferenced(Loc, D);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-24 02:54:35 +08:00
|
|
|
return Owned(DeclRefExpr::Create(Context,
|
|
|
|
SS? (NestedNameSpecifier *)SS->getScopeRep() : 0,
|
|
|
|
SS? SS->getRange() : SourceRange(),
|
|
|
|
D, Loc,
|
|
|
|
Ty, 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-04-10 05:40:53 +08:00
|
|
|
static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
|
|
|
|
RecordDecl *Record) {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(Record->isAnonymousStructOrUnion() &&
|
2009-01-07 08:43:41 +08:00
|
|
|
"Record must be an anonymous struct or union!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: Once Decls are directly linked together, this will 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.
|
2009-01-07 08:43:41 +08:00
|
|
|
DeclContext *Ctx = Record->getDeclContext();
|
2009-09-09 23:08:12 +08:00
|
|
|
for (DeclContext::decl_iterator D = Ctx->decls_begin(),
|
2009-06-30 10:36:12 +08:00
|
|
|
DEnd = Ctx->decls_end();
|
2009-01-07 08:43:41 +08:00
|
|
|
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-04-15 14:41:24 +08:00
|
|
|
/// \brief Given a field that represents a member of an anonymous
|
|
|
|
/// struct/union, build the path from that field's context to the
|
|
|
|
/// actual member.
|
|
|
|
///
|
|
|
|
/// 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.
|
|
|
|
///
|
|
|
|
/// \returns The variable from which the field access should begin,
|
|
|
|
/// for an anonymous struct/union that is not a member of another
|
|
|
|
/// class. Otherwise, returns NULL.
|
|
|
|
VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
|
|
|
|
llvm::SmallVectorImpl<FieldDecl *> &Path) {
|
2009-01-07 08:43:41 +08:00
|
|
|
assert(Field->getDeclContext()->isRecord() &&
|
|
|
|
cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()
|
|
|
|
&& "Field must be stored inside an anonymous struct or union");
|
|
|
|
|
2009-04-15 14:41:24 +08:00
|
|
|
Path.push_back(Field);
|
2009-01-07 08:43:41 +08:00
|
|
|
VarDecl *BaseObject = 0;
|
|
|
|
DeclContext *Ctx = Field->getDeclContext();
|
|
|
|
do {
|
|
|
|
RecordDecl *Record = cast<RecordDecl>(Ctx);
|
2009-04-10 05:40:53 +08:00
|
|
|
Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record);
|
2009-01-07 08:43:41 +08:00
|
|
|
if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject))
|
2009-04-15 14:41:24 +08:00
|
|
|
Path.push_back(AnonField);
|
2009-01-07 08:43:41 +08:00
|
|
|
else {
|
|
|
|
BaseObject = cast<VarDecl>(AnonObject);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Ctx = Ctx->getParent();
|
2009-09-09 23:08:12 +08:00
|
|
|
} while (Ctx->isRecord() &&
|
2009-01-07 08:43:41 +08:00
|
|
|
cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
|
2009-04-15 14:41:24 +08:00
|
|
|
|
|
|
|
return BaseObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sema::OwningExprResult
|
|
|
|
Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
|
|
|
FieldDecl *Field,
|
|
|
|
Expr *BaseObjectExpr,
|
|
|
|
SourceLocation OpLoc) {
|
|
|
|
llvm::SmallVector<FieldDecl *, 4> AnonFields;
|
2009-09-09 23:08:12 +08:00
|
|
|
VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
|
2009-04-15 14:41:24 +08:00
|
|
|
AnonFields);
|
|
|
|
|
2009-01-07 08:43:41 +08:00
|
|
|
// 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;
|
2009-09-25 03:53:00 +08:00
|
|
|
Qualifiers BaseQuals;
|
2009-01-07 08:43:41 +08:00
|
|
|
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-06-20 07:52:42 +08:00
|
|
|
MarkDeclarationReferenced(Loc, BaseObject);
|
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-09-25 03:53:00 +08:00
|
|
|
BaseQuals
|
|
|
|
= Context.getCanonicalType(BaseObject->getType()).getQualifiers();
|
2009-01-07 08:43:41 +08:00
|
|
|
} 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();
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const PointerType *ObjectPtr = ObjectType->getAs<PointerType>()) {
|
2009-01-07 08:43:41 +08:00
|
|
|
BaseObjectIsPointer = true;
|
|
|
|
ObjectType = ObjectPtr->getPointeeType();
|
|
|
|
}
|
2009-09-25 03:53:00 +08:00
|
|
|
BaseQuals
|
|
|
|
= Context.getCanonicalType(ObjectType).getQualifiers();
|
2009-01-07 08:43:41 +08:00
|
|
|
} 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()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType AnonFieldType
|
2009-01-07 08:43:41 +08:00
|
|
|
= Context.getTagDeclType(
|
|
|
|
cast<RecordDecl>(AnonFields.back()->getDeclContext()));
|
|
|
|
QualType ThisType = Context.getTagDeclType(MD->getParent());
|
2009-09-09 23:08:12 +08:00
|
|
|
if ((Context.getCanonicalType(AnonFieldType)
|
2009-01-07 08:43:41 +08:00
|
|
|
== 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
|
|
|
}
|
2009-09-25 03:53:00 +08:00
|
|
|
BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
|
2009-01-07 08:43:41 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
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;
|
2009-09-25 03:53:00 +08:00
|
|
|
Qualifiers ResultQuals = BaseQuals;
|
2009-01-07 08:43:41 +08:00
|
|
|
for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
|
|
|
|
FI = AnonFields.rbegin(), FIEnd = AnonFields.rend();
|
|
|
|
FI != FIEnd; ++FI) {
|
|
|
|
QualType MemberType = (*FI)->getType();
|
2009-09-25 03:53:00 +08:00
|
|
|
Qualifiers MemberTypeQuals =
|
|
|
|
Context.getCanonicalType(MemberType).getQualifiers();
|
|
|
|
|
|
|
|
// CVR attributes from the base are picked up by members,
|
|
|
|
// except that 'mutable' members don't pick up 'const'.
|
|
|
|
if ((*FI)->isMutable())
|
|
|
|
ResultQuals.removeConst();
|
|
|
|
|
|
|
|
// GC attributes are never picked up by members.
|
|
|
|
ResultQuals.removeObjCGCAttr();
|
|
|
|
|
|
|
|
// TR 18037 does not allow fields to be declared with address spaces.
|
|
|
|
assert(!MemberTypeQuals.hasAddressSpace());
|
|
|
|
|
|
|
|
Qualifiers NewQuals = ResultQuals + MemberTypeQuals;
|
|
|
|
if (NewQuals != MemberTypeQuals)
|
|
|
|
MemberType = Context.getQualifiedType(MemberType, NewQuals);
|
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
MarkDeclarationReferenced(Loc, *FI);
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
// FIXME: Might this end up being a qualified name?
|
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;
|
2009-09-25 03:53:00 +08:00
|
|
|
ResultQuals = NewQuals;
|
2009-01-07 08:43:41 +08:00
|
|
|
}
|
|
|
|
|
2009-01-19 02:53:16 +08:00
|
|
|
return Owned(Result);
|
2009-01-07 08:43:41 +08:00
|
|
|
}
|
|
|
|
|
2009-11-04 00:56:39 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
|
|
|
|
const CXXScopeSpec &SS,
|
|
|
|
UnqualifiedId &Name,
|
|
|
|
bool HasTrailingLParen,
|
|
|
|
bool IsAddressOfOperand) {
|
|
|
|
if (Name.getKind() == UnqualifiedId::IK_TemplateId) {
|
|
|
|
ASTTemplateArgsPtr TemplateArgsPtr(*this,
|
|
|
|
Name.TemplateId->getTemplateArgs(),
|
|
|
|
Name.TemplateId->NumArgs);
|
|
|
|
return ActOnTemplateIdExpr(SS,
|
|
|
|
TemplateTy::make(Name.TemplateId->Template),
|
|
|
|
Name.TemplateId->TemplateNameLoc,
|
|
|
|
Name.TemplateId->LAngleLoc,
|
|
|
|
TemplateArgsPtr,
|
|
|
|
Name.TemplateId->RAngleLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: We lose a bunch of source information by doing this. Later,
|
|
|
|
// we'll want to merge ActOnDeclarationNameExpr's logic into
|
|
|
|
// ActOnIdExpression.
|
|
|
|
return ActOnDeclarationNameExpr(S,
|
|
|
|
Name.StartLocation,
|
|
|
|
GetNameFromUnqualifiedId(Name),
|
|
|
|
HasTrailingLParen,
|
|
|
|
&SS,
|
|
|
|
IsAddressOfOperand);
|
|
|
|
}
|
|
|
|
|
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,
|
2009-11-04 00:56:39 +08:00
|
|
|
/// this routine is called by ActOnIdExpression, which contains a
|
|
|
|
/// parsed UnqualifiedId.
|
2008-11-18 23:03:34 +08:00
|
|
|
///
|
|
|
|
/// 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-09-09 23:08:12 +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();
|
Introduce a new expression type, UnresolvedDeclRefExpr, that describes
dependent qualified-ids such as
Fibonacci<N - 1>::value
where N is a template parameter. These references are "unresolved"
because the name is dependent and, therefore, cannot be resolved to a
declaration node (as we would do for a DeclRefExpr or
QualifiedDeclRefExpr). UnresolvedDeclRefExprs instantiate to
DeclRefExprs, QualifiedDeclRefExprs, etc.
Also, be a bit more careful about keeping only a single set of
specializations for a class template, and instantiating from the
definition of that template rather than a previous declaration. In
general, we need a better solution for this for all TagDecls, because
it's too easy to accidentally look at a declaration that isn't the
definition.
We can now process a simple Fibonacci computation described as a
template metaprogram.
llvm-svn: 67308
2009-03-20 01:26:29 +08:00
|
|
|
|
|
|
|
// C++ [temp.dep.expr]p3:
|
|
|
|
// An id-expression is type-dependent if it contains:
|
|
|
|
// -- a nested-name-specifier that contains a class-name that
|
|
|
|
// names a dependent type.
|
2009-05-29 22:49:33 +08:00
|
|
|
// FIXME: Member of the current instantiation.
|
Introduce a new expression type, UnresolvedDeclRefExpr, that describes
dependent qualified-ids such as
Fibonacci<N - 1>::value
where N is a template parameter. These references are "unresolved"
because the name is dependent and, therefore, cannot be resolved to a
declaration node (as we would do for a DeclRefExpr or
QualifiedDeclRefExpr). UnresolvedDeclRefExprs instantiate to
DeclRefExprs, QualifiedDeclRefExprs, etc.
Also, be a bit more careful about keeping only a single set of
specializations for a class template, and instantiating from the
definition of that template rather than a previous declaration. In
general, we need a better solution for this for all TagDecls, because
it's too easy to accidentally look at a declaration that isn't the
definition.
We can now process a simple Fibonacci computation described as a
template metaprogram.
llvm-svn: 67308
2009-03-20 01:26:29 +08:00
|
|
|
if (SS && isDependentScopeSpecifier(*SS)) {
|
2009-03-27 07:50:42 +08:00
|
|
|
return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy,
|
2009-09-09 23:08:12 +08:00
|
|
|
Loc, SS->getRange(),
|
2009-07-09 08:05:08 +08:00
|
|
|
static_cast<NestedNameSpecifier *>(SS->getScopeRep()),
|
|
|
|
isAddressOfOperand));
|
Introduce a new expression type, UnresolvedDeclRefExpr, that describes
dependent qualified-ids such as
Fibonacci<N - 1>::value
where N is a template parameter. These references are "unresolved"
because the name is dependent and, therefore, cannot be resolved to a
declaration node (as we would do for a DeclRefExpr or
QualifiedDeclRefExpr). UnresolvedDeclRefExprs instantiate to
DeclRefExprs, QualifiedDeclRefExprs, etc.
Also, be a bit more careful about keeping only a single set of
specializations for a class template, and instantiating from the
definition of that template rather than a previous declaration. In
general, we need a better solution for this for all TagDecls, because
it's too easy to accidentally look at a declaration that isn't the
definition.
We can now process a simple Fibonacci computation described as a
template metaprogram.
llvm-svn: 67308
2009-03-20 01:26:29 +08:00
|
|
|
}
|
|
|
|
|
2009-11-17 10:14:36 +08:00
|
|
|
LookupResult Lookup(*this, Name, Loc, LookupOrdinaryName);
|
|
|
|
LookupParsedName(Lookup, S, SS, true);
|
2009-01-15 08:26:24 +08:00
|
|
|
|
2009-11-17 10:14:36 +08:00
|
|
|
if (Lookup.isAmbiguous())
|
2009-01-19 02:53:16 +08:00
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-10 05:13:30 +08:00
|
|
|
NamedDecl *D = Lookup.getAsSingleDecl(Context);
|
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-09-09 23:08:12 +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
|
2009-03-03 05:55:29 +08:00
|
|
|
// 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;
|
2009-06-30 10:36:12 +08:00
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2009-04-25 06:30:50 +08:00
|
|
|
// If we're referencing an invalid decl, just return this as a silent
|
|
|
|
// error node. The error diagnostic was already emitted on the decl.
|
|
|
|
if (IV->isInvalidDecl())
|
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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-05-16 15:39:55 +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.
|
2009-03-03 05:55:29 +08:00
|
|
|
IdentifierInfo &II = Context.Idents.get("self");
|
2009-11-04 00:56:39 +08:00
|
|
|
UnqualifiedId SelfName;
|
|
|
|
SelfName.setIdentifier(&II, SourceLocation());
|
|
|
|
CXXScopeSpec SelfScopeSpec;
|
|
|
|
OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
|
|
|
|
SelfName, false, false);
|
2009-06-20 07:52:42 +08:00
|
|
|
MarkDeclarationReferenced(Loc, IV);
|
2009-09-09 23:08:12 +08:00
|
|
|
return Owned(new (Context)
|
|
|
|
ObjCIvarRefExpr(IV, IV->getType(), Loc,
|
2009-05-02 03:49:17 +08:00
|
|
|
SelfExpr.takeAs<Expr>(), true, true));
|
2009-03-03 05:55:29 +08:00
|
|
|
}
|
2008-03-31 08:36:02 +08:00
|
|
|
}
|
2009-08-05 05:02:39 +08:00
|
|
|
} else if (getCurMethodDecl()->isInstanceMethod()) {
|
2009-03-03 05:55:29 +08:00
|
|
|
// We should warn if a local variable hides an ivar.
|
|
|
|
ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
|
2009-03-03 09:21:12 +08:00
|
|
|
ObjCInterfaceDecl *ClassDeclared;
|
2009-06-30 10:36:12 +08:00
|
|
|
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
|
2009-03-03 09:21:12 +08:00
|
|
|
if (IV->getAccessControl() != ObjCIvarDecl::Private ||
|
|
|
|
IFace == ClassDeclared)
|
2009-04-25 06:30:50 +08:00
|
|
|
Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName();
|
2009-03-03 09:21:12 +08:00
|
|
|
}
|
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")) {
|
2009-03-06 04:12:00 +08:00
|
|
|
QualType T;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-06 04:12:00 +08:00
|
|
|
if (getCurMethodDecl()->isInstanceMethod())
|
2009-07-11 07:34:53 +08:00
|
|
|
T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
|
|
|
|
getCurMethodDecl()->getClassInterface()));
|
2009-03-06 04:12:00 +08:00
|
|
|
else
|
|
|
|
T = Context.getObjCClassType();
|
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.
|
2009-09-09 23:08:12 +08:00
|
|
|
bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
|
2009-02-19 05:56:37 +08:00
|
|
|
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.
|
2009-10-14 05:16:44 +08:00
|
|
|
if (SS && !SS->isEmpty())
|
|
|
|
return ExprError(Diag(Loc, diag::err_no_member)
|
|
|
|
<< Name << computeDeclContext(*SS, false)
|
|
|
|
<< SS->getRange());
|
|
|
|
else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
|
2008-11-18 23:03:34 +08:00
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2009-06-30 23:47:41 +08:00
|
|
|
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
|
|
|
// Warn about constructs like:
|
|
|
|
// if (void *X = foo()) { ... } else { X }.
|
|
|
|
// In the else block, the pointer is always false.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-30 23:47:41 +08:00
|
|
|
// FIXME: In a template instantiation, we don't have scope
|
|
|
|
// information to check this property.
|
|
|
|
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
|
|
|
|
Scope *CheckS = S;
|
2009-11-06 01:49:26 +08:00
|
|
|
while (CheckS && CheckS->getControlParent()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (CheckS->isWithinElse() &&
|
2009-06-30 23:47:41 +08:00
|
|
|
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
|
2009-11-06 01:49:26 +08:00
|
|
|
ExprError(Diag(Loc, diag::warn_value_always_zero)
|
|
|
|
<< Var->getDeclName()
|
|
|
|
<< (Var->getType()->isPointerType()? 2 :
|
|
|
|
Var->getType()->isBooleanType()? 1 : 0));
|
2009-06-30 23:47:41 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-06 01:49:26 +08:00
|
|
|
// Move to the parent of this scope.
|
|
|
|
CheckS = CheckS->getParent();
|
2009-06-30 23:47:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
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.
|
|
|
|
if (DiagnoseUseOfDecl(Func, Loc))
|
|
|
|
return ExprError();
|
2009-01-07 08:43:41 +08:00
|
|
|
|
2009-06-30 23:47:41 +08:00
|
|
|
QualType T = Func->getType();
|
|
|
|
QualType NoProtoType = T;
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>())
|
2009-06-30 23:47:41 +08:00
|
|
|
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
|
|
|
|
return BuildDeclRefExpr(Func, NoProtoType, Loc, false, false, SS);
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-30 23:47:41 +08:00
|
|
|
return BuildDeclarationNameExpr(Loc, D, HasTrailingLParen, SS, isAddressOfOperand);
|
|
|
|
}
|
2009-07-30 02:40:24 +08:00
|
|
|
/// \brief Cast member's object to its own class if necessary.
|
2009-07-30 03:40:11 +08:00
|
|
|
bool
|
2009-07-30 02:40:24 +08:00
|
|
|
Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) {
|
|
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(Member))
|
2009-09-09 23:08:12 +08:00
|
|
|
if (CXXRecordDecl *RD =
|
2009-07-30 02:40:24 +08:00
|
|
|
dyn_cast<CXXRecordDecl>(FD->getDeclContext())) {
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType DestType =
|
2009-07-30 02:40:24 +08:00
|
|
|
Context.getCanonicalType(Context.getTypeDeclType(RD));
|
2009-07-30 04:41:46 +08:00
|
|
|
if (DestType->isDependentType() || From->getType()->isDependentType())
|
|
|
|
return false;
|
|
|
|
QualType FromRecordType = From->getType();
|
|
|
|
QualType DestRecordType = DestType;
|
2009-07-30 05:53:49 +08:00
|
|
|
if (FromRecordType->getAs<PointerType>()) {
|
2009-07-30 04:41:46 +08:00
|
|
|
DestType = Context.getPointerType(DestType);
|
|
|
|
FromRecordType = FromRecordType->getPointeeType();
|
2009-07-30 02:40:24 +08:00
|
|
|
}
|
2009-07-30 04:41:46 +08:00
|
|
|
if (!Context.hasSameUnqualifiedType(FromRecordType, DestRecordType) &&
|
|
|
|
CheckDerivedToBaseConversion(FromRecordType,
|
|
|
|
DestRecordType,
|
|
|
|
From->getSourceRange().getBegin(),
|
|
|
|
From->getSourceRange()))
|
|
|
|
return true;
|
2009-07-31 09:23:52 +08:00
|
|
|
ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
|
|
|
|
/*isLvalue=*/true);
|
2009-07-30 02:40:24 +08:00
|
|
|
}
|
2009-07-30 03:40:11 +08:00
|
|
|
return false;
|
2009-07-30 02:40:24 +08:00
|
|
|
}
|
2009-06-30 23:47:41 +08:00
|
|
|
|
2009-09-01 07:41:50 +08:00
|
|
|
/// \brief Build a MemberExpr AST node.
|
2009-09-09 23:08:12 +08:00
|
|
|
static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
|
|
|
|
const CXXScopeSpec *SS, NamedDecl *Member,
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
SourceLocation Loc, QualType Ty) {
|
|
|
|
if (SS && SS->isSet())
|
2009-09-09 23:08:12 +08:00
|
|
|
return MemberExpr::Create(C, Base, isArrow,
|
2009-09-01 07:41:50 +08:00
|
|
|
(NestedNameSpecifier *)SS->getScopeRep(),
|
2009-09-09 23:08:12 +08:00
|
|
|
SS->getRange(), Member, Loc,
|
2009-09-01 08:37:14 +08:00
|
|
|
// FIXME: Explicit template argument lists
|
|
|
|
false, SourceLocation(), 0, 0, SourceLocation(),
|
|
|
|
Ty);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty);
|
|
|
|
}
|
|
|
|
|
2009-06-30 23:47:41 +08:00
|
|
|
/// \brief Complete semantic analysis for a reference to the given declaration.
|
|
|
|
Sema::OwningExprResult
|
|
|
|
Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
|
|
|
|
bool HasTrailingLParen,
|
2009-09-09 23:08:12 +08:00
|
|
|
const CXXScopeSpec *SS,
|
2009-06-30 23:47:41 +08:00
|
|
|
bool isAddressOfOperand) {
|
|
|
|
assert(D && "Cannot refer to a NULL declaration");
|
|
|
|
DeclarationName Name = D->getDeclName();
|
2009-09-09 23:08:12 +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) {
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
DeclContext *DC = computeDeclContext(*SS);
|
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.
|
2009-05-29 22:49:33 +08:00
|
|
|
bool Dependent = DC->isDependentContext();
|
2009-06-24 08:10:43 +08:00
|
|
|
return 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]).
|
2009-10-22 15:08:30 +08:00
|
|
|
// FIXME: This needs to happen post-isImplicitMemberReference?
|
2009-01-07 08:43:41 +08:00
|
|
|
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
|
|
|
|
2009-10-22 15:08:30 +08:00
|
|
|
// Cope with an implicit member access in a C++ non-static member function.
|
|
|
|
QualType ThisType, MemberType;
|
|
|
|
if (isImplicitMemberReference(SS, D, Loc, ThisType, MemberType)) {
|
|
|
|
Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
|
|
|
|
MarkDeclarationReferenced(Loc, D);
|
|
|
|
if (PerformObjectMemberConversion(This, D))
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
bool ShouldCheckUse = true;
|
|
|
|
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
|
|
|
|
// Don't diagnose the use of a virtual member function unless it's
|
|
|
|
// explicitly qualified.
|
|
|
|
if (MD->isVirtual() && (!SS || !SS->isSet()))
|
|
|
|
ShouldCheckUse = false;
|
2008-12-22 13:46:06 +08:00
|
|
|
}
|
2009-10-22 15:08:30 +08:00
|
|
|
|
|
|
|
if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc))
|
|
|
|
return ExprError();
|
|
|
|
return Owned(BuildMemberExpr(Context, This, true, SS, D,
|
|
|
|
Loc, 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-06-24 08:10:43 +08:00
|
|
|
return BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
|
|
|
|
false, false, SS);
|
2009-02-10 07:23:08 +08:00
|
|
|
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
|
2009-06-24 08:10:43 +08:00
|
|
|
return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
|
|
|
|
false, false, SS);
|
2009-11-18 10:36:19 +08:00
|
|
|
else if (UnresolvedUsingValueDecl *UD = dyn_cast<UnresolvedUsingValueDecl>(D))
|
2009-09-09 23:08:12 +08:00
|
|
|
return BuildDeclRefExpr(UD, Context.DependentTy, Loc,
|
|
|
|
/*TypeDependent=*/true,
|
2009-08-29 09:06:32 +08:00
|
|
|
/*ValueDependent=*/true, 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.
|
2009-09-09 23:08:12 +08:00
|
|
|
bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
|
2009-06-30 23:47:41 +08:00
|
|
|
HasTrailingLParen;
|
2009-02-19 05:56:37 +08:00
|
|
|
if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
|
|
|
|
return ExprError();
|
|
|
|
|
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-06-20 07:52:42 +08:00
|
|
|
MarkDeclarationReferenced(Loc, VD);
|
2009-03-23 07:00:19 +08:00
|
|
|
QualType ExprTy = VD->getType().getNonReferenceType();
|
2008-10-10 09:28:17 +08:00
|
|
|
// The BlocksAttr indicates the variable is bound by-reference.
|
2009-06-30 10:34:44 +08:00
|
|
|
if (VD->getAttr<BlocksAttr>())
|
2009-03-23 07:00:19 +08:00
|
|
|
return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, true));
|
2009-06-20 07:37:08 +08:00
|
|
|
// This is to record that a 'const' was actually synthesize and added.
|
|
|
|
bool constAdded = !ExprTy.isConstQualified();
|
2008-10-10 09:28:17 +08:00
|
|
|
// Variable will be bound by-copy, make it const within the closure.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-23 07:00:19 +08:00
|
|
|
ExprTy.addConst();
|
2009-09-09 23:08:12 +08:00
|
|
|
return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false,
|
2009-06-20 07:37:08 +08:00
|
|
|
constAdded));
|
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:
|
2009-09-09 23:08:12 +08:00
|
|
|
// An id-expression is type-dependent if it contains:
|
2008-12-11 04:57:37 +08:00
|
|
|
// - 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()) {
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
for (DeclContext *DC = computeDeclContext(*SS);
|
2008-12-11 04:57:37 +08:00
|
|
|
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
|
2009-06-11 09:11:20 +08:00
|
|
|
else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) {
|
2009-11-04 06:20:01 +08:00
|
|
|
if (Context.getCanonicalType(Dcl->getType()).getCVRQualifiers()
|
|
|
|
== Qualifiers::Const &&
|
2009-06-11 09:11:20 +08:00
|
|
|
Dcl->getInit()) {
|
|
|
|
ValueDependent = Dcl->getInit()->isValueDependent();
|
|
|
|
}
|
|
|
|
}
|
2008-12-11 04:57:37 +08:00
|
|
|
}
|
2008-12-06 07:32:09 +08:00
|
|
|
|
2009-06-24 08:10:43 +08:00
|
|
|
return 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.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-09 02:24:21 +08:00
|
|
|
Decl *currentDecl = getCurFunctionOrMethodDecl();
|
|
|
|
if (!currentDecl) {
|
2008-12-12 13:05:20 +08:00
|
|
|
Diag(Loc, diag::ext_predef_outside_function);
|
2009-09-09 02:24:21 +08:00
|
|
|
currentDecl = Context.getTranslationUnitDecl();
|
2008-12-12 13:05:20 +08:00
|
|
|
}
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2009-09-11 09:22:35 +08:00
|
|
|
QualType ResTy;
|
|
|
|
if (cast<DeclContext>(currentDecl)->isDependentContext()) {
|
|
|
|
ResTy = Context.DependentTy;
|
|
|
|
} else {
|
|
|
|
unsigned Length =
|
|
|
|
PredefinedExpr::ComputeName(Context, IT, currentDecl).length();
|
2009-01-19 02:53:16 +08:00
|
|
|
|
2009-09-11 09:22:35 +08:00
|
|
|
llvm::APInt LengthI(32, Length + 1);
|
2009-09-25 03:53:00 +08:00
|
|
|
ResTy = Context.CharTy.withConst();
|
2009-09-11 09:22:35 +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
|
|
|
|
2009-09-09 23:08:12 +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-06-30 01:34:55 +08:00
|
|
|
llvm::APFloat Val = Literal.GetFloatValue(Format, &isExact);
|
|
|
|
Res = new (Context) FloatingLiteral(Val, 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-09-09 23:08:12 +08:00
|
|
|
Res = new (Context) ImaginaryLiteral(Res,
|
2009-01-21 08:14:39 +08:00
|
|
|
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) {
|
2009-05-02 03:49:17 +08:00
|
|
|
Expr *E = Val.takeAs<Expr>();
|
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-11-04 15:28:41 +08:00
|
|
|
if (exprType->isFunctionType()) {
|
2009-04-24 08:30:45 +08:00
|
|
|
// alignof(function) is allowed as an extension.
|
2009-01-25 03:46:37 +08:00
|
|
|
if (isSizeof)
|
|
|
|
Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange;
|
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-24 08:30:45 +08:00
|
|
|
// Allow sizeof(void)/alignof(void) as an extension.
|
2009-01-25 03:46:37 +08:00
|
|
|
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;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-24 08:30:45 +08:00
|
|
|
if (RequireCompleteType(OpLoc, exprType,
|
2009-09-09 23:08:12 +08:00
|
|
|
isSizeof ? diag::err_sizeof_incomplete_type :
|
2009-08-27 07:45:07 +08:00
|
|
|
PDiag(diag::err_alignof_incomplete_type)
|
|
|
|
<< ExprRange))
|
2009-04-24 08:30:45 +08:00
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-24 08:30:45 +08:00
|
|
|
// Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
|
2009-04-25 01:34:33 +08:00
|
|
|
if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) {
|
2009-04-24 08:30:45 +08:00
|
|
|
Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
|
2009-04-25 06:30:50 +08:00
|
|
|
<< exprType << isSizeof << ExprRange;
|
|
|
|
return true;
|
2009-04-22 03:55:16 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-24 08:30:45 +08:00
|
|
|
return false;
|
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-09-09 23:08:12 +08:00
|
|
|
// alignof decl is always ok.
|
2009-01-25 04:17:12 +08:00
|
|
|
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-05-02 10:18:30 +08:00
|
|
|
if (E->getBitField()) {
|
|
|
|
Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange;
|
|
|
|
return true;
|
2009-01-25 04:17:12 +08:00
|
|
|
}
|
2009-05-02 10:18:30 +08:00
|
|
|
|
|
|
|
// Alignment of a field access is always okay, so long as it isn't a
|
|
|
|
// bit-field.
|
|
|
|
if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
|
2009-07-23 02:58:19 +08:00
|
|
|
if (isa<FieldDecl>(ME->getMemberDecl()))
|
2009-05-02 10:18:30 +08:00
|
|
|
return false;
|
|
|
|
|
2009-01-25 04:17:12 +08:00
|
|
|
return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
|
|
|
|
}
|
|
|
|
|
2009-03-14 05:01:28 +08:00
|
|
|
/// \brief Build a sizeof or alignof expression given a type operand.
|
2009-09-09 23:08:12 +08:00
|
|
|
Action::OwningExprResult
|
2009-11-04 15:28:41 +08:00
|
|
|
Sema::CreateSizeOfAlignOfExpr(DeclaratorInfo *DInfo,
|
|
|
|
SourceLocation OpLoc,
|
2009-03-14 05:01:28 +08:00
|
|
|
bool isSizeOf, SourceRange R) {
|
2009-11-04 15:28:41 +08:00
|
|
|
if (!DInfo)
|
2009-03-14 05:01:28 +08:00
|
|
|
return ExprError();
|
|
|
|
|
2009-11-04 15:28:41 +08:00
|
|
|
QualType T = DInfo->getType();
|
|
|
|
|
2009-03-14 05:01:28 +08:00
|
|
|
if (!T->isDependentType() &&
|
|
|
|
CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf))
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
|
2009-11-04 15:28:41 +08:00
|
|
|
return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, DInfo,
|
2009-03-14 05:01:28 +08:00
|
|
|
Context.getSizeType(), OpLoc,
|
|
|
|
R.getEnd()));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Build a sizeof or alignof expression given an expression
|
|
|
|
/// operand.
|
2009-09-09 23:08:12 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
|
2009-03-14 05:01:28 +08:00
|
|
|
bool isSizeOf, SourceRange R) {
|
|
|
|
// Verify that the operand is valid.
|
|
|
|
bool isInvalid = false;
|
|
|
|
if (E->isTypeDependent()) {
|
|
|
|
// Delay type-checking for type-dependent expressions.
|
|
|
|
} else if (!isSizeOf) {
|
|
|
|
isInvalid = CheckAlignOfExpr(E, OpLoc, R);
|
2009-05-02 10:18:30 +08:00
|
|
|
} else if (E->getBitField()) { // C99 6.5.3.4p1.
|
2009-03-14 05:01:28 +08:00
|
|
|
Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isInvalid)
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
|
|
|
|
return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E,
|
|
|
|
Context.getSizeType(), OpLoc,
|
|
|
|
R.getEnd()));
|
|
|
|
}
|
|
|
|
|
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
|
|
|
if (isType) {
|
2009-11-04 15:28:41 +08:00
|
|
|
DeclaratorInfo *DInfo;
|
|
|
|
(void) GetTypeFromParser(TyOrEx, &DInfo);
|
|
|
|
return CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeof, ArgRange);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2008-11-12 01:56:53 +08:00
|
|
|
|
2009-03-14 05:01:28 +08:00
|
|
|
Expr *ArgEx = (Expr *)TyOrEx;
|
|
|
|
Action::OwningExprResult Result
|
|
|
|
= CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange());
|
|
|
|
|
|
|
|
if (Result.isInvalid())
|
|
|
|
DeleteExpr(ArgEx);
|
|
|
|
|
|
|
|
return move(Result);
|
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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-26 13:39:26 +08:00
|
|
|
// These operators return the element type of a complex type.
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const ComplexType *CT = V->getType()->getAs<ComplexType>())
|
2007-08-25 05:16:53 +08:00
|
|
|
return CT->getElementType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-26 13:39:26 +08:00
|
|
|
// 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) {
|
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
|
|
|
|
2009-11-18 11:38:04 +08:00
|
|
|
return BuildUnaryOp(S, OpLoc, Opc, move(Input));
|
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) {
|
2009-08-11 07:49:36 +08:00
|
|
|
// Since this might be a postfix expression, get rid of ParenListExprs.
|
|
|
|
Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
|
|
|
|
|
2009-01-19 08:08:26 +08:00
|
|
|
Expr *LHSExp = static_cast<Expr*>(Base.get()),
|
|
|
|
*RHSExp = static_cast<Expr*>(Idx.get());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-20 01:17:41 +08:00
|
|
|
if (getLangOptions().CPlusPlus &&
|
2009-05-19 08:01:19 +08:00
|
|
|
(LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) {
|
|
|
|
Base.release();
|
|
|
|
Idx.release();
|
|
|
|
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
|
|
|
|
Context.DependentTy, RLoc));
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +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())) {
|
2009-10-30 04:17:01 +08:00
|
|
|
return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, move(Base),move(Idx));
|
|
|
|
}
|
2008-11-20 01:17:41 +08:00
|
|
|
|
2009-10-30 04:17:01 +08:00
|
|
|
return CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc);
|
|
|
|
}
|
2009-02-19 05:56:37 +08:00
|
|
|
|
2008-11-20 01:17:41 +08:00
|
|
|
|
2009-10-30 04:17:01 +08:00
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc,
|
|
|
|
ExprArg Idx, SourceLocation RLoc) {
|
|
|
|
Expr *LHSExp = static_cast<Expr*>(Base.get());
|
|
|
|
Expr *RHSExp = static_cast<Expr*>(Idx.get());
|
2008-11-20 01:17:41 +08:00
|
|
|
|
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;
|
2009-07-30 05:53:49 +08:00
|
|
|
} else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) {
|
2007-07-16 08:14:47 +08:00
|
|
|
BaseExpr = LHSExp;
|
|
|
|
IndexExpr = RHSExp;
|
|
|
|
ResultType = PTy->getPointeeType();
|
2009-07-30 05:53:49 +08:00
|
|
|
} else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
|
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;
|
|
|
|
ResultType = PTy->getPointeeType();
|
2009-09-09 23:08:12 +08:00
|
|
|
} else if (const ObjCObjectPointerType *PTy =
|
2009-09-22 07:43:11 +08:00
|
|
|
LHSTy->getAs<ObjCObjectPointerType>()) {
|
2009-07-11 07:34:53 +08:00
|
|
|
BaseExpr = LHSExp;
|
|
|
|
IndexExpr = RHSExp;
|
|
|
|
ResultType = PTy->getPointeeType();
|
2009-09-09 23:08:12 +08:00
|
|
|
} else if (const ObjCObjectPointerType *PTy =
|
2009-09-22 07:43:11 +08:00
|
|
|
RHSTy->getAs<ObjCObjectPointerType>()) {
|
2009-07-11 07:34:53 +08:00
|
|
|
// Handle the uncommon case of "123[Ptr]".
|
|
|
|
BaseExpr = RHSExp;
|
|
|
|
IndexExpr = LHSExp;
|
|
|
|
ResultType = PTy->getPointeeType();
|
2009-09-22 07:43:11 +08:00
|
|
|
} else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) {
|
2007-08-01 03:29:30 +08:00
|
|
|
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();
|
2009-04-26 07:46:54 +08:00
|
|
|
} else if (LHSTy->isArrayType()) {
|
|
|
|
// If we see an array that wasn't promoted by
|
|
|
|
// DefaultFunctionArrayConversion, it must be an array that
|
|
|
|
// wasn't promoted because of the C90 rule that doesn't
|
|
|
|
// allow promoting non-lvalue arrays. Warn, then
|
|
|
|
// force the promotion here.
|
|
|
|
Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
|
|
|
|
LHSExp->getSourceRange();
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy),
|
|
|
|
CastExpr::CK_ArrayToPointerDecay);
|
2009-04-26 07:46:54 +08:00
|
|
|
LHSTy = LHSExp->getType();
|
|
|
|
|
|
|
|
BaseExpr = LHSExp;
|
|
|
|
IndexExpr = RHSExp;
|
2009-07-30 05:53:49 +08:00
|
|
|
ResultType = LHSTy->getAs<PointerType>()->getPointeeType();
|
2009-04-26 07:46:54 +08:00
|
|
|
} else if (RHSTy->isArrayType()) {
|
|
|
|
// Same as previous, except for 123[f().a] case
|
|
|
|
Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
|
|
|
|
RHSExp->getSourceRange();
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy),
|
|
|
|
CastExpr::CK_ArrayToPointerDecay);
|
2009-04-26 07:46:54 +08:00
|
|
|
RHSTy = RHSExp->getType();
|
|
|
|
|
|
|
|
BaseExpr = RHSExp;
|
|
|
|
IndexExpr = LHSExp;
|
2009-07-30 05:53:49 +08:00
|
|
|
ResultType = RHSTy->getAs<PointerType>()->getPointeeType();
|
2007-06-09 11:47:53 +08:00
|
|
|
} else {
|
2009-04-26 06:50:55 +08:00
|
|
|
return ExprError(Diag(LLoc, diag::err_typecheck_subscript_value)
|
|
|
|
<< LHSExp->getSourceRange() << RHSExp->getSourceRange());
|
2009-01-19 08:08:26 +08:00
|
|
|
}
|
2007-03-29 05:49:40 +08:00
|
|
|
// C99 6.5.2.1p1
|
2009-08-11 07:49:36 +08:00
|
|
|
if (!(IndexExpr->getType()->isIntegerType() &&
|
|
|
|
IndexExpr->getType()->isScalarType()) && !IndexExpr->isTypeDependent())
|
2009-04-26 06:50:55 +08:00
|
|
|
return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer)
|
|
|
|
<< IndexExpr->getSourceRange());
|
2007-07-16 08:14:47 +08:00
|
|
|
|
2009-09-17 14:31:17 +08:00
|
|
|
if ((IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
|
2009-09-15 04:14:57 +08:00
|
|
|
IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
|
|
|
|
&& !IndexExpr->isTypeDependent())
|
2009-09-14 09:58:58 +08:00
|
|
|
Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange();
|
|
|
|
|
2009-03-25 03:52:54 +08:00
|
|
|
// C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
|
2009-09-09 23:08:12 +08:00
|
|
|
// C++ [expr.sub]p1: The type "T" shall be a completely-defined object
|
|
|
|
// type. Note that Functions are not objects, and that (in C99 parlance)
|
2009-03-25 03:52:54 +08:00
|
|
|
// incomplete types are not object types.
|
|
|
|
if (ResultType->isFunctionType()) {
|
|
|
|
Diag(BaseExpr->getLocStart(), diag::err_subscript_function_type)
|
|
|
|
<< ResultType << BaseExpr->getSourceRange();
|
|
|
|
return ExprError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-25 03:52:54 +08:00
|
|
|
if (!ResultType->isDependentType() &&
|
2009-09-09 23:08:12 +08:00
|
|
|
RequireCompleteType(LLoc, ResultType,
|
2009-08-27 07:45:07 +08:00
|
|
|
PDiag(diag::err_subscript_incomplete_type)
|
|
|
|
<< BaseExpr->getSourceRange()))
|
2009-03-25 03:52:54 +08:00
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-24 08:30:45 +08:00
|
|
|
// Diagnose bad cases where we step over interface counts.
|
|
|
|
if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
|
|
|
|
Diag(LLoc, diag::err_subscript_nonfragile_interface)
|
|
|
|
<< ResultType << BaseExpr->getSourceRange();
|
|
|
|
return ExprError();
|
|
|
|
}
|
2009-09-09 23:08:12 +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,
|
2009-09-09 23:08:12 +08:00
|
|
|
const IdentifierInfo *CompName,
|
2009-08-27 02:25:21 +08:00
|
|
|
SourceLocation CompLoc) {
|
2009-10-18 10:09:38 +08:00
|
|
|
// FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements,
|
|
|
|
// see FIXME there.
|
|
|
|
//
|
|
|
|
// FIXME: This logic can be greatly simplified by splitting it along
|
|
|
|
// halving/not halving and reworking the component checking.
|
2009-09-22 07:43:11 +08:00
|
|
|
const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
|
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.
|
2009-10-19 04:26:12 +08:00
|
|
|
const char *compStr = CompName->getNameStart();
|
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.
|
2009-06-26 05:06:09 +08:00
|
|
|
bool HexSwizzle = *compStr == 's' || *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) {
|
2009-10-19 04:26:12 +08:00
|
|
|
compStr = CompName->getNameStart();
|
2009-01-18 09:47:54 +08:00
|
|
|
|
|
|
|
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
|
2009-08-27 02:25:21 +08:00
|
|
|
: CompName->getLength();
|
2009-01-18 09:47:54 +08:00
|
|
|
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-03-20 02:15:34 +08:00
|
|
|
static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
|
2009-08-27 02:25:21 +08:00
|
|
|
IdentifierInfo *Member,
|
2009-04-10 05:40:53 +08:00
|
|
|
const Selector &Sel,
|
|
|
|
ASTContext &Context) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-27 02:25:21 +08:00
|
|
|
if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
|
2009-03-20 02:15:34 +08:00
|
|
|
return PD;
|
2009-06-30 10:36:12 +08:00
|
|
|
if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
|
2009-03-20 02:15:34 +08:00
|
|
|
return OMD;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-20 02:15:34 +08:00
|
|
|
for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
|
|
|
|
E = PDecl->protocol_end(); I != E; ++I) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel,
|
2009-04-10 05:40:53 +08:00
|
|
|
Context))
|
2009-03-20 02:15:34 +08:00
|
|
|
return D;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-18 06:40:22 +08:00
|
|
|
static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
|
2009-08-27 02:25:21 +08:00
|
|
|
IdentifierInfo *Member,
|
2009-04-10 05:40:53 +08:00
|
|
|
const Selector &Sel,
|
|
|
|
ASTContext &Context) {
|
2009-03-20 02:15:34 +08:00
|
|
|
// Check protocols on qualified interfaces.
|
|
|
|
Decl *GDecl = 0;
|
2009-06-18 06:40:22 +08:00
|
|
|
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
|
2009-03-20 02:15:34 +08:00
|
|
|
E = QIdTy->qual_end(); I != E; ++I) {
|
2009-08-27 02:25:21 +08:00
|
|
|
if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
|
2009-03-20 02:15:34 +08:00
|
|
|
GDecl = PD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Also must look for a getter name which uses property syntax.
|
2009-06-30 10:36:12 +08:00
|
|
|
if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
|
2009-03-20 02:15:34 +08:00
|
|
|
GDecl = OMD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!GDecl) {
|
2009-06-18 06:40:22 +08:00
|
|
|
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
|
2009-03-20 02:15:34 +08:00
|
|
|
E = QIdTy->qual_end(); I != E; ++I) {
|
|
|
|
// Search in the protocol-qualifier list of current protocol.
|
2009-04-10 05:40:53 +08:00
|
|
|
GDecl = FindGetterNameDeclFromProtocolList(*I, Member, Sel, Context);
|
2009-03-20 02:15:34 +08:00
|
|
|
if (GDecl)
|
|
|
|
return GDecl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return GDecl;
|
|
|
|
}
|
2009-02-16 06:43:40 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
Action::OwningExprResult
|
2009-08-27 02:25:21 +08:00
|
|
|
Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
2009-01-19 08:08:26 +08:00
|
|
|
tok::TokenKind OpKind, SourceLocation MemberLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclarationName MemberName,
|
2009-09-01 08:37:14 +08:00
|
|
|
bool HasExplicitTemplateArgs,
|
|
|
|
SourceLocation LAngleLoc,
|
2009-10-29 16:12:44 +08:00
|
|
|
const TemplateArgumentLoc *ExplicitTemplateArgs,
|
2009-09-01 08:37:14 +08:00
|
|
|
unsigned NumExplicitTemplateArgs,
|
|
|
|
SourceLocation RAngleLoc,
|
2009-09-04 05:38:09 +08:00
|
|
|
DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS,
|
|
|
|
NamedDecl *FirstQualifierInScope) {
|
2009-08-06 11:17:00 +08:00
|
|
|
if (SS && SS->isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
|
2009-08-11 07:49:36 +08:00
|
|
|
// Since this might be a postfix expression, get rid of ParenListExprs.
|
|
|
|
Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
|
|
|
|
|
2009-05-02 03:30:39 +08:00
|
|
|
Expr *BaseExpr = Base.takeAs<Expr>();
|
2009-09-05 01:36:40 +08:00
|
|
|
assert(BaseExpr && "no base expression");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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();
|
2009-11-06 14:30:47 +08:00
|
|
|
|
|
|
|
// If the user is trying to apply -> or . to a function pointer
|
|
|
|
// type, it's probably because the forgot parentheses to call that
|
|
|
|
// function. Suggest the addition of those parentheses, build the
|
|
|
|
// call, and continue on.
|
|
|
|
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
|
|
|
|
if (const FunctionProtoType *Fun
|
|
|
|
= Ptr->getPointeeType()->getAs<FunctionProtoType>()) {
|
|
|
|
QualType ResultTy = Fun->getResultType();
|
|
|
|
if (Fun->getNumArgs() == 0 &&
|
|
|
|
((OpKind == tok::period && ResultTy->isRecordType()) ||
|
|
|
|
(OpKind == tok::arrow && ResultTy->isPointerType() &&
|
|
|
|
ResultTy->getAs<PointerType>()->getPointeeType()
|
|
|
|
->isRecordType()))) {
|
|
|
|
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
|
|
|
|
Diag(Loc, diag::err_member_reference_needs_call)
|
|
|
|
<< QualType(Fun, 0)
|
|
|
|
<< CodeModificationHint::CreateInsertion(Loc, "()");
|
|
|
|
|
|
|
|
OwningExprResult NewBase
|
|
|
|
= ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc,
|
|
|
|
MultiExprArg(*this, 0, 0), 0, Loc);
|
|
|
|
if (NewBase.isInvalid())
|
|
|
|
return move(NewBase);
|
|
|
|
|
|
|
|
BaseExpr = NewBase.takeAs<Expr>();
|
|
|
|
DefaultFunctionArrayConversion(BaseExpr);
|
|
|
|
BaseType = BaseExpr->getType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-18 00:35:33 +08:00
|
|
|
// If this is an Objective-C pseudo-builtin and a definition is provided then
|
|
|
|
// use that.
|
|
|
|
if (BaseType->isObjCIdType()) {
|
|
|
|
// We have an 'id' type. Rather than fall through, we check if this
|
|
|
|
// is a reference to 'isa'.
|
|
|
|
if (BaseType != Context.ObjCIdRedefinitionType) {
|
|
|
|
BaseType = Context.ObjCIdRedefinitionType;
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast);
|
2009-08-18 00:35:33 +08:00
|
|
|
}
|
|
|
|
}
|
2007-07-26 11:11:44 +08:00
|
|
|
assert(!BaseType.isNull() && "no type for member expression");
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2009-09-23 00:48:37 +08:00
|
|
|
// Handle properties on ObjC 'Class' types.
|
|
|
|
if (OpKind == tok::period && BaseType->isObjCClassType()) {
|
|
|
|
// Also must look for a getter name which uses property syntax.
|
|
|
|
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
|
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
|
|
|
|
if (ObjCMethodDecl *MD = getCurMethodDecl()) {
|
|
|
|
ObjCInterfaceDecl *IFace = MD->getClassInterface();
|
|
|
|
ObjCMethodDecl *Getter;
|
|
|
|
// FIXME: need to also look locally in the implementation.
|
|
|
|
if ((Getter = IFace->lookupClassMethod(Sel))) {
|
|
|
|
// Check the use of this method.
|
|
|
|
if (DiagnoseUseOfDecl(Getter, MemberLoc))
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
// If we found a getter then this may be a valid dot-reference, we
|
|
|
|
// will look for the matching setter, in case it is needed.
|
|
|
|
Selector SetterSel =
|
|
|
|
SelectorTable::constructSetterName(PP.getIdentifierTable(),
|
|
|
|
PP.getSelectorTable(), Member);
|
|
|
|
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
|
|
|
|
if (!Setter) {
|
|
|
|
// If this reference is in an @implementation, also check for 'private'
|
|
|
|
// methods.
|
2009-10-02 07:46:04 +08:00
|
|
|
Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
|
2009-09-23 00:48:37 +08:00
|
|
|
}
|
|
|
|
// Look through local category implementations associated with the class.
|
|
|
|
if (!Setter)
|
|
|
|
Setter = IFace->getCategoryClassMethod(SetterSel);
|
|
|
|
|
|
|
|
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
if (Getter || Setter) {
|
|
|
|
QualType PType;
|
|
|
|
|
|
|
|
if (Getter)
|
|
|
|
PType = Getter->getResultType();
|
|
|
|
else
|
|
|
|
// Get the expression type from Setter's incoming parameter.
|
|
|
|
PType = (*(Setter->param_end() -1))->getType();
|
|
|
|
// FIXME: we must check that the setter has property type.
|
|
|
|
return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter,
|
|
|
|
PType,
|
|
|
|
Setter, MemberLoc, BaseExpr));
|
|
|
|
}
|
|
|
|
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
|
|
|
<< MemberName << BaseType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BaseType->isObjCClassType() &&
|
|
|
|
BaseType != Context.ObjCClassRedefinitionType) {
|
|
|
|
BaseType = Context.ObjCClassRedefinitionType;
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast);
|
2009-09-23 00:48:37 +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) {
|
2009-09-04 05:38:09 +08:00
|
|
|
if (BaseType->isDependentType()) {
|
|
|
|
NestedNameSpecifier *Qualifier = 0;
|
|
|
|
if (SS) {
|
|
|
|
Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
|
|
|
|
if (!FirstQualifierInScope)
|
|
|
|
FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
return Owned(CXXUnresolvedMemberExpr::Create(Context, BaseExpr, true,
|
2009-09-09 08:23:06 +08:00
|
|
|
OpLoc, Qualifier,
|
2009-09-04 00:14:30 +08:00
|
|
|
SS? SS->getRange() : SourceRange(),
|
2009-09-09 08:23:06 +08:00
|
|
|
FirstQualifierInScope,
|
|
|
|
MemberName,
|
|
|
|
MemberLoc,
|
|
|
|
HasExplicitTemplateArgs,
|
|
|
|
LAngleLoc,
|
|
|
|
ExplicitTemplateArgs,
|
|
|
|
NumExplicitTemplateArgs,
|
|
|
|
RAngleLoc));
|
2009-09-04 05:38:09 +08:00
|
|
|
}
|
2009-07-30 05:53:49 +08:00
|
|
|
else if (const PointerType *PT = BaseType->getAs<PointerType>())
|
2007-07-26 11:11:44 +08:00
|
|
|
BaseType = PT->getPointeeType();
|
2009-07-11 07:34:53 +08:00
|
|
|
else if (BaseType->isObjCObjectPointerType())
|
|
|
|
;
|
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());
|
2009-09-23 00:48:37 +08:00
|
|
|
} else if (BaseType->isDependentType()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
// Require that the base type isn't a pointer type
|
2009-05-17 04:31:20 +08:00
|
|
|
// (so we'll report an error for)
|
|
|
|
// T* t;
|
|
|
|
// t.f;
|
2009-09-09 23:08:12 +08:00
|
|
|
//
|
2009-05-17 04:31:20 +08:00
|
|
|
// In Obj-C++, however, the above expression is valid, since it could be
|
|
|
|
// accessing the 'f' property if T is an Obj-C interface. The extra check
|
|
|
|
// allows this, while still reporting an error if T is a struct pointer.
|
2009-07-30 05:53:49 +08:00
|
|
|
const PointerType *PT = BaseType->getAs<PointerType>();
|
2009-05-17 04:31:20 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!PT || (getLangOptions().ObjC1 &&
|
2009-09-04 05:38:09 +08:00
|
|
|
!PT->getPointeeType()->isRecordType())) {
|
|
|
|
NestedNameSpecifier *Qualifier = 0;
|
|
|
|
if (SS) {
|
|
|
|
Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
|
|
|
|
if (!FirstQualifierInScope)
|
|
|
|
FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-09 08:23:06 +08:00
|
|
|
return Owned(CXXUnresolvedMemberExpr::Create(Context,
|
2009-09-09 23:08:12 +08:00
|
|
|
BaseExpr, false,
|
|
|
|
OpLoc,
|
2009-09-09 08:23:06 +08:00
|
|
|
Qualifier,
|
2009-09-04 00:14:30 +08:00
|
|
|
SS? SS->getRange() : SourceRange(),
|
2009-09-09 08:23:06 +08:00
|
|
|
FirstQualifierInScope,
|
|
|
|
MemberName,
|
|
|
|
MemberLoc,
|
|
|
|
HasExplicitTemplateArgs,
|
|
|
|
LAngleLoc,
|
|
|
|
ExplicitTemplateArgs,
|
|
|
|
NumExplicitTemplateArgs,
|
|
|
|
RAngleLoc));
|
2009-09-04 05:38:09 +08:00
|
|
|
}
|
2009-05-17 04:31:20 +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.
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
|
2007-07-26 11:11:44 +08:00
|
|
|
RecordDecl *RDecl = RTy->getDecl();
|
2009-03-10 00:13:40 +08:00
|
|
|
if (RequireCompleteType(OpLoc, BaseType,
|
2009-08-27 07:45:07 +08:00
|
|
|
PDiag(diag::err_typecheck_incomplete_tag)
|
|
|
|
<< BaseExpr->getSourceRange()))
|
2009-01-20 03:26:10 +08:00
|
|
|
return ExprError();
|
|
|
|
|
2009-08-06 11:17:00 +08:00
|
|
|
DeclContext *DC = RDecl;
|
|
|
|
if (SS && SS->isSet()) {
|
|
|
|
// If the member name was a qualified-id, look into the
|
|
|
|
// nested-name-specifier.
|
|
|
|
DC = computeDeclContext(*SS, false);
|
2009-10-18 06:37:54 +08:00
|
|
|
|
|
|
|
if (!isa<TypeDecl>(DC)) {
|
|
|
|
Diag(MemberLoc, diag::err_qualified_member_nonclass)
|
|
|
|
<< DC << SS->getRange();
|
|
|
|
return ExprError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// FIXME: If DC is not computable, we should build a
|
2009-08-06 11:17:00 +08:00
|
|
|
// CXXUnresolvedMemberExpr.
|
|
|
|
assert(DC && "Cannot handle non-computable dependent contexts in lookup");
|
|
|
|
}
|
|
|
|
|
2007-07-26 11:11:44 +08:00
|
|
|
// The record definition is complete, now make sure the member is valid.
|
2009-11-17 10:14:36 +08:00
|
|
|
LookupResult Result(*this, MemberName, MemberLoc, LookupMemberName);
|
|
|
|
LookupQualifiedName(Result, DC);
|
2009-01-15 08:26:24 +08:00
|
|
|
|
2009-10-10 05:13:30 +08:00
|
|
|
if (Result.empty())
|
2009-10-14 05:16:44 +08:00
|
|
|
return ExprError(Diag(MemberLoc, diag::err_no_member)
|
|
|
|
<< MemberName << DC << BaseExpr->getSourceRange());
|
2009-11-17 10:14:36 +08:00
|
|
|
if (Result.isAmbiguous())
|
2009-09-04 00:14:30 +08:00
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-10 05:13:30 +08:00
|
|
|
NamedDecl *MemberDecl = Result.getAsSingleDecl(Context);
|
|
|
|
|
2009-08-06 13:28:30 +08:00
|
|
|
if (SS && SS->isSet()) {
|
2009-10-10 05:13:30 +08:00
|
|
|
TypeDecl* TyD = cast<TypeDecl>(MemberDecl->getDeclContext());
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType BaseTypeCanon
|
2009-08-06 11:17:00 +08:00
|
|
|
= Context.getCanonicalType(BaseType).getUnqualifiedType();
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType MemberTypeCanon
|
2009-10-10 05:13:30 +08:00
|
|
|
= Context.getCanonicalType(Context.getTypeDeclType(TyD));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 11:17:00 +08:00
|
|
|
if (BaseTypeCanon != MemberTypeCanon &&
|
|
|
|
!IsDerivedFrom(BaseTypeCanon, MemberTypeCanon))
|
|
|
|
return ExprError(Diag(SS->getBeginLoc(),
|
|
|
|
diag::err_not_direct_base_or_virtual)
|
|
|
|
<< MemberTypeCanon << BaseTypeCanon);
|
|
|
|
}
|
2009-09-09 23:08:12 +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-09-11 04:48:14 +08:00
|
|
|
bool ShouldCheckUse = true;
|
|
|
|
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
|
|
|
|
// Don't diagnose the use of a virtual member function unless it's
|
|
|
|
// explicitly qualified.
|
|
|
|
if (MD->isVirtual() && (!SS || !SS->isSet()))
|
|
|
|
ShouldCheckUse = false;
|
|
|
|
}
|
2009-09-17 14:31:17 +08:00
|
|
|
|
2009-02-19 05:56:37 +08:00
|
|
|
// Check the use of this field
|
2009-09-11 04:48:14 +08:00
|
|
|
if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc))
|
2009-02-19 05:56:37 +08:00
|
|
|
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]
|
2008-12-23 08:26:44 +08:00
|
|
|
QualType MemberType = FD->getType();
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>())
|
2008-12-21 07:49:58 +08:00
|
|
|
MemberType = Ref->getPointeeType();
|
|
|
|
else {
|
2009-09-25 03:53:00 +08:00
|
|
|
Qualifiers BaseQuals = BaseType.getQualifiers();
|
|
|
|
BaseQuals.removeObjCGCAttr();
|
|
|
|
if (FD->isMutable()) BaseQuals.removeConst();
|
|
|
|
|
|
|
|
Qualifiers MemberQuals
|
|
|
|
= Context.getCanonicalType(MemberType).getQualifiers();
|
|
|
|
|
|
|
|
Qualifiers Combined = BaseQuals + MemberQuals;
|
|
|
|
if (Combined != MemberQuals)
|
|
|
|
MemberType = Context.getQualifiedType(MemberType, Combined);
|
2008-12-21 07:49:58 +08:00
|
|
|
}
|
2008-02-07 06:48:16 +08:00
|
|
|
|
2009-06-23 07:06:13 +08:00
|
|
|
MarkDeclarationReferenced(MemberLoc, FD);
|
2009-07-30 03:40:11 +08:00
|
|
|
if (PerformObjectMemberConversion(BaseExpr, FD))
|
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
FD, MemberLoc, MemberType));
|
2009-03-31 16:18:48 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-23 07:06:13 +08:00
|
|
|
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
|
|
|
|
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
|
|
|
Var, MemberLoc,
|
|
|
|
Var->getType().getNonReferenceType()));
|
2009-06-23 07:06:13 +08:00
|
|
|
}
|
|
|
|
if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
|
|
|
|
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
|
|
|
MemberFn, MemberLoc,
|
|
|
|
MemberFn->getType()));
|
2009-06-23 07:06:13 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
if (FunctionTemplateDecl *FunTmpl
|
2009-08-21 08:16:32 +08:00
|
|
|
= dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
|
|
|
|
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-01 08:37:14 +08:00
|
|
|
if (HasExplicitTemplateArgs)
|
2009-09-09 23:08:12 +08:00
|
|
|
return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
|
|
|
|
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
2009-09-01 08:37:14 +08:00
|
|
|
SS? SS->getRange() : SourceRange(),
|
2009-09-09 23:08:12 +08:00
|
|
|
FunTmpl, MemberLoc, true,
|
|
|
|
LAngleLoc, ExplicitTemplateArgs,
|
|
|
|
NumExplicitTemplateArgs, RAngleLoc,
|
2009-09-01 08:37:14 +08:00
|
|
|
Context.OverloadTy));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
|
|
|
FunTmpl, MemberLoc,
|
|
|
|
Context.OverloadTy));
|
2009-08-21 08:16:32 +08:00
|
|
|
}
|
2009-03-31 16:18:48 +08:00
|
|
|
if (OverloadedFunctionDecl *Ovl
|
2009-09-01 08:37:14 +08:00
|
|
|
= dyn_cast<OverloadedFunctionDecl>(MemberDecl)) {
|
|
|
|
if (HasExplicitTemplateArgs)
|
2009-09-09 23:08:12 +08:00
|
|
|
return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
|
|
|
|
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
2009-09-01 08:37:14 +08:00
|
|
|
SS? SS->getRange() : SourceRange(),
|
2009-09-09 23:08:12 +08:00
|
|
|
Ovl, MemberLoc, true,
|
|
|
|
LAngleLoc, ExplicitTemplateArgs,
|
|
|
|
NumExplicitTemplateArgs, RAngleLoc,
|
2009-09-01 08:37:14 +08:00
|
|
|
Context.OverloadTy));
|
|
|
|
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
|
|
|
Ovl, MemberLoc, Context.OverloadTy));
|
2009-09-01 08:37:14 +08:00
|
|
|
}
|
2009-06-23 07:06:13 +08:00
|
|
|
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
|
|
|
|
MarkDeclarationReferenced(MemberLoc, MemberDecl);
|
When a member reference expression includes a qualifier on the member
name, e.g.,
x->Base::f()
retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.
When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?
llvm-svn: 80167
2009-08-27 06:36:53 +08:00
|
|
|
return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
|
|
|
|
Enum, MemberLoc, Enum->getType()));
|
2009-06-23 07:06:13 +08:00
|
|
|
}
|
2009-03-31 16:18:48 +08:00
|
|
|
if (isa<TypeDecl>(MemberDecl))
|
2009-01-19 08:08:26 +08:00
|
|
|
return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
|
2009-08-27 02:25:21 +08:00
|
|
|
<< MemberName << 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)
|
2009-08-27 02:25:21 +08:00
|
|
|
<< MemberName << int(OpKind == tok::arrow));
|
2008-07-21 12:28:12 +08:00
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2009-09-05 01:36:40 +08:00
|
|
|
// Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring
|
|
|
|
// into a record type was handled above, any destructor we see here is a
|
|
|
|
// pseudo-destructor.
|
|
|
|
if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) {
|
|
|
|
// C++ [expr.pseudo]p2:
|
2009-09-09 23:08:12 +08:00
|
|
|
// The left hand side of the dot operator shall be of scalar type. The
|
|
|
|
// left hand side of the arrow operator shall be of pointer to scalar
|
2009-09-05 01:36:40 +08:00
|
|
|
// type.
|
|
|
|
if (!BaseType->isScalarType())
|
|
|
|
return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
|
|
|
|
<< BaseType << BaseExpr->getSourceRange());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-05 01:36:40 +08:00
|
|
|
// [...] The type designated by the pseudo-destructor-name shall be the
|
|
|
|
// same as the object type.
|
|
|
|
if (!MemberName.getCXXNameType()->isDependentType() &&
|
|
|
|
!Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType()))
|
|
|
|
return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch)
|
|
|
|
<< BaseType << MemberName.getCXXNameType()
|
|
|
|
<< BaseExpr->getSourceRange() << SourceRange(MemberLoc));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// [...] Furthermore, the two type-names in a pseudo-destructor-name of
|
2009-09-05 01:36:40 +08:00
|
|
|
// the form
|
|
|
|
//
|
2009-09-09 23:08:12 +08:00
|
|
|
// ::[opt] nested-name-specifier[opt] type-name :: ̃ type-name
|
|
|
|
//
|
2009-09-05 01:36:40 +08:00
|
|
|
// shall designate the same scalar type.
|
|
|
|
//
|
|
|
|
// FIXME: DPG can't see any way to trigger this particular clause, so it
|
|
|
|
// isn't checked here.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-05 01:36:40 +08:00
|
|
|
// FIXME: We've lost the precise spelling of the type by going through
|
|
|
|
// DeclarationName. Can we do better?
|
|
|
|
return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr,
|
2009-09-09 23:08:12 +08:00
|
|
|
OpKind == tok::arrow,
|
2009-09-05 01:36:40 +08:00
|
|
|
OpLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
2009-09-05 01:36:40 +08:00
|
|
|
SS? SS->getRange() : SourceRange(),
|
|
|
|
MemberName.getCXXNameType(),
|
|
|
|
MemberLoc));
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-21 12:59:05 +08:00
|
|
|
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
|
|
|
|
// (*Obj).ivar.
|
2009-07-11 07:34:53 +08:00
|
|
|
if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) ||
|
|
|
|
(OpKind == tok::period && BaseType->isObjCInterfaceType())) {
|
2009-09-22 07:43:11 +08:00
|
|
|
const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>();
|
2009-09-09 23:08:12 +08:00
|
|
|
const ObjCInterfaceType *IFaceT =
|
2009-09-22 07:43:11 +08:00
|
|
|
OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>();
|
2009-07-16 08:25:06 +08:00
|
|
|
if (IFaceT) {
|
2009-08-27 02:25:21 +08:00
|
|
|
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
|
|
|
|
|
2009-07-16 08:25:06 +08:00
|
|
|
ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
|
|
|
|
ObjCInterfaceDecl *ClassDeclared;
|
2009-08-27 02:25:21 +08:00
|
|
|
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-16 08:25:06 +08:00
|
|
|
if (IV) {
|
|
|
|
// 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
|
|
|
|
2009-07-16 08:25:06 +08:00
|
|
|
// Check whether we can reference this field.
|
|
|
|
if (DiagnoseUseOfDecl(IV, MemberLoc))
|
|
|
|
return ExprError();
|
|
|
|
if (IV->getAccessControl() != ObjCIvarDecl::Public &&
|
|
|
|
IV->getAccessControl() != ObjCIvarDecl::Package) {
|
|
|
|
ObjCInterfaceDecl *ClassOfMethodDecl = 0;
|
|
|
|
if (ObjCMethodDecl *MD = getCurMethodDecl())
|
|
|
|
ClassOfMethodDecl = MD->getClassInterface();
|
|
|
|
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 = ObjCImpDecl.getAs<Decl>();
|
2009-09-09 23:08:12 +08:00
|
|
|
if (ObjCImplementationDecl *IMPD =
|
2009-07-16 08:25:06 +08:00
|
|
|
dyn_cast<ObjCImplementationDecl>(ImplDecl))
|
|
|
|
ClassOfMethodDecl = IMPD->getClassInterface();
|
|
|
|
else if (ObjCCategoryImplDecl* CatImplClass =
|
|
|
|
dyn_cast<ObjCCategoryImplDecl>(ImplDecl))
|
|
|
|
ClassOfMethodDecl = CatImplClass->getClassInterface();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (IV->getAccessControl() == ObjCIvarDecl::Private) {
|
|
|
|
if (ClassDeclared != IDecl ||
|
2009-07-16 08:25:06 +08:00
|
|
|
ClassOfMethodDecl != ClassDeclared)
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(MemberLoc, diag::error_private_ivar_access)
|
2009-07-16 08:25:06 +08:00
|
|
|
<< IV->getDeclName();
|
2009-08-05 05:02:39 +08:00
|
|
|
} else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
|
|
|
|
// @protected
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(MemberLoc, diag::error_protected_ivar_access)
|
2009-07-16 08:25:06 +08:00
|
|
|
<< IV->getDeclName();
|
2009-03-03 09:21:12 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-07-16 08:25:06 +08:00
|
|
|
return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
|
|
|
|
MemberLoc, BaseExpr,
|
|
|
|
OpKind == tok::arrow));
|
|
|
|
}
|
|
|
|
return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
|
2009-08-27 02:25:21 +08:00
|
|
|
<< IDecl->getDeclName() << MemberName
|
2009-07-16 08:25:06 +08:00
|
|
|
<< BaseExpr->getSourceRange());
|
2008-12-14 06:20:28 +08:00
|
|
|
}
|
2008-07-21 12:28:12 +08:00
|
|
|
}
|
2009-07-16 02:40:39 +08:00
|
|
|
// Handle properties on 'id' and qualified "id".
|
2009-09-09 23:08:12 +08:00
|
|
|
if (OpKind == tok::period && (BaseType->isObjCIdType() ||
|
2009-07-16 02:40:39 +08:00
|
|
|
BaseType->isObjCQualifiedIdType())) {
|
2009-09-22 07:43:11 +08:00
|
|
|
const ObjCObjectPointerType *QIdTy = BaseType->getAs<ObjCObjectPointerType>();
|
2009-08-27 02:25:21 +08:00
|
|
|
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-11 07:34:53 +08:00
|
|
|
// Check protocols on qualified interfaces.
|
2009-08-27 02:25:21 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
|
2009-07-11 07:34:53 +08:00
|
|
|
if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) {
|
|
|
|
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
|
|
|
|
// Check the use of this declaration
|
|
|
|
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-11 07:34:53 +08:00
|
|
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
|
|
|
MemberLoc, BaseExpr));
|
|
|
|
}
|
|
|
|
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
|
|
|
|
// Check the use of this method.
|
|
|
|
if (DiagnoseUseOfDecl(OMD, MemberLoc))
|
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-11 07:34:53 +08:00
|
|
|
return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
|
2009-09-09 23:08:12 +08:00
|
|
|
OMD->getResultType(),
|
|
|
|
OMD, OpLoc, MemberLoc,
|
2009-07-11 07:34:53 +08:00
|
|
|
NULL, 0));
|
|
|
|
}
|
|
|
|
}
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2009-07-11 07:34:53 +08:00
|
|
|
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
|
2009-08-27 02:25:21 +08:00
|
|
|
<< MemberName << BaseType);
|
2009-07-11 07:34:53 +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.
|
2009-07-11 07:34:53 +08:00
|
|
|
const ObjCObjectPointerType *OPT;
|
2009-09-09 23:08:12 +08:00
|
|
|
if (OpKind == tok::period &&
|
2009-07-11 07:34:53 +08:00
|
|
|
(OPT = BaseType->getAsObjCInterfacePointerType())) {
|
|
|
|
const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
|
|
|
|
ObjCInterfaceDecl *IFace = IFaceT->getDecl();
|
2009-08-27 02:25:21 +08:00
|
|
|
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-03 09:05:41 +08:00
|
|
|
// Search for a declared property first.
|
2009-08-27 02:25:21 +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-05-09 03:36:34 +08:00
|
|
|
QualType ResTy = PD->getType();
|
2009-08-27 02:25:21 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
|
2009-06-30 10:36:12 +08:00
|
|
|
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
|
2009-05-09 04:20:55 +08:00
|
|
|
if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
|
|
|
|
ResTy = Getter->getResultType();
|
2009-05-09 03:36:34 +08:00
|
|
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
|
2009-02-17 02:35:08 +08:00
|
|
|
MemberLoc, BaseExpr));
|
|
|
|
}
|
2008-09-03 09:05:41 +08:00
|
|
|
// Check protocols on qualified interfaces.
|
2009-07-21 01:56:53 +08:00
|
|
|
for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
|
|
|
|
E = OPT->qual_end(); I != E; ++I)
|
2009-08-27 02:25:21 +08:00
|
|
|
if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
|
2009-07-11 07:34:53 +08:00
|
|
|
// Check whether we can reference this property.
|
|
|
|
if (DiagnoseUseOfDecl(PD, MemberLoc))
|
|
|
|
return ExprError();
|
2008-09-03 09:05:41 +08:00
|
|
|
|
2009-07-11 07:34:53 +08:00
|
|
|
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
|
|
|
|
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.
|
|
|
|
|
2009-08-27 02:25:21 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
|
2009-06-30 10:36:12 +08:00
|
|
|
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)
|
2009-10-02 07:46:04 +08:00
|
|
|
Getter = IFace->lookupPrivateInstanceMethod(Sel);
|
2008-09-03 09:05:41 +08:00
|
|
|
|
2008-10-23 03:16:27 +08:00
|
|
|
// Look through local category implementations associated with the class.
|
2009-07-21 08:06:20 +08:00
|
|
|
if (!Getter)
|
|
|
|
Getter = IFace->getCategoryInstanceMethod(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-03-11 21:48:17 +08:00
|
|
|
}
|
|
|
|
// If we found a getter then this may be a valid dot-reference, we
|
|
|
|
// will look for the matching setter, in case it is needed.
|
2009-09-09 23:08:12 +08:00
|
|
|
Selector SetterSel =
|
|
|
|
SelectorTable::constructSetterName(PP.getIdentifierTable(),
|
2009-08-27 02:25:21 +08:00
|
|
|
PP.getSelectorTable(), Member);
|
2009-06-30 10:36:12 +08:00
|
|
|
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
|
2009-03-11 21:48:17 +08:00
|
|
|
if (!Setter) {
|
|
|
|
// If this reference is in an @implementation, also check for 'private'
|
|
|
|
// methods.
|
2009-10-02 07:46:04 +08:00
|
|
|
Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
|
2009-03-11 21:48:17 +08:00
|
|
|
}
|
|
|
|
// Look through local category implementations associated with the class.
|
2009-07-21 08:06:20 +08:00
|
|
|
if (!Setter)
|
|
|
|
Setter = IFace->getCategoryInstanceMethod(SetterSel);
|
2009-01-19 08:08:26 +08:00
|
|
|
|
2009-03-11 21:48:17 +08:00
|
|
|
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
|
|
|
|
return ExprError();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-11 21:48:17 +08:00
|
|
|
if (Getter || Setter) {
|
|
|
|
QualType PType;
|
|
|
|
|
|
|
|
if (Getter)
|
|
|
|
PType = Getter->getResultType();
|
2009-08-19 04:50:23 +08:00
|
|
|
else
|
|
|
|
// Get the expression type from Setter's incoming parameter.
|
|
|
|
PType = (*(Setter->param_end() -1))->getType();
|
2009-01-19 08:08:26 +08:00
|
|
|
// FIXME: we must check that the setter has property type.
|
2009-08-21 01:02:02 +08:00
|
|
|
return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
|
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)
|
2009-08-27 02:25:21 +08:00
|
|
|
<< MemberName << BaseType);
|
2007-11-13 06:29:28 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-25 01:54:45 +08:00
|
|
|
// Handle the following exceptional case (*Obj).isa.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (OpKind == tok::period &&
|
2009-07-25 01:54:45 +08:00
|
|
|
BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
|
2009-08-27 02:25:21 +08:00
|
|
|
MemberName.getAsIdentifierInfo()->isStr("isa"))
|
2009-07-25 01:54:45 +08:00
|
|
|
return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
|
|
|
|
Context.getObjCIdType()));
|
|
|
|
|
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()) {
|
2009-08-27 02:25:21 +08:00
|
|
|
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
|
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-08-27 02:25:21 +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
|
|
|
|
2009-03-27 14:00:30 +08:00
|
|
|
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
|
|
|
|
<< BaseType << BaseExpr->getSourceRange();
|
|
|
|
|
|
|
|
return ExprError();
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2009-11-04 03:44:04 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base,
|
|
|
|
SourceLocation OpLoc,
|
|
|
|
tok::TokenKind OpKind,
|
|
|
|
const CXXScopeSpec &SS,
|
|
|
|
UnqualifiedId &Member,
|
|
|
|
DeclPtrTy ObjCImpDecl,
|
|
|
|
bool HasTrailingLParen) {
|
|
|
|
if (Member.getKind() == UnqualifiedId::IK_TemplateId) {
|
|
|
|
TemplateName Template
|
|
|
|
= TemplateName::getFromVoidPointer(Member.TemplateId->Template);
|
|
|
|
|
|
|
|
// FIXME: We're going to end up looking up the template based on its name,
|
|
|
|
// twice!
|
|
|
|
DeclarationName Name;
|
|
|
|
if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
|
|
|
|
Name = ActualTemplate->getDeclName();
|
|
|
|
else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
|
|
|
|
Name = Ovl->getDeclName();
|
2009-11-04 08:56:37 +08:00
|
|
|
else {
|
|
|
|
DependentTemplateName *DTN = Template.getAsDependentTemplateName();
|
|
|
|
if (DTN->isIdentifier())
|
|
|
|
Name = DTN->getIdentifier();
|
|
|
|
else
|
|
|
|
Name = Context.DeclarationNames.getCXXOperatorName(DTN->getOperator());
|
|
|
|
}
|
2009-11-04 03:44:04 +08:00
|
|
|
|
|
|
|
// Translate the parser's template argument list in our AST format.
|
|
|
|
ASTTemplateArgsPtr TemplateArgsPtr(*this,
|
|
|
|
Member.TemplateId->getTemplateArgs(),
|
|
|
|
Member.TemplateId->NumArgs);
|
|
|
|
|
|
|
|
llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
|
|
|
|
translateTemplateArguments(TemplateArgsPtr,
|
|
|
|
TemplateArgs);
|
|
|
|
TemplateArgsPtr.release();
|
|
|
|
|
|
|
|
// Do we have the save the actual template name? We might need it...
|
|
|
|
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind,
|
|
|
|
Member.TemplateId->TemplateNameLoc,
|
|
|
|
Name, true, Member.TemplateId->LAngleLoc,
|
|
|
|
TemplateArgs.data(), TemplateArgs.size(),
|
|
|
|
Member.TemplateId->RAngleLoc, DeclPtrTy(),
|
|
|
|
&SS);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: We lose a lot of source information by mapping directly to the
|
|
|
|
// DeclarationName.
|
|
|
|
OwningExprResult Result
|
|
|
|
= BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind,
|
|
|
|
Member.getSourceRange().getBegin(),
|
|
|
|
GetNameFromUnqualifiedId(Member),
|
|
|
|
ObjCImpDecl, &SS);
|
|
|
|
|
|
|
|
if (Result.isInvalid() || HasTrailingLParen ||
|
|
|
|
Member.getKind() != UnqualifiedId::IK_DestructorName)
|
|
|
|
return move(Result);
|
|
|
|
|
|
|
|
// The only way a reference to a destructor can be used is to
|
|
|
|
// immediately call them. Since the next token is not a '(', produce a
|
|
|
|
// diagnostic and build the call now.
|
|
|
|
Expr *E = (Expr *)Result.get();
|
|
|
|
SourceLocation ExpectedLParenLoc
|
|
|
|
= PP.getLocForEndOfToken(Member.getSourceRange().getEnd());
|
|
|
|
Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
|
|
|
|
<< isa<CXXPseudoDestructorExpr>(E)
|
|
|
|
<< CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
|
|
|
|
|
|
|
|
return ActOnCallExpr(0, move(Result), ExpectedLParenLoc,
|
|
|
|
MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc);
|
2009-08-27 02:25:21 +08:00
|
|
|
}
|
|
|
|
|
2009-08-25 11:49:14 +08:00
|
|
|
Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
|
|
|
|
FunctionDecl *FD,
|
|
|
|
ParmVarDecl *Param) {
|
|
|
|
if (Param->hasUnparsedDefaultArg()) {
|
|
|
|
Diag (CallLoc,
|
|
|
|
diag::err_use_of_default_argument_to_function_declared_later) <<
|
|
|
|
FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName();
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(UnparsedDefaultArgLocs[Param],
|
2009-08-25 11:49:14 +08:00
|
|
|
diag::note_default_argument_declared_here);
|
|
|
|
} else {
|
|
|
|
if (Param->hasUninstantiatedDefaultArg()) {
|
|
|
|
Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
|
|
|
|
|
|
|
|
// Instantiate the expression.
|
2009-08-29 04:31:08 +08:00
|
|
|
MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD);
|
2009-09-05 13:14:19 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
InstantiatingTemplate Inst(*this, CallLoc, Param,
|
|
|
|
ArgList.getInnermost().getFlatArgumentList(),
|
2009-08-29 04:31:08 +08:00
|
|
|
ArgList.getInnermost().flat_size());
|
2009-08-25 11:49:14 +08:00
|
|
|
|
2009-08-26 06:02:44 +08:00
|
|
|
OwningExprResult Result = SubstExpr(UninstExpr, ArgList);
|
2009-09-09 23:08:12 +08:00
|
|
|
if (Result.isInvalid())
|
2009-08-25 11:49:14 +08:00
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (SetParamDefaultArgument(Param, move(Result),
|
2009-08-25 11:49:14 +08:00
|
|
|
/*FIXME:EqualLoc*/
|
|
|
|
UninstExpr->getSourceRange().getBegin()))
|
|
|
|
return ExprError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-25 11:49:14 +08:00
|
|
|
Expr *DefaultExpr = Param->getDefaultArg();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-25 11:49:14 +08:00
|
|
|
// If the default expression creates temporaries, we need to
|
|
|
|
// push them to the current stack of expression temporaries so they'll
|
|
|
|
// be properly destroyed.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (CXXExprWithTemporaries *E
|
2009-08-25 11:49:14 +08:00
|
|
|
= dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(!E->shouldDestroyTemporaries() &&
|
2009-08-25 11:49:14 +08:00
|
|
|
"Can't destroy temporaries in a default argument expr!");
|
|
|
|
for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I)
|
|
|
|
ExprTemporaries.push_back(E->getTemporary(I));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We already type-checked the argument, so we know it works.
|
|
|
|
return Owned(CXXDefaultArgExpr::Create(Context, Param));
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2009-03-23 06:00:50 +08:00
|
|
|
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
|
|
|
|
ProtoArgType,
|
2009-08-27 07:45:07 +08:00
|
|
|
PDiag(diag::err_call_incomplete_argument)
|
|
|
|
<< Arg->getSourceRange()))
|
2009-03-23 06:00:50 +08:00
|
|
|
return true;
|
|
|
|
|
2008-12-24 08:01:03 +08:00
|
|
|
// Pass the argument.
|
|
|
|
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
|
|
|
|
return true;
|
2009-11-13 12:34:45 +08:00
|
|
|
|
2009-11-14 01:04:35 +08:00
|
|
|
if (!ProtoArgType->isReferenceType())
|
|
|
|
Arg = MaybeBindToTemporary(Arg).takeAs<Expr>();
|
2009-06-13 00:51:40 +08:00
|
|
|
} else {
|
2009-08-25 10:29:20 +08:00
|
|
|
ParmVarDecl *Param = FDecl->getParamDecl(i);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
OwningExprResult ArgExpr =
|
2009-08-25 11:49:14 +08:00
|
|
|
BuildCXXDefaultArgExpr(Call->getSourceRange().getBegin(),
|
|
|
|
FDecl, Param);
|
|
|
|
if (ArgExpr.isInvalid())
|
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-25 11:49:14 +08:00
|
|
|
Arg = ArgExpr.takeAs<Expr>();
|
2009-06-13 00:51:40 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +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).
|
2009-11-14 12:43:10 +08:00
|
|
|
for (unsigned i = NumArgsInProto; i < NumArgs; i++) {
|
2008-12-22 13:46:06 +08:00
|
|
|
Expr *Arg = Args[i];
|
2009-04-12 16:11:20 +08:00
|
|
|
Invalid |= 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
|
|
|
}
|
|
|
|
|
2009-09-22 23:41:20 +08:00
|
|
|
/// \brief "Deconstruct" the function argument of a call expression to find
|
|
|
|
/// the underlying declaration (if any), the name of the called function,
|
|
|
|
/// whether argument-dependent lookup is available, whether it has explicit
|
|
|
|
/// template arguments, etc.
|
|
|
|
void Sema::DeconstructCallFunction(Expr *FnExpr,
|
|
|
|
NamedDecl *&Function,
|
|
|
|
DeclarationName &Name,
|
|
|
|
NestedNameSpecifier *&Qualifier,
|
|
|
|
SourceRange &QualifierRange,
|
|
|
|
bool &ArgumentDependentLookup,
|
|
|
|
bool &HasExplicitTemplateArguments,
|
2009-10-29 16:12:44 +08:00
|
|
|
const TemplateArgumentLoc *&ExplicitTemplateArgs,
|
2009-09-22 23:41:20 +08:00
|
|
|
unsigned &NumExplicitTemplateArgs) {
|
|
|
|
// Set defaults for all of the output parameters.
|
|
|
|
Function = 0;
|
|
|
|
Name = DeclarationName();
|
|
|
|
Qualifier = 0;
|
|
|
|
QualifierRange = SourceRange();
|
|
|
|
ArgumentDependentLookup = getLangOptions().CPlusPlus;
|
|
|
|
HasExplicitTemplateArguments = false;
|
|
|
|
|
|
|
|
// If we're directly calling a function, get the appropriate declaration.
|
|
|
|
// Also, in C++, keep track of whether we should perform argument-dependent
|
|
|
|
// lookup and whether there were any explicitly-specified template arguments.
|
|
|
|
while (true) {
|
|
|
|
if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
|
|
|
|
FnExpr = IcExpr->getSubExpr();
|
|
|
|
else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
|
|
|
|
// Parentheses around a function disable ADL
|
|
|
|
// (C++0x [basic.lookup.argdep]p1).
|
|
|
|
ArgumentDependentLookup = false;
|
|
|
|
FnExpr = PExpr->getSubExpr();
|
|
|
|
} else if (isa<UnaryOperator>(FnExpr) &&
|
|
|
|
cast<UnaryOperator>(FnExpr)->getOpcode()
|
|
|
|
== UnaryOperator::AddrOf) {
|
|
|
|
FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
|
|
|
|
} else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
|
|
|
|
Function = dyn_cast<NamedDecl>(DRExpr->getDecl());
|
2009-10-24 02:54:35 +08:00
|
|
|
if ((Qualifier = DRExpr->getQualifier())) {
|
|
|
|
ArgumentDependentLookup = false;
|
|
|
|
QualifierRange = DRExpr->getQualifierRange();
|
|
|
|
}
|
2009-09-22 23:41:20 +08:00
|
|
|
break;
|
|
|
|
} else if (UnresolvedFunctionNameExpr *DepName
|
|
|
|
= dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
|
|
|
|
Name = DepName->getName();
|
|
|
|
break;
|
|
|
|
} else if (TemplateIdRefExpr *TemplateIdRef
|
|
|
|
= dyn_cast<TemplateIdRefExpr>(FnExpr)) {
|
|
|
|
Function = TemplateIdRef->getTemplateName().getAsTemplateDecl();
|
|
|
|
if (!Function)
|
|
|
|
Function = TemplateIdRef->getTemplateName().getAsOverloadedFunctionDecl();
|
|
|
|
HasExplicitTemplateArguments = true;
|
|
|
|
ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs();
|
|
|
|
NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs();
|
|
|
|
|
|
|
|
// C++ [temp.arg.explicit]p6:
|
|
|
|
// [Note: For simple function names, argument dependent lookup (3.4.2)
|
|
|
|
// applies even when the function name is not visible within the
|
|
|
|
// scope of the call. This is because the call still has the syntactic
|
|
|
|
// form of a function call (3.4.1). But when a function template with
|
|
|
|
// explicit template arguments is used, the call does not have the
|
|
|
|
// correct syntactic form unless there is a function template with
|
|
|
|
// that name visible at the point of the call. If no such name is
|
|
|
|
// visible, the call is not syntactically well-formed and
|
|
|
|
// argument-dependent lookup does not apply. If some such name is
|
|
|
|
// visible, argument dependent lookup applies and additional function
|
|
|
|
// templates may be found in other namespaces.
|
|
|
|
//
|
|
|
|
// The summary of this paragraph is that, if we get to this point and the
|
|
|
|
// template-id was not a qualified name, then argument-dependent lookup
|
|
|
|
// is still possible.
|
|
|
|
if ((Qualifier = TemplateIdRef->getQualifier())) {
|
|
|
|
ArgumentDependentLookup = false;
|
|
|
|
QualifierRange = TemplateIdRef->getQualifierRange();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// Any kind of name that does not refer to a declaration (or
|
|
|
|
// set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3).
|
|
|
|
ArgumentDependentLookup = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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();
|
2009-08-11 07:49:36 +08:00
|
|
|
|
|
|
|
// Since this might be a postfix expression, get rid of ParenListExprs.
|
|
|
|
fn = MaybeConvertParenListExprToParenExpr(S, move(fn));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-02 03:30:39 +08:00
|
|
|
Expr *Fn = fn.takeAs<Expr>();
|
2009-01-19 08:08:26 +08:00
|
|
|
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-05-16 04:33:25 +08:00
|
|
|
NamedDecl *NDecl = NULL;
|
2009-02-04 23:01:18 +08:00
|
|
|
DeclarationName UnqualifiedName;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-04 23:01:18 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
2009-09-05 01:36:40 +08:00
|
|
|
// If this is a pseudo-destructor expression, build the call immediately.
|
|
|
|
if (isa<CXXPseudoDestructorExpr>(Fn)) {
|
|
|
|
if (NumArgs > 0) {
|
|
|
|
// Pseudo-destructor calls should not have any arguments.
|
|
|
|
Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args)
|
|
|
|
<< CodeModificationHint::CreateRemoval(
|
|
|
|
SourceRange(Args[0]->getLocStart(),
|
|
|
|
Args[NumArgs-1]->getLocEnd()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-05 01:36:40 +08:00
|
|
|
for (unsigned I = 0; I != NumArgs; ++I)
|
|
|
|
Args[I]->Destroy(Context);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-05 01:36:40 +08:00
|
|
|
NumArgs = 0;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-05 01:36:40 +08:00
|
|
|
return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy,
|
|
|
|
RParenLoc));
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-04 23:01:18 +08:00
|
|
|
// 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-05-16 15:39:55 +08:00
|
|
|
// FIXME: Will need to cache the results of name lookup (including ADL) in
|
|
|
|
// Fn.
|
2009-02-04 23:01:18 +08:00
|
|
|
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.
|
2009-06-26 06:08:12 +08:00
|
|
|
if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens())) {
|
|
|
|
NamedDecl *MemDecl = MemExpr->getMemberDecl();
|
|
|
|
if (isa<OverloadedFunctionDecl>(MemDecl) ||
|
|
|
|
isa<CXXMethodDecl>(MemDecl) ||
|
|
|
|
(isa<FunctionTemplateDecl>(MemDecl) &&
|
|
|
|
isa<CXXMethodDecl>(
|
|
|
|
cast<FunctionTemplateDecl>(MemDecl)->getTemplatedDecl())))
|
2009-01-19 08:08:26 +08:00
|
|
|
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
|
|
|
|
CommaLocs, RParenLoc));
|
2009-06-26 06:08:12 +08:00
|
|
|
}
|
2009-10-04 01:40:22 +08:00
|
|
|
|
|
|
|
// Determine whether this is a call to a pointer-to-member function.
|
|
|
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Fn->IgnoreParens())) {
|
|
|
|
if (BO->getOpcode() == BinaryOperator::PtrMemD ||
|
|
|
|
BO->getOpcode() == BinaryOperator::PtrMemI) {
|
2009-10-29 00:49:46 +08:00
|
|
|
if (const FunctionProtoType *FPT =
|
|
|
|
dyn_cast<FunctionProtoType>(BO->getType())) {
|
|
|
|
QualType ResultTy = FPT->getResultType().getNonReferenceType();
|
2009-10-04 01:40:22 +08:00
|
|
|
|
2009-10-29 00:49:46 +08:00
|
|
|
ExprOwningPtr<CXXMemberCallExpr>
|
|
|
|
TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args,
|
|
|
|
NumArgs, ResultTy,
|
|
|
|
RParenLoc));
|
2009-10-04 01:40:22 +08:00
|
|
|
|
2009-10-29 00:49:46 +08:00
|
|
|
if (CheckCallReturnType(FPT->getResultType(),
|
|
|
|
BO->getRHS()->getSourceRange().getBegin(),
|
|
|
|
TheCall.get(), 0))
|
|
|
|
return ExprError();
|
2009-10-15 08:41:48 +08:00
|
|
|
|
2009-10-29 00:49:46 +08:00
|
|
|
if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs,
|
|
|
|
RParenLoc))
|
|
|
|
return ExprError();
|
2009-10-04 01:40:22 +08:00
|
|
|
|
2009-10-29 00:49:46 +08:00
|
|
|
return Owned(MaybeBindToTemporary(TheCall.release()).release());
|
|
|
|
}
|
|
|
|
return ExprError(Diag(Fn->getLocStart(),
|
|
|
|
diag::err_typecheck_call_not_function)
|
|
|
|
<< Fn->getType() << Fn->getSourceRange());
|
2009-10-04 01:40:22 +08:00
|
|
|
}
|
|
|
|
}
|
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-09-09 23:08:12 +08:00
|
|
|
// Also, in C++, keep track of whether we should perform argument-dependent
|
2009-07-01 07:57:56 +08:00
|
|
|
// lookup and whether there were any explicitly-specified template arguments.
|
2009-02-04 08:32:51 +08:00
|
|
|
bool ADL = true;
|
2009-07-01 07:57:56 +08:00
|
|
|
bool HasExplicitTemplateArgs = 0;
|
2009-10-29 16:12:44 +08:00
|
|
|
const TemplateArgumentLoc *ExplicitTemplateArgs = 0;
|
2009-07-01 07:57:56 +08:00
|
|
|
unsigned NumExplicitTemplateArgs = 0;
|
2009-09-22 23:41:20 +08:00
|
|
|
NestedNameSpecifier *Qualifier = 0;
|
|
|
|
SourceRange QualifierRange;
|
|
|
|
DeconstructCallFunction(Fn, NDecl, UnqualifiedName, Qualifier, QualifierRange,
|
|
|
|
ADL,HasExplicitTemplateArgs, ExplicitTemplateArgs,
|
|
|
|
NumExplicitTemplateArgs);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-02-04 23:01:18 +08:00
|
|
|
OverloadedFunctionDecl *Ovl = 0;
|
2009-06-26 06:08:12 +08:00
|
|
|
FunctionTemplateDecl *FunctionTemplate = 0;
|
2009-07-01 06:34:41 +08:00
|
|
|
if (NDecl) {
|
|
|
|
FDecl = dyn_cast<FunctionDecl>(NDecl);
|
|
|
|
if ((FunctionTemplate = dyn_cast<FunctionTemplateDecl>(NDecl)))
|
2009-06-26 06:08:12 +08:00
|
|
|
FDecl = FunctionTemplate->getTemplatedDecl();
|
|
|
|
else
|
2009-07-01 06:34:41 +08:00
|
|
|
FDecl = dyn_cast<FunctionDecl>(NDecl);
|
|
|
|
Ovl = dyn_cast<OverloadedFunctionDecl>(NDecl);
|
2009-02-04 23:01:18 +08:00
|
|
|
}
|
2008-10-22 00:13:35 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
if (Ovl || FunctionTemplate ||
|
2009-06-26 06:08:12 +08:00
|
|
|
(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-09-12 08:22:50 +08:00
|
|
|
if (FDecl && FDecl->getBuiltinID() && 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-06-26 06:08:12 +08:00
|
|
|
if (Ovl || FunctionTemplate || ADL) {
|
2009-09-09 23:08:12 +08:00
|
|
|
FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
|
2009-07-01 07:57:56 +08:00
|
|
|
HasExplicitTemplateArgs,
|
|
|
|
ExplicitTemplateArgs,
|
|
|
|
NumExplicitTemplateArgs,
|
2009-09-09 23:08:12 +08:00
|
|
|
LParenLoc, Args, NumArgs, CommaLocs,
|
2009-07-01 07:57:56 +08:00
|
|
|
RParenLoc, ADL);
|
2009-02-04 08:32:51 +08:00
|
|
|
if (!FDecl)
|
|
|
|
return ExprError();
|
|
|
|
|
2009-10-24 06:18:25 +08:00
|
|
|
Fn = FixOverloadedFunctionReference(Fn, FDecl);
|
2009-02-04 08:32:51 +08:00
|
|
|
}
|
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".
|
2009-07-30 05:53:49 +08:00
|
|
|
const PointerType *PT = Fn->getType()->getAs<PointerType>();
|
2008-09-06 06:11:13 +08:00
|
|
|
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());
|
2009-09-22 07:43:11 +08:00
|
|
|
FuncT = PT->getPointeeType()->getAs<FunctionType>();
|
2008-09-06 06:11:13 +08:00
|
|
|
} else { // This is a block call.
|
2009-07-30 05:53:49 +08:00
|
|
|
FuncT = Fn->getType()->getAs<BlockPointerType>()->getPointeeType()->
|
2009-09-22 07:43:11 +08:00
|
|
|
getAs<FunctionType>();
|
2008-09-06 06:11:13 +08:00
|
|
|
}
|
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());
|
|
|
|
|
2009-03-23 06:00:50 +08:00
|
|
|
// Check for a valid return type
|
2009-10-10 07:51:55 +08:00
|
|
|
if (CheckCallReturnType(FuncT->getResultType(),
|
|
|
|
Fn->getSourceRange().getBegin(), TheCall.get(),
|
|
|
|
FDecl))
|
2009-03-23 06:00:50 +08:00
|
|
|
return ExprError();
|
|
|
|
|
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
|
|
|
|
2009-04-02 23:37:10 +08:00
|
|
|
if (FDecl) {
|
|
|
|
// Check if we have too few/too many template arguments, based
|
|
|
|
// on our knowledge of the function definition.
|
|
|
|
const FunctionDecl *Def = 0;
|
2009-06-30 10:35:26 +08:00
|
|
|
if (FDecl->getBody(Def) && NumArgs != Def->param_size()) {
|
2009-06-01 17:24:59 +08:00
|
|
|
const FunctionProtoType *Proto =
|
2009-09-22 07:43:11 +08:00
|
|
|
Def->getType()->getAs<FunctionProtoType>();
|
2009-06-01 17:24:59 +08:00
|
|
|
if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) {
|
|
|
|
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
|
|
|
|
<< (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
|
|
|
|
}
|
|
|
|
}
|
2009-04-02 23:37:10 +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);
|
2009-03-23 06:00:50 +08:00
|
|
|
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
|
|
|
|
Arg->getType(),
|
2009-08-27 07:45:07 +08:00
|
|
|
PDiag(diag::err_call_incomplete_argument)
|
|
|
|
<< Arg->getSourceRange()))
|
2009-03-23 06:00:50 +08:00
|
|
|
return ExprError();
|
2007-12-28 13:29:59 +08:00
|
|
|
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
|
|
|
|
2009-05-16 04:33:25 +08:00
|
|
|
// Check for sentinels
|
|
|
|
if (NDecl)
|
|
|
|
DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-11 04:18:51 +08:00
|
|
|
// Do special checking on direct calls to functions.
|
2009-08-16 09:56:34 +08:00
|
|
|
if (FDecl) {
|
|
|
|
if (CheckFunctionCall(FDecl, TheCall.get()))
|
|
|
|
return ExprError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-12 08:22:50 +08:00
|
|
|
if (unsigned BuiltinID = FDecl->getBuiltinID())
|
2009-08-16 09:56:34 +08:00
|
|
|
return CheckBuiltinFunctionCall(BuiltinID, TheCall.take());
|
|
|
|
} else if (NDecl) {
|
|
|
|
if (CheckBlockCall(NDecl, TheCall.get()))
|
|
|
|
return ExprError();
|
|
|
|
}
|
2007-08-11 04:18:51 +08:00
|
|
|
|
2009-08-16 11:06:32 +08:00
|
|
|
return MaybeBindToTemporary(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");
|
2009-08-19 09:28:28 +08:00
|
|
|
//FIXME: Preserve type source info.
|
|
|
|
QualType literalType = GetTypeFromParser(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-05-22 07:48:18 +08:00
|
|
|
} else if (!literalType->isDependentType() &&
|
|
|
|
RequireCompleteType(LParenLoc, literalType,
|
2009-08-27 07:45:07 +08:00
|
|
|
PDiag(diag::err_typecheck_decl_incomplete_type)
|
2009-09-09 23:08:12 +08:00
|
|
|
<< SourceRange(LParenLoc,
|
2009-08-27 07:45:07 +08:00
|
|
|
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,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2009-10-19 02:12:03 +08:00
|
|
|
static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
|
|
|
|
QualType SrcTy, QualType DestTy) {
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (Context.hasSameUnqualifiedType(SrcTy, DestTy))
|
2009-10-19 02:12:03 +08:00
|
|
|
return CastExpr::CK_NoOp;
|
|
|
|
|
|
|
|
if (SrcTy->hasPointerRepresentation()) {
|
|
|
|
if (DestTy->hasPointerRepresentation())
|
|
|
|
return CastExpr::CK_BitCast;
|
|
|
|
if (DestTy->isIntegerType())
|
|
|
|
return CastExpr::CK_PointerToIntegral;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SrcTy->isIntegerType()) {
|
|
|
|
if (DestTy->isIntegerType())
|
|
|
|
return CastExpr::CK_IntegralCast;
|
|
|
|
if (DestTy->hasPointerRepresentation())
|
|
|
|
return CastExpr::CK_IntegralToPointer;
|
|
|
|
if (DestTy->isRealFloatingType())
|
|
|
|
return CastExpr::CK_IntegralToFloating;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SrcTy->isRealFloatingType()) {
|
|
|
|
if (DestTy->isRealFloatingType())
|
|
|
|
return CastExpr::CK_FloatingCast;
|
|
|
|
if (DestTy->isIntegerType())
|
|
|
|
return CastExpr::CK_FloatingToIntegral;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Assert here.
|
|
|
|
// assert(false && "Unhandled cast combination!");
|
|
|
|
return CastExpr::CK_Unknown;
|
|
|
|
}
|
|
|
|
|
2008-08-17 04:27:34 +08:00
|
|
|
/// CheckCastTypes - Check type constraints for casting between types.
|
2009-07-29 21:50:23 +08:00
|
|
|
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
|
2009-09-09 23:08:12 +08:00
|
|
|
CastExpr::CastKind& Kind,
|
2009-08-27 02:55:36 +08:00
|
|
|
CXXMethodDecl *& ConversionDecl,
|
|
|
|
bool FunctionalStyle) {
|
2009-07-25 23:41:38 +08:00
|
|
|
if (getLangOptions().CPlusPlus)
|
2009-08-27 02:55:36 +08:00
|
|
|
return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
|
|
|
|
ConversionDecl);
|
2009-07-25 23:41:38 +08:00
|
|
|
|
2009-08-16 03:02:19 +08:00
|
|
|
DefaultFunctionArrayConversion(castExpr);
|
2008-08-17 04:27:34 +08:00
|
|
|
|
|
|
|
// 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.
|
2009-10-16 10:35:04 +08:00
|
|
|
Kind = CastExpr::CK_ToVoid;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!castType->isScalarType() && !castType->isVectorType()) {
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) &&
|
2009-01-15 12:51:39 +08:00
|
|
|
(castType->isStructureType() || castType->isUnionType())) {
|
|
|
|
// GCC struct/union extension: allow cast to self.
|
2009-03-23 08:24:07 +08:00
|
|
|
// FIXME: Check that the cast destination type is complete.
|
2009-01-15 12:51:39 +08:00
|
|
|
Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar)
|
|
|
|
<< castType << castExpr->getSourceRange();
|
2009-08-08 07:22:37 +08:00
|
|
|
Kind = CastExpr::CK_NoOp;
|
2009-10-16 10:48:28 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (castType->isUnionType()) {
|
2009-01-15 12:51:39 +08:00
|
|
|
// GCC cast to union extension
|
2009-07-30 05:53:49 +08:00
|
|
|
RecordDecl *RD = castType->getAs<RecordType>()->getDecl();
|
2009-01-15 12:51:39 +08:00
|
|
|
RecordDecl::field_iterator Field, FieldEnd;
|
2009-06-30 10:36:12 +08:00
|
|
|
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
|
2009-01-15 12:51:39 +08:00
|
|
|
Field != FieldEnd; ++Field) {
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (Context.hasSameUnqualifiedType(Field->getType(),
|
|
|
|
castExpr->getType())) {
|
2009-01-15 12:51:39 +08:00
|
|
|
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();
|
2009-08-08 07:22:37 +08:00
|
|
|
Kind = CastExpr::CK_ToUnion;
|
2009-10-16 10:48:28 +08:00
|
|
|
return false;
|
2008-08-17 04:27:34 +08:00
|
|
|
}
|
2009-10-16 10:48:28 +08:00
|
|
|
|
|
|
|
// Reject any other conversions to non-scalar types.
|
|
|
|
return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
|
|
|
|
<< castType << castExpr->getSourceRange();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!castExpr->getType()->isScalarType() &&
|
|
|
|
!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();
|
2009-10-16 10:48:28 +08:00
|
|
|
}
|
|
|
|
|
2009-10-16 13:23:41 +08:00
|
|
|
if (castType->isExtVectorType())
|
|
|
|
return CheckExtVectorCast(TyR, castType, castExpr, Kind);
|
|
|
|
|
2009-10-16 10:48:28 +08:00
|
|
|
if (castType->isVectorType())
|
|
|
|
return CheckVectorCast(TyR, castType, castExpr->getType(), Kind);
|
|
|
|
if (castExpr->getType()->isVectorType())
|
|
|
|
return CheckVectorCast(TyR, castExpr->getType(), castType, Kind);
|
|
|
|
|
|
|
|
if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr))
|
2009-04-09 07:52:26 +08:00
|
|
|
return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
|
2009-10-16 10:48:28 +08:00
|
|
|
|
2009-10-16 13:23:41 +08:00
|
|
|
if (isa<ObjCSelectorExpr>(castExpr))
|
|
|
|
return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
|
|
|
|
|
2009-10-16 10:48:28 +08:00
|
|
|
if (!castType->isArithmeticType()) {
|
2009-05-01 10:23:58 +08:00
|
|
|
QualType castExprType = castExpr->getType();
|
|
|
|
if (!castExprType->isIntegralType() && castExprType->isArithmeticType())
|
|
|
|
return Diag(castExpr->getLocStart(),
|
|
|
|
diag::err_cast_pointer_from_non_pointer_int)
|
|
|
|
<< castExprType << castExpr->getSourceRange();
|
|
|
|
} else if (!castExpr->getType()->isArithmeticType()) {
|
|
|
|
if (!castType->isIntegralType() && castType->isArithmeticType())
|
|
|
|
return Diag(castExpr->getLocStart(),
|
|
|
|
diag::err_cast_pointer_to_non_pointer_int)
|
|
|
|
<< castType << castExpr->getSourceRange();
|
2008-08-17 04:27:34 +08:00
|
|
|
}
|
2009-10-19 02:12:03 +08:00
|
|
|
|
|
|
|
Kind = getScalarCastKind(Context, castExpr->getType(), castType);
|
2008-08-17 04:27:34 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-16 10:48:28 +08:00
|
|
|
bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
|
|
|
|
CastExpr::CastKind &Kind) {
|
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
|
|
|
|
2009-10-16 10:48:28 +08:00
|
|
|
Kind = CastExpr::CK_BitCast;
|
2007-11-27 13:51:55 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-16 13:23:41 +08:00
|
|
|
bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
|
|
|
|
CastExpr::CastKind &Kind) {
|
2009-06-26 08:50:28 +08:00
|
|
|
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
|
2009-10-16 13:23:41 +08:00
|
|
|
|
|
|
|
QualType SrcTy = CastExpr->getType();
|
|
|
|
|
2009-06-28 06:05:55 +08:00
|
|
|
// If SrcTy is a VectorType, the total size must match to explicitly cast to
|
|
|
|
// an ExtVectorType.
|
2009-06-26 08:50:28 +08:00
|
|
|
if (SrcTy->isVectorType()) {
|
|
|
|
if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy))
|
|
|
|
return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
|
|
|
|
<< DestTy << SrcTy << R;
|
2009-10-16 13:23:41 +08:00
|
|
|
Kind = CastExpr::CK_BitCast;
|
2009-06-26 08:50:28 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-06-28 10:36:38 +08:00
|
|
|
// All non-pointer scalars can be cast to ExtVector type. The appropriate
|
2009-06-26 08:50:28 +08:00
|
|
|
// conversion will take place first from scalar to elt type, and then
|
|
|
|
// splat from elt type to vector.
|
2009-06-28 10:36:38 +08:00
|
|
|
if (SrcTy->isPointerType())
|
|
|
|
return Diag(R.getBegin(),
|
|
|
|
diag::err_invalid_conversion_between_vector_and_scalar)
|
|
|
|
<< DestTy << SrcTy << R;
|
2009-10-20 16:27:19 +08:00
|
|
|
|
|
|
|
QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType();
|
|
|
|
ImpCastExprToType(CastExpr, DestElemTy,
|
|
|
|
getScalarCastKind(Context, SrcTy, DestElemTy));
|
2009-10-16 13:23:41 +08:00
|
|
|
|
|
|
|
Kind = CastExpr::CK_VectorSplat;
|
2009-06-26 08:50:28 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-01-20 06:31:54 +08:00
|
|
|
Action::OwningExprResult
|
2009-08-11 07:49:36 +08:00
|
|
|
Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
|
2009-01-20 06:31:54 +08:00
|
|
|
SourceLocation RParenLoc, ExprArg Op) {
|
2009-08-08 06:21:05 +08:00
|
|
|
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-20 06:31:54 +08:00
|
|
|
assert((Ty != 0) && (Op.get() != 0) &&
|
|
|
|
"ActOnCastExpr(): missing type or expr");
|
2007-07-17 07:25:18 +08:00
|
|
|
|
2009-08-11 07:49:36 +08:00
|
|
|
Expr *castExpr = (Expr *)Op.get();
|
2009-08-19 09:28:28 +08:00
|
|
|
//FIXME: Preserve type source info.
|
|
|
|
QualType castType = GetTypeFromParser(Ty);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-11 07:49:36 +08:00
|
|
|
// If the Expr being casted is a ParenListExpr, handle it specially.
|
|
|
|
if (isa<ParenListExpr>(castExpr))
|
|
|
|
return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType);
|
2009-09-10 05:33:21 +08:00
|
|
|
CXXMethodDecl *Method = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr,
|
2009-09-10 05:33:21 +08:00
|
|
|
Kind, Method))
|
2009-01-20 06:31:54 +08:00
|
|
|
return ExprError();
|
2009-09-10 05:33:21 +08:00
|
|
|
|
|
|
|
if (Method) {
|
2009-09-17 14:31:17 +08:00
|
|
|
OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind,
|
2009-09-10 05:33:21 +08:00
|
|
|
Method, move(Op));
|
2009-09-17 14:31:17 +08:00
|
|
|
|
2009-09-10 05:33:21 +08:00
|
|
|
if (CastArg.isInvalid())
|
|
|
|
return ExprError();
|
2009-09-17 14:31:17 +08:00
|
|
|
|
2009-09-10 05:33:21 +08:00
|
|
|
castExpr = CastArg.takeAs<Expr>();
|
|
|
|
} else {
|
|
|
|
Op.release();
|
2009-08-30 03:15:16 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-25 23:41:38 +08:00
|
|
|
return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(),
|
2009-09-09 23:08:12 +08:00
|
|
|
Kind, castExpr, castType,
|
2009-08-08 06:21:05 +08:00
|
|
|
LParenLoc, RParenLoc));
|
2006-11-10 13:29:30 +08:00
|
|
|
}
|
|
|
|
|
2009-08-11 07:49:36 +08:00
|
|
|
/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence
|
|
|
|
/// of comma binary operators.
|
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) {
|
|
|
|
Expr *expr = EA.takeAs<Expr>();
|
|
|
|
ParenListExpr *E = dyn_cast<ParenListExpr>(expr);
|
|
|
|
if (!E)
|
|
|
|
return Owned(expr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-11 07:49:36 +08:00
|
|
|
OwningExprResult Result(*this, E->getExpr(0));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-11 07:49:36 +08:00
|
|
|
for (unsigned i = 1, e = E->getNumExprs(); i != e && !Result.isInvalid(); ++i)
|
|
|
|
Result = ActOnBinOp(S, E->getExprLoc(), tok::comma, move(Result),
|
|
|
|
Owned(E->getExpr(i)));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-11 07:49:36 +08:00
|
|
|
return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), move(Result));
|
|
|
|
}
|
|
|
|
|
|
|
|
Action::OwningExprResult
|
|
|
|
Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc, ExprArg Op,
|
|
|
|
QualType Ty) {
|
|
|
|
ParenListExpr *PE = (ParenListExpr *)Op.get();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// If this is an altivec initializer, '(' type ')' '(' init, ..., init ')'
|
2009-08-11 07:49:36 +08:00
|
|
|
// then handle it as such.
|
|
|
|
if (getLangOptions().AltiVec && Ty->isVectorType()) {
|
|
|
|
if (PE->getNumExprs() == 0) {
|
|
|
|
Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::SmallVector<Expr *, 8> initExprs;
|
|
|
|
for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
|
|
|
|
initExprs.push_back(PE->getExpr(i));
|
|
|
|
|
|
|
|
// FIXME: This means that pretty-printing the final AST will produce curly
|
|
|
|
// braces instead of the original commas.
|
|
|
|
Op.release();
|
2009-09-09 23:08:12 +08:00
|
|
|
InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0],
|
2009-08-11 07:49:36 +08:00
|
|
|
initExprs.size(), RParenLoc);
|
|
|
|
E->setType(Ty);
|
2009-09-09 23:08:12 +08:00
|
|
|
return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,
|
2009-08-11 07:49:36 +08:00
|
|
|
Owned(E));
|
|
|
|
} else {
|
2009-09-09 23:08:12 +08:00
|
|
|
// This is not an AltiVec-style cast, so turn the ParenListExpr into a
|
2009-08-11 07:49:36 +08:00
|
|
|
// sequence of BinOp comma operators.
|
|
|
|
Op = MaybeConvertParenListExprToParenExpr(S, move(Op));
|
|
|
|
return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Action::OwningExprResult Sema::ActOnParenListExpr(SourceLocation L,
|
|
|
|
SourceLocation R,
|
|
|
|
MultiExprArg Val) {
|
|
|
|
unsigned nexprs = Val.size();
|
|
|
|
Expr **exprs = reinterpret_cast<Expr**>(Val.release());
|
|
|
|
assert((exprs != 0) && "ActOnParenListExpr() missing expr list");
|
|
|
|
Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
|
|
|
|
return Owned(expr);
|
|
|
|
}
|
|
|
|
|
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-04-17 01:51:27 +08:00
|
|
|
// C++ is sufficiently different to merit its own checker.
|
|
|
|
if (getLangOptions().CPlusPlus)
|
|
|
|
return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);
|
|
|
|
|
2009-11-05 17:23:39 +08:00
|
|
|
CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional);
|
|
|
|
|
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-04-17 01:51:27 +08:00
|
|
|
if (!CondTy->isScalarType()) { // C99 6.5.15p2
|
|
|
|
Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar)
|
|
|
|
<< CondTy;
|
|
|
|
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-08-11 07:49:36 +08:00
|
|
|
if (LHSTy->isVectorType() || RHSTy->isVectorType())
|
|
|
|
return CheckVectorOperands(QuestionLoc, LHS, RHS);
|
2008-12-06 07:32:09 +08:00
|
|
|
|
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-07-30 05:53:49 +08:00
|
|
|
if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3
|
|
|
|
if (const RecordType *RHSRT = RHSTy->getAs<RecordType>())
|
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();
|
2009-03-23 08:24:07 +08:00
|
|
|
// FIXME: Type of conditional expression must be complete in C mode.
|
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();
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, Context.VoidTy, CastExpr::CK_ToVoid);
|
|
|
|
ImpCastExprToType(RHS, Context.VoidTy, CastExpr::CK_ToVoid);
|
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-07-15 02:25:06 +08:00
|
|
|
if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) &&
|
2009-09-25 12:25:58 +08:00
|
|
|
RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
|
2009-10-20 16:27:19 +08:00
|
|
|
// promote the null to a pointer.
|
|
|
|
ImpCastExprToType(RHS, LHSTy, CastExpr::CK_Unknown);
|
2009-02-18 12:28:32 +08:00
|
|
|
return LHSTy;
|
2008-01-08 09:11:38 +08:00
|
|
|
}
|
2009-07-15 02:25:06 +08:00
|
|
|
if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) &&
|
2009-09-25 12:25:58 +08:00
|
|
|
LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown);
|
2009-02-18 12:28:32 +08:00
|
|
|
return RHSTy;
|
2008-01-08 09:11:38 +08:00
|
|
|
}
|
2009-08-18 00:35:33 +08:00
|
|
|
// Handle things like Class and struct objc_class*. Here we case the result
|
|
|
|
// to the pseudo-builtin, because that will be implicitly cast back to the
|
|
|
|
// redefinition type if an attempt is made to access its fields.
|
|
|
|
if (LHSTy->isObjCClassType() &&
|
|
|
|
(RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
|
2009-08-18 00:35:33 +08:00
|
|
|
return LHSTy;
|
|
|
|
}
|
|
|
|
if (RHSTy->isObjCClassType() &&
|
|
|
|
(LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast);
|
2009-08-18 00:35:33 +08:00
|
|
|
return RHSTy;
|
|
|
|
}
|
|
|
|
// And the same for struct objc_object* / id
|
|
|
|
if (LHSTy->isObjCIdType() &&
|
|
|
|
(RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
|
2009-08-18 00:35:33 +08:00
|
|
|
return LHSTy;
|
|
|
|
}
|
|
|
|
if (RHSTy->isObjCIdType() &&
|
|
|
|
(LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast);
|
2009-08-18 00:35:33 +08:00
|
|
|
return RHSTy;
|
|
|
|
}
|
2009-07-01 22:36:47 +08:00
|
|
|
// Handle block pointer types.
|
|
|
|
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
|
|
|
|
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
|
|
|
|
if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
|
|
|
|
QualType destType = Context.getPointerType(Context.VoidTy);
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast);
|
2009-07-01 22:36:47 +08:00
|
|
|
return destType;
|
|
|
|
}
|
|
|
|
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
|
|
|
|
<< LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
// We have 2 block pointer types.
|
|
|
|
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
|
|
|
|
// Two identical block pointer types are always compatible.
|
|
|
|
return LHSTy;
|
|
|
|
}
|
|
|
|
// The block pointer types aren't identical, continue checking.
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
|
|
|
|
QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-07-01 22:36:47 +08:00
|
|
|
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
|
|
|
|
rhptee.getUnqualifiedType())) {
|
|
|
|
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
|
|
|
|
<< LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
|
|
|
|
// 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-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast);
|
2009-07-01 22:36:47 +08:00
|
|
|
return incompatTy;
|
|
|
|
}
|
|
|
|
// The block pointer types are compatible.
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, LHSTy, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
|
2009-07-01 22:36:47 +08:00
|
|
|
return LHSTy;
|
|
|
|
}
|
|
|
|
// Check constraints for Objective-C object pointers types.
|
2009-07-11 07:34:53 +08:00
|
|
|
if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-01 22:36:47 +08:00
|
|
|
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
|
|
|
|
// Two identical object pointer types are always compatible.
|
|
|
|
return LHSTy;
|
|
|
|
}
|
2009-09-22 07:43:11 +08:00
|
|
|
const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>();
|
|
|
|
const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>();
|
2009-07-01 22:36:47 +08:00
|
|
|
QualType compositeType = LHSTy;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-01 22:36:47 +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.
|
|
|
|
|
|
|
|
// FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
|
|
|
|
// It could return the composite type.
|
2009-07-11 07:34:53 +08:00
|
|
|
if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
|
2009-08-23 06:27:17 +08:00
|
|
|
compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
|
2009-07-11 07:34:53 +08:00
|
|
|
} else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
|
2009-08-23 06:27:17 +08:00
|
|
|
compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
|
2009-09-09 23:08:12 +08:00
|
|
|
} else if ((LHSTy->isObjCQualifiedIdType() ||
|
2009-07-11 07:34:53 +08:00
|
|
|
RHSTy->isObjCQualifiedIdType()) &&
|
2009-07-23 09:01:38 +08:00
|
|
|
Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
// Need to handle "id<xx>" explicitly.
|
2009-07-11 07:34:53 +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.
|
|
|
|
compositeType = Context.getObjCIdType();
|
|
|
|
} else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) {
|
2009-07-01 22:36:47 +08:00
|
|
|
compositeType = Context.getObjCIdType();
|
2009-10-28 07:02:38 +08:00
|
|
|
} else if (!(compositeType =
|
|
|
|
Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull())
|
|
|
|
;
|
|
|
|
else {
|
2009-07-01 22:36:47 +08:00
|
|
|
Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
|
|
|
|
<< LHSTy << RHSTy
|
|
|
|
<< LHS->getSourceRange() << RHS->getSourceRange();
|
|
|
|
QualType incompatTy = Context.getObjCIdType();
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast);
|
2009-07-01 22:36:47 +08:00
|
|
|
return incompatTy;
|
|
|
|
}
|
|
|
|
// The object pointer types are compatible.
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast);
|
2009-07-01 22:36:47 +08:00
|
|
|
return compositeType;
|
|
|
|
}
|
2009-07-29 23:09:39 +08:00
|
|
|
// Check Objective-C object pointer types and 'void *'
|
|
|
|
if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) {
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
|
2009-09-22 07:43:11 +08:00
|
|
|
QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
|
2009-09-25 03:53:00 +08:00
|
|
|
QualType destPointee
|
|
|
|
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
|
2009-07-29 23:09:39 +08:00
|
|
|
QualType destType = Context.getPointerType(destPointee);
|
2009-10-20 16:27:19 +08:00
|
|
|
// Add qualifiers if necessary.
|
|
|
|
ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp);
|
|
|
|
// Promote to void*.
|
|
|
|
ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast);
|
2009-07-29 23:09:39 +08:00
|
|
|
return destType;
|
|
|
|
}
|
|
|
|
if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
|
2009-09-22 07:43:11 +08:00
|
|
|
QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
|
2009-09-25 03:53:00 +08:00
|
|
|
QualType destPointee
|
|
|
|
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
|
2009-07-29 23:09:39 +08:00
|
|
|
QualType destType = Context.getPointerType(destPointee);
|
2009-10-20 16:27:19 +08:00
|
|
|
// Add qualifiers if necessary.
|
|
|
|
ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp);
|
|
|
|
// Promote to void*.
|
|
|
|
ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast);
|
2009-07-29 23:09:39 +08:00
|
|
|
return destType;
|
|
|
|
}
|
2009-07-01 22:36:47 +08:00
|
|
|
// Check constraints for C object pointers types (C99 6.5.15p3,6).
|
|
|
|
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
|
2009-05-07 11:14:14 +08:00
|
|
|
// get the "pointed to" types
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
|
|
|
|
QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
|
2009-05-07 11:14:14 +08:00
|
|
|
|
|
|
|
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
|
2009-07-01 22:36:47 +08:00
|
|
|
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
|
2009-05-07 11:14:14 +08:00
|
|
|
// Figure out necessary qualifiers (C99 6.5.15p6)
|
2009-09-25 03:53:00 +08:00
|
|
|
QualType destPointee
|
|
|
|
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
|
2009-05-07 11:14:14 +08:00
|
|
|
QualType destType = Context.getPointerType(destPointee);
|
2009-10-20 16:27:19 +08:00
|
|
|
// Add qualifiers if necessary.
|
|
|
|
ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp);
|
|
|
|
// Promote to void*.
|
|
|
|
ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast);
|
2009-05-07 11:14:14 +08:00
|
|
|
return destType;
|
|
|
|
}
|
2009-07-01 22:36:47 +08:00
|
|
|
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
|
2009-09-25 03:53:00 +08:00
|
|
|
QualType destPointee
|
|
|
|
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
|
2009-05-07 11:14:14 +08:00
|
|
|
QualType destType = Context.getPointerType(destPointee);
|
2009-10-20 16:27:19 +08:00
|
|
|
// Add qualifiers if necessary.
|
2009-11-17 09:22:05 +08:00
|
|
|
ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp);
|
2009-10-20 16:27:19 +08:00
|
|
|
// Promote to void*.
|
2009-11-17 09:22:05 +08:00
|
|
|
ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast);
|
2009-05-07 11:14:14 +08:00
|
|
|
return destType;
|
|
|
|
}
|
|
|
|
|
2009-07-01 22:36:47 +08:00
|
|
|
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
|
2009-05-07 11:14:14 +08:00
|
|
|
// Two identical pointer types are always compatible.
|
|
|
|
return LHSTy;
|
|
|
|
}
|
2009-07-01 22:36:47 +08:00
|
|
|
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
|
|
|
|
rhptee.getUnqualifiedType())) {
|
2009-05-07 11:14:14 +08:00
|
|
|
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
|
|
|
|
<< LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
|
|
|
|
// 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-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast);
|
2009-05-07 11:14:14 +08:00
|
|
|
return incompatTy;
|
|
|
|
}
|
|
|
|
// The pointer types are compatible.
|
|
|
|
// 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.
|
|
|
|
// FIXME: Need to calculate the composite type.
|
|
|
|
// FIXME: Need to add qualifiers
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, LHSTy, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast);
|
2009-07-01 22:36:47 +08:00
|
|
|
return LHSTy;
|
2007-05-17 03:47:19 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-09 01:05:15 +08:00
|
|
|
// GCC compatibility: soften pointer/integer mismatch.
|
|
|
|
if (RHSTy->isPointerType() && LHSTy->isIntegerType()) {
|
|
|
|
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
|
|
|
|
<< LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(LHS, RHSTy, CastExpr::CK_IntegralToPointer);
|
2009-04-09 01:05:15 +08:00
|
|
|
return RHSTy;
|
|
|
|
}
|
|
|
|
if (LHSTy->isPointerType() && RHSTy->isIntegerType()) {
|
|
|
|
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
|
|
|
|
<< LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(RHS, LHSTy, CastExpr::CK_IntegralToPointer);
|
2009-04-09 01:05:15 +08:00
|
|
|
return LHSTy;
|
|
|
|
}
|
|
|
|
|
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-08-26 22:37:04 +08:00
|
|
|
return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc,
|
2009-01-21 08:14:39 +08:00
|
|
|
isLHSNull ? 0 : LHSExpr,
|
2009-08-26 22:37:04 +08:00
|
|
|
ColonLoc, RHSExpr, result));
|
2006-11-10 13:29:30 +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
|
|
|
|
2009-08-18 00:35:33 +08:00
|
|
|
if ((lhsType->isObjCClassType() &&
|
|
|
|
(rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
|
|
|
|
(rhsType->isObjCClassType() &&
|
|
|
|
(lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
|
|
|
|
return Compatible;
|
|
|
|
}
|
|
|
|
|
2007-05-11 12:00:31 +08:00
|
|
|
// get the "pointed to" type (ignoring qualifiers at the top level)
|
2009-07-30 05:53:49 +08:00
|
|
|
lhptee = lhsType->getAs<PointerType>()->getPointeeType();
|
|
|
|
rhptee = rhsType->getAs<PointerType>()->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-03-23 07:59:44 +08:00
|
|
|
lhptee = lhptee.getUnqualifiedType();
|
|
|
|
rhptee = rhptee.getUnqualifiedType();
|
|
|
|
if (!Context.typesAreCompatible(lhptee, rhptee)) {
|
|
|
|
// Check if the pointee types are compatible ignoring the sign.
|
|
|
|
// We explicitly check for char so that we catch "char" vs
|
|
|
|
// "unsigned char" on systems where "char" is unsigned.
|
2009-10-18 04:33:28 +08:00
|
|
|
if (lhptee->isCharType())
|
2009-03-23 07:59:44 +08:00
|
|
|
lhptee = Context.UnsignedCharTy;
|
2009-10-18 04:33:28 +08:00
|
|
|
else if (lhptee->isSignedIntegerType())
|
2009-03-23 07:59:44 +08:00
|
|
|
lhptee = Context.getCorrespondingUnsignedType(lhptee);
|
2009-10-18 04:33:28 +08:00
|
|
|
|
|
|
|
if (rhptee->isCharType())
|
2009-03-23 07:59:44 +08:00
|
|
|
rhptee = Context.UnsignedCharTy;
|
2009-10-18 04:33:28 +08:00
|
|
|
else if (rhptee->isSignedIntegerType())
|
2009-03-23 07:59:44 +08:00
|
|
|
rhptee = Context.getCorrespondingUnsignedType(rhptee);
|
2009-10-18 04:33:28 +08:00
|
|
|
|
2009-03-23 07:59:44 +08:00
|
|
|
if (lhptee == rhptee) {
|
|
|
|
// Types are compatible ignoring the sign. Qualifier incompatibility
|
|
|
|
// takes priority over sign incompatibility because the sign
|
|
|
|
// warning can be disabled.
|
|
|
|
if (ConvTy != Compatible)
|
|
|
|
return ConvTy;
|
|
|
|
return IncompatiblePointerSign;
|
|
|
|
}
|
2009-11-08 04:20:40 +08:00
|
|
|
|
|
|
|
// If we are a multi-level pointer, it's possible that our issue is simply
|
|
|
|
// one of qualification - e.g. char ** -> const char ** is not allowed. If
|
|
|
|
// the eventual target type is the same and the pointers have the same
|
|
|
|
// level of indirection, this must be the issue.
|
|
|
|
if (lhptee->isPointerType() && rhptee->isPointerType()) {
|
|
|
|
do {
|
|
|
|
lhptee = lhptee->getAs<PointerType>()->getPointeeType();
|
|
|
|
rhptee = rhptee->getAs<PointerType>()->getPointeeType();
|
|
|
|
|
|
|
|
lhptee = Context.getCanonicalType(lhptee);
|
|
|
|
rhptee = Context.getCanonicalType(rhptee);
|
|
|
|
} while (lhptee->isPointerType() && rhptee->isPointerType());
|
|
|
|
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (Context.hasSameUnqualifiedType(lhptee, rhptee))
|
2009-11-08 15:46:34 +08:00
|
|
|
return IncompatibleNestedPointerQualifiers;
|
2009-11-08 04:20:40 +08:00
|
|
|
}
|
|
|
|
|
2009-03-23 07:59:44 +08:00
|
|
|
// General pointer incompatibility takes priority over qualifiers.
|
2009-09-09 23:08:12 +08:00
|
|
|
return IncompatiblePointer;
|
2009-03-23 07:59:44 +08:00
|
|
|
}
|
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)
|
2009-07-30 05:53:49 +08:00
|
|
|
lhptee = lhsType->getAs<BlockPointerType>()->getPointeeType();
|
|
|
|
rhptee = rhsType->getAs<BlockPointerType>()->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
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.
|
First part of changes to eliminate problems with cv-qualifiers and
sugared types. The basic problem is that our qualifier accessors
(getQualifiers, getCVRQualifiers, isConstQualified, etc.) only look at
the current QualType and not at any qualifiers that come from sugared
types, meaning that we won't see these qualifiers through, e.g.,
typedefs:
typedef const int CInt;
typedef CInt Self;
Self.isConstQualified() currently returns false!
Various bugs (e.g., PR5383) have cropped up all over the front end due
to such problems. I'm addressing this problem by splitting each
qualifier accessor into two versions:
- the "local" version only returns qualifiers on this particular
QualType instance
- the "normal" version that will eventually combine qualifiers from this
QualType instance with the qualifiers on the canonical type to
produce the full set of qualifiers.
This commit adds the local versions and switches a few callers from
the "normal" version (e.g., isConstQualified) over to the "local"
version (e.g., isLocalConstQualified) when that is the right thing to
do, e.g., because we're printing or serializing the qualifiers. Also,
switch a bunch of
Context.getCanonicalType(T1).getUnqualifiedType() == Context.getCanonicalType(T2).getQualifiedType()
expressions over to
Context.hasSameUnqualifiedType(T1, T2)
llvm-svn: 88969
2009-11-17 05:35:15 +08:00
|
|
|
if (lhptee.getLocalCVRQualifiers() != rhptee.getLocalCVRQualifiers())
|
2008-09-04 23:10:53 +08:00
|
|
|
ConvTy = CompatiblePointerDiscardsQualifiers;
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-06-08 13:08:54 +08:00
|
|
|
if (!Context.typesAreCompatible(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
|
|
|
|
2009-08-18 00:35:33 +08:00
|
|
|
if ((lhsType->isObjCClassType() &&
|
|
|
|
(rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
|
|
|
|
(rhsType->isObjCClassType() &&
|
|
|
|
(lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
|
|
|
|
return Compatible;
|
|
|
|
}
|
|
|
|
|
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.
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) {
|
2008-10-28 08:22:11 +08:00
|
|
|
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
|
|
|
}
|
2009-06-28 10:36:38 +08:00
|
|
|
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
|
|
|
|
// to the same ExtVector type.
|
|
|
|
if (lhsType->isExtVectorType()) {
|
|
|
|
if (rhsType->isExtVectorType())
|
|
|
|
return lhsType == rhsType ? Compatible : Incompatible;
|
|
|
|
if (!rhsType->isVectorType() && rhsType->isArithmeticType())
|
|
|
|
return Compatible;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-15 02:02:46 +08:00
|
|
|
if (lhsType->isVectorType() || rhsType->isVectorType()) {
|
|
|
|
// 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
|
|
|
|
2009-07-21 01:56:53 +08:00
|
|
|
// In general, C pointers are not compatible with ObjC object pointers.
|
2009-07-11 07:34:53 +08:00
|
|
|
if (isa<ObjCObjectPointerType>(rhsType)) {
|
2009-07-21 01:56:53 +08:00
|
|
|
if (lhsType->isVoidPointerType()) // an exception to the rule.
|
|
|
|
return Compatible;
|
|
|
|
return IncompatiblePointer;
|
2009-07-11 07:34:53 +08:00
|
|
|
}
|
2009-07-30 05:53:49 +08:00
|
|
|
if (rhsType->getAs<BlockPointerType>()) {
|
|
|
|
if (lhsType->getAs<PointerType>()->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.
|
2009-07-11 07:34:53 +08:00
|
|
|
if (getLangOptions().ObjC1 && lhsType->isObjCIdType())
|
2008-09-30 02:10:17 +08:00
|
|
|
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.
|
2009-07-11 07:34:53 +08:00
|
|
|
if (getLangOptions().ObjC1 && rhsType->isObjCIdType())
|
2008-09-30 02:10:17 +08:00
|
|
|
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
|
|
|
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
|
2008-09-04 23:10:53 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-07-11 07:34:53 +08:00
|
|
|
if (isa<ObjCObjectPointerType>(lhsType)) {
|
|
|
|
if (rhsType->isIntegerType())
|
|
|
|
return IntToPointer;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-21 01:56:53 +08:00
|
|
|
// In general, C pointers are not compatible with ObjC object pointers.
|
2009-07-11 07:34:53 +08:00
|
|
|
if (isa<PointerType>(rhsType)) {
|
2009-07-21 01:56:53 +08:00
|
|
|
if (rhsType->isVoidPointerType()) // an exception to the rule.
|
|
|
|
return Compatible;
|
|
|
|
return IncompatiblePointer;
|
2009-07-11 07:34:53 +08:00
|
|
|
}
|
|
|
|
if (rhsType->isObjCObjectPointerType()) {
|
2009-07-16 02:40:39 +08:00
|
|
|
if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType())
|
|
|
|
return Compatible;
|
2009-07-21 01:56:53 +08:00
|
|
|
if (Context.typesAreCompatible(lhsType, rhsType))
|
|
|
|
return Compatible;
|
2009-07-23 09:01:38 +08:00
|
|
|
if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
|
|
|
|
return IncompatibleObjCQualifiedId;
|
2009-07-21 01:56:53 +08:00
|
|
|
return IncompatiblePointer;
|
2009-07-11 07:34:53 +08:00
|
|
|
}
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
|
2009-07-11 07:34:53 +08:00
|
|
|
if (RHSPT->getPointeeType()->isVoidType())
|
|
|
|
return Compatible;
|
|
|
|
}
|
|
|
|
// Treat block pointers as objects.
|
|
|
|
if (rhsType->isBlockPointerType())
|
|
|
|
return Compatible;
|
|
|
|
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) &&
|
2009-07-30 05:53:49 +08:00
|
|
|
rhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
|
2008-11-27 08:44:28 +08:00
|
|
|
return Compatible;
|
2008-01-05 07:18:45 +08:00
|
|
|
return Incompatible;
|
|
|
|
}
|
2009-07-11 07:34:53 +08:00
|
|
|
if (isa<ObjCObjectPointerType>(rhsType)) {
|
|
|
|
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
|
|
|
|
if (lhsType == Context.BoolTy)
|
|
|
|
return Compatible;
|
|
|
|
|
|
|
|
if (lhsType->isIntegerType())
|
|
|
|
return PointerToInt;
|
|
|
|
|
2009-07-21 01:56:53 +08:00
|
|
|
// In general, C pointers are not compatible with ObjC object pointers.
|
2009-07-11 07:34:53 +08:00
|
|
|
if (isa<PointerType>(lhsType)) {
|
2009-07-21 01:56:53 +08:00
|
|
|
if (lhsType->isVoidPointerType()) // an exception to the rule.
|
|
|
|
return Compatible;
|
|
|
|
return IncompatiblePointer;
|
2009-07-11 07:34:53 +08:00
|
|
|
}
|
|
|
|
if (isa<BlockPointerType>(lhsType) &&
|
2009-07-30 05:53:49 +08:00
|
|
|
rhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
|
2009-07-11 07:34:53 +08:00
|
|
|
return Compatible;
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2009-04-30 06:16:16 +08:00
|
|
|
/// \brief Constructs a transparent union from an expression that is
|
|
|
|
/// used to initialize the transparent union.
|
2009-09-09 23:08:12 +08:00
|
|
|
static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
|
2009-04-30 06:16:16 +08:00
|
|
|
QualType UnionType, FieldDecl *Field) {
|
|
|
|
// Build an initializer list that designates the appropriate member
|
|
|
|
// of the transparent union.
|
|
|
|
InitListExpr *Initializer = new (C) InitListExpr(SourceLocation(),
|
|
|
|
&E, 1,
|
|
|
|
SourceLocation());
|
|
|
|
Initializer->setType(UnionType);
|
|
|
|
Initializer->setInitializedFieldInUnion(Field);
|
|
|
|
|
|
|
|
// Build a compound literal constructing a value of the transparent
|
|
|
|
// union type from this initializer list.
|
|
|
|
E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
|
|
|
Sema::AssignConvertType
|
|
|
|
Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
|
|
|
|
QualType FromType = rExpr->getType();
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// If the ArgType is a Union type, we want to handle a potential
|
2009-04-30 06:16:16 +08:00
|
|
|
// transparent_union GCC extension.
|
|
|
|
const RecordType *UT = ArgType->getAsUnionType();
|
2009-06-30 10:34:44 +08:00
|
|
|
if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
|
2009-04-30 06:16:16 +08:00
|
|
|
return Incompatible;
|
|
|
|
|
|
|
|
// The field to initialize within the transparent union.
|
|
|
|
RecordDecl *UD = UT->getDecl();
|
|
|
|
FieldDecl *InitField = 0;
|
|
|
|
// It's compatible if the expression matches any of the fields.
|
2009-06-30 10:36:12 +08:00
|
|
|
for (RecordDecl::field_iterator it = UD->field_begin(),
|
|
|
|
itend = UD->field_end();
|
2009-04-30 06:16:16 +08:00
|
|
|
it != itend; ++it) {
|
|
|
|
if (it->getType()->isPointerType()) {
|
|
|
|
// If the transparent union contains a pointer type, we allow:
|
|
|
|
// 1) void pointer
|
|
|
|
// 2) null pointer constant
|
|
|
|
if (FromType->isPointerType())
|
2009-07-30 05:53:49 +08:00
|
|
|
if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_BitCast);
|
2009-04-30 06:16:16 +08:00
|
|
|
InitField = *it;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 12:25:58 +08:00
|
|
|
if (rExpr->isNullPointerConstant(Context,
|
|
|
|
Expr::NPC_ValueDependentIsNull)) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_IntegralToPointer);
|
2009-04-30 06:16:16 +08:00
|
|
|
InitField = *it;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CheckAssignmentConstraints(it->getType(), rExpr->getType())
|
|
|
|
== Compatible) {
|
|
|
|
InitField = *it;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!InitField)
|
|
|
|
return Incompatible;
|
|
|
|
|
|
|
|
ConstructTransparentUnion(Context, rExpr, ArgType, InitField);
|
|
|
|
return Compatible;
|
|
|
|
}
|
|
|
|
|
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;
|
2009-04-12 17:02:39 +08:00
|
|
|
return Compatible;
|
2008-10-22 07:43:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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-09-09 23:08:12 +08:00
|
|
|
if ((lhsType->isPointerType() ||
|
|
|
|
lhsType->isObjCObjectPointerType() ||
|
2009-02-19 11:04:26 +08:00
|
|
|
lhsType->isBlockPointerType())
|
2009-09-25 12:25:58 +08:00
|
|
|
&& rExpr->isNullPointerConstant(Context,
|
|
|
|
Expr::NPC_ValueDependentIsNull)) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rExpr, lhsType, CastExpr::CK_Unknown);
|
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
|
2009-11-04 00:56:39 +08:00
|
|
|
// DeclExpr's (created by ActOnIdExpression), 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.
|
2009-04-30 06:16:16 +08:00
|
|
|
if (result != Incompatible && rExpr->getType() != lhsType)
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rExpr, lhsType.getNonReferenceType(),
|
|
|
|
CastExpr::CK_Unknown);
|
2007-08-25 06:33:52 +08:00
|
|
|
return result;
|
2007-07-14 07:32:42 +08:00
|
|
|
}
|
|
|
|
|
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?
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const VectorType *LV = lhsType->getAs<VectorType>()) {
|
|
|
|
if (const VectorType *RV = rhsType->getAs<VectorType>())
|
2008-07-15 02:02:46 +08:00
|
|
|
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
|
|
|
|
2009-06-28 10:36:38 +08:00
|
|
|
// Canonicalize the ExtVector to the LHS, remember if we swapped so we can
|
|
|
|
// swap back (so that we don't reverse the inputs to a subtract, for instance.
|
|
|
|
bool swapped = false;
|
|
|
|
if (rhsType->isExtVectorType()) {
|
|
|
|
swapped = true;
|
|
|
|
std::swap(rex, lex);
|
|
|
|
std::swap(rhsType, lhsType);
|
2007-12-30 10:59:45 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-29 03:12:57 +08:00
|
|
|
// Handle the case of an ext vector and scalar.
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) {
|
2009-06-28 10:36:38 +08:00
|
|
|
QualType EltTy = LV->getElementType();
|
|
|
|
if (EltTy->isIntegralType() && rhsType->isIntegralType()) {
|
|
|
|
if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lhsType, CastExpr::CK_IntegralCast);
|
2009-06-28 10:36:38 +08:00
|
|
|
if (swapped) std::swap(rex, lex);
|
|
|
|
return lhsType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (EltTy->isRealFloatingType() && rhsType->isScalarType() &&
|
|
|
|
rhsType->isRealFloatingType()) {
|
|
|
|
if (Context.getFloatingTypeOrder(EltTy, rhsType) >= 0) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lhsType, CastExpr::CK_FloatingCast);
|
2009-06-28 10:36:38 +08:00
|
|
|
if (swapped) std::swap(rex, lex);
|
|
|
|
return lhsType;
|
|
|
|
}
|
2007-12-30 10:59:45 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-29 03:12:57 +08:00
|
|
|
// Vectors of different size or scalar and non-ext-vector are errors.
|
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-09-09 23:08:12 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
|
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-09-09 23:08:12 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
|
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-09-09 23:08:12 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) {
|
2009-03-28 09:22:36 +08:00
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
|
|
|
|
QualType compType = CheckVectorOperands(Loc, lex, rex);
|
|
|
|
if (CompLHSTy) *CompLHSTy = compType;
|
|
|
|
return compType;
|
|
|
|
}
|
2007-07-14 00:58:59 +08:00
|
|
|
|
2009-03-28 09:22:36 +08:00
|
|
|
QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
|
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).
|
2009-03-28 09:22:36 +08:00
|
|
|
if (lex->getType()->isArithmeticType() &&
|
|
|
|
rex->getType()->isArithmeticType()) {
|
|
|
|
if (CompLHSTy) *CompLHSTy = compType;
|
2007-08-25 03:07:16 +08:00
|
|
|
return compType;
|
2009-03-28 09:22:36 +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
|
|
|
|
2008-05-19 02:08:51 +08:00
|
|
|
// Put any potential pointer into PExp
|
|
|
|
Expr* PExp = lex, *IExp = rex;
|
2009-07-15 02:25:06 +08:00
|
|
|
if (IExp->getType()->isAnyPointerType())
|
2008-05-19 02:08:51 +08:00
|
|
|
std::swap(PExp, IExp);
|
|
|
|
|
2009-07-15 02:25:06 +08:00
|
|
|
if (PExp->getType()->isAnyPointerType()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-05-19 02:08:51 +08:00
|
|
|
if (IExp->getType()->isIntegerType()) {
|
2009-07-14 05:20:41 +08:00
|
|
|
QualType PointeeTy = PExp->getType()->getPointeeType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-25 07:50:08 +08:00
|
|
|
// Check for arithmetic on pointers to incomplete types.
|
|
|
|
if (PointeeTy->isVoidType()) {
|
2009-03-25 03:52:54 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
|
2008-11-19 13:08:23 +08:00
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2009-03-25 03:52:54 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-01-23 08:36:41 +08:00
|
|
|
|
2009-03-25 03:52:54 +08:00
|
|
|
// GNU extension: arithmetic on pointer to void
|
|
|
|
Diag(Loc, diag::ext_gnu_void_ptr)
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2009-04-25 07:50:08 +08:00
|
|
|
} else if (PointeeTy->isFunctionType()) {
|
2009-03-25 03:52:54 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lex->getType() << lex->getSourceRange();
|
2009-01-20 03:26:10 +08:00
|
|
|
return QualType();
|
2008-05-19 02:08:51 +08:00
|
|
|
}
|
2009-03-25 03:52:54 +08:00
|
|
|
|
|
|
|
// GNU extension: arithmetic on pointer to function
|
|
|
|
Diag(Loc, diag::ext_gnu_ptr_func_arith)
|
|
|
|
<< lex->getType() << lex->getSourceRange();
|
2009-07-14 05:32:29 +08:00
|
|
|
} else {
|
2009-07-14 05:20:41 +08:00
|
|
|
// Check if we require a complete type.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (((PExp->getType()->isPointerType() &&
|
2009-07-14 05:32:29 +08:00
|
|
|
!PExp->getType()->isDependentType()) ||
|
2009-07-14 05:20:41 +08:00
|
|
|
PExp->getType()->isObjCObjectPointerType()) &&
|
|
|
|
RequireCompleteType(Loc, PointeeTy,
|
2009-09-09 23:08:12 +08:00
|
|
|
PDiag(diag::err_typecheck_arithmetic_incomplete_type)
|
|
|
|
<< PExp->getSourceRange()
|
2009-08-27 06:59:12 +08:00
|
|
|
<< PExp->getType()))
|
2009-07-14 05:20:41 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-04-25 07:50:08 +08:00
|
|
|
// Diagnose bad cases where we step over interface counts.
|
|
|
|
if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
|
|
|
|
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
|
|
|
|
<< PointeeTy << PExp->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-28 09:22:36 +08:00
|
|
|
if (CompLHSTy) {
|
2009-08-20 12:21:42 +08:00
|
|
|
QualType LHSTy = Context.isPromotableBitField(lex);
|
|
|
|
if (LHSTy.isNull()) {
|
|
|
|
LHSTy = lex->getType();
|
|
|
|
if (LHSTy->isPromotableIntegerType())
|
|
|
|
LHSTy = Context.getPromotedIntegerType(LHSTy);
|
2009-05-02 08:36:19 +08:00
|
|
|
}
|
2009-03-28 09:22:36 +08:00
|
|
|
*CompLHSTy = LHSTy;
|
|
|
|
}
|
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,
|
2009-03-28 09:22:36 +08:00
|
|
|
SourceLocation Loc, QualType* CompLHSTy) {
|
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
|
|
|
|
QualType compType = CheckVectorOperands(Loc, lex, rex);
|
|
|
|
if (CompLHSTy) *CompLHSTy = compType;
|
|
|
|
return compType;
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-28 09:22:36 +08:00
|
|
|
QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
|
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).
|
2009-05-08 02:43:07 +08:00
|
|
|
if (lex->getType()->isArithmeticType()
|
|
|
|
&& rex->getType()->isArithmeticType()) {
|
2009-03-28 09:22:36 +08:00
|
|
|
if (CompLHSTy) *CompLHSTy = compType;
|
2007-08-25 03:07:16 +08:00
|
|
|
return compType;
|
2009-03-28 09:22:36 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// Either ptr - int or ptr - ptr.
|
2009-07-15 02:25:06 +08:00
|
|
|
if (lex->getType()->isAnyPointerType()) {
|
2009-07-14 01:19:15 +08:00
|
|
|
QualType lpointee = lex->getType()->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-25 03:52:54 +08:00
|
|
|
// The LHS must be an completely-defined object type.
|
|
|
|
|
|
|
|
bool ComplainAboutVoid = false;
|
|
|
|
Expr *ComplainAboutFunc = 0;
|
|
|
|
if (lpointee->isVoidType()) {
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
|
2008-11-19 13:08:23 +08:00
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
2009-03-25 03:52:54 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-01-23 08:36:41 +08:00
|
|
|
|
2009-03-25 03:52:54 +08:00
|
|
|
// GNU C extension: arithmetic on pointer to void
|
|
|
|
ComplainAboutVoid = true;
|
|
|
|
} else if (lpointee->isFunctionType()) {
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lex->getType() << lex->getSourceRange();
|
2007-12-10 05:53:25 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-03-25 03:52:54 +08:00
|
|
|
|
|
|
|
// GNU C extension: arithmetic on pointer to function
|
|
|
|
ComplainAboutFunc = lex;
|
|
|
|
} else if (!lpointee->isDependentType() &&
|
2009-09-09 23:08:12 +08:00
|
|
|
RequireCompleteType(Loc, lpointee,
|
2009-08-27 06:59:12 +08:00
|
|
|
PDiag(diag::err_typecheck_sub_ptr_object)
|
2009-09-09 23:08:12 +08:00
|
|
|
<< lex->getSourceRange()
|
2009-08-27 06:59:12 +08:00
|
|
|
<< lex->getType()))
|
2009-03-25 03:52:54 +08:00
|
|
|
return QualType();
|
2007-12-10 05:53:25 +08:00
|
|
|
|
2009-04-25 07:50:08 +08:00
|
|
|
// Diagnose bad cases where we step over interface counts.
|
|
|
|
if (lpointee->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
|
|
|
|
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
|
|
|
|
<< lpointee << lex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// The result type of a pointer-int computation is the pointer type.
|
2009-03-25 03:52:54 +08:00
|
|
|
if (rex->getType()->isIntegerType()) {
|
|
|
|
if (ComplainAboutVoid)
|
|
|
|
Diag(Loc, diag::ext_gnu_void_ptr)
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
if (ComplainAboutFunc)
|
|
|
|
Diag(Loc, diag::ext_gnu_ptr_func_arith)
|
2009-09-09 23:08:12 +08:00
|
|
|
<< ComplainAboutFunc->getType()
|
2009-03-25 03:52:54 +08:00
|
|
|
<< ComplainAboutFunc->getSourceRange();
|
|
|
|
|
2009-03-28 09:22:36 +08:00
|
|
|
if (CompLHSTy) *CompLHSTy = lex->getType();
|
2007-12-10 05:53:25 +08:00
|
|
|
return lex->getType();
|
2009-03-25 03:52:54 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-12-10 05:53:25 +08:00
|
|
|
// Handle pointer-pointer subtractions.
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const PointerType *RHSPTy = rex->getType()->getAs<PointerType>()) {
|
2008-02-08 09:19:44 +08:00
|
|
|
QualType rpointee = RHSPTy->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-25 03:52:54 +08:00
|
|
|
// RHS must be a completely-type object type.
|
|
|
|
// Handle the GNU void* extension.
|
|
|
|
if (rpointee->isVoidType()) {
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-25 03:52:54 +08:00
|
|
|
ComplainAboutVoid = true;
|
|
|
|
} else if (rpointee->isFunctionType()) {
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< rex->getType() << rex->getSourceRange();
|
2007-12-10 05:53:25 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-03-25 03:52:54 +08:00
|
|
|
|
|
|
|
// GNU extension: arithmetic on pointer to function
|
|
|
|
if (!ComplainAboutFunc)
|
|
|
|
ComplainAboutFunc = rex;
|
|
|
|
} else if (!rpointee->isDependentType() &&
|
|
|
|
RequireCompleteType(Loc, rpointee,
|
2009-08-27 06:59:12 +08:00
|
|
|
PDiag(diag::err_typecheck_sub_ptr_object)
|
|
|
|
<< rex->getSourceRange()
|
|
|
|
<< rex->getType()))
|
2009-03-25 03:52:54 +08:00
|
|
|
return QualType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-05-16 21:54:38 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
// Pointee types must be the same: C++ [expr.add]
|
|
|
|
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
|
|
|
|
Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
|
|
|
|
<< lex->getType() << rex->getType()
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Pointee types must be compatible C99 6.5.6p3
|
|
|
|
if (!Context.typesAreCompatible(
|
|
|
|
Context.getCanonicalType(lpointee).getUnqualifiedType(),
|
|
|
|
Context.getCanonicalType(rpointee).getUnqualifiedType())) {
|
|
|
|
Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
|
|
|
|
<< lex->getType() << rex->getType()
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
2007-12-10 05:53:25 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-25 03:52:54 +08:00
|
|
|
if (ComplainAboutVoid)
|
|
|
|
Diag(Loc, diag::ext_gnu_void_ptr)
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
if (ComplainAboutFunc)
|
|
|
|
Diag(Loc, diag::ext_gnu_ptr_func_arith)
|
2009-09-09 23:08:12 +08:00
|
|
|
<< ComplainAboutFunc->getType()
|
2009-03-25 03:52:54 +08:00
|
|
|
<< ComplainAboutFunc->getSourceRange();
|
2009-03-28 09:22:36 +08:00
|
|
|
|
|
|
|
if (CompLHSTy) *CompLHSTy = lex->getType();
|
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
|
|
|
|
2009-10-25 10:26:48 +08:00
|
|
|
// Vector shifts promote their scalar inputs to vector type.
|
|
|
|
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
|
|
|
|
return CheckVectorOperands(Loc, lex, rex);
|
|
|
|
|
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
|
2009-08-20 12:21:42 +08:00
|
|
|
QualType LHSTy = Context.isPromotableBitField(lex);
|
|
|
|
if (LHSTy.isNull()) {
|
|
|
|
LHSTy = lex->getType();
|
|
|
|
if (LHSTy->isPromotableIntegerType())
|
|
|
|
LHSTy = Context.getPromotedIntegerType(LHSTy);
|
2009-05-02 08:36:19 +08:00
|
|
|
}
|
2007-12-13 15:28:16 +08:00
|
|
|
if (!isCompAssign)
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(lex, LHSTy, CastExpr::CK_IntegralCast);
|
2009-03-28 09:22:36 +08:00
|
|
|
|
2007-12-12 13:47:28 +08:00
|
|
|
UsualUnaryConversions(rex);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-08-08 00:20:20 +08:00
|
|
|
// Sanity-check shift operands
|
|
|
|
llvm::APSInt Right;
|
|
|
|
// Check right/shifter operand
|
2009-09-17 14:31:27 +08:00
|
|
|
if (!rex->isValueDependent() &&
|
|
|
|
rex->isIntegerConstantExpr(Right, Context)) {
|
2009-08-09 03:18:23 +08:00
|
|
|
if (Right.isNegative())
|
2009-08-08 00:20:20 +08:00
|
|
|
Diag(Loc, diag::warn_shift_negative) << rex->getSourceRange();
|
|
|
|
else {
|
|
|
|
llvm::APInt LeftBits(Right.getBitWidth(),
|
|
|
|
Context.getTypeSize(lex->getType()));
|
|
|
|
if (Right.uge(LeftBits))
|
|
|
|
Diag(Loc, diag::warn_shift_gt_typewidth) << rex->getSourceRange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-12 13:47:28 +08:00
|
|
|
// "The type of the result is that of the promoted left operand."
|
2009-03-28 09:22:36 +08:00
|
|
|
return LHSTy;
|
2007-03-22 05:08:52 +08:00
|
|
|
}
|
|
|
|
|
2009-11-06 16:49:08 +08:00
|
|
|
/// \brief Implements -Wsign-compare.
|
|
|
|
///
|
|
|
|
/// \param lex the left-hand expression
|
|
|
|
/// \param rex the right-hand expression
|
|
|
|
/// \param OpLoc the location of the joining operator
|
2009-11-06 16:53:51 +08:00
|
|
|
/// \param Equality whether this is an "equality-like" join, which
|
|
|
|
/// suppresses the warning in some cases
|
2009-11-05 17:23:39 +08:00
|
|
|
void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
|
2009-11-06 16:49:08 +08:00
|
|
|
const PartialDiagnostic &PD, bool Equality) {
|
2009-11-07 02:16:06 +08:00
|
|
|
// Don't warn if we're in an unevaluated context.
|
|
|
|
if (ExprEvalContext == Unevaluated)
|
|
|
|
return;
|
|
|
|
|
2009-11-05 08:40:04 +08:00
|
|
|
QualType lt = lex->getType(), rt = rex->getType();
|
|
|
|
|
|
|
|
// Only warn if both operands are integral.
|
|
|
|
if (!lt->isIntegerType() || !rt->isIntegerType())
|
|
|
|
return;
|
|
|
|
|
2009-11-06 05:09:23 +08:00
|
|
|
// If either expression is value-dependent, don't warn. We'll get another
|
|
|
|
// chance at instantiation time.
|
|
|
|
if (lex->isValueDependent() || rex->isValueDependent())
|
|
|
|
return;
|
|
|
|
|
2009-11-05 08:40:04 +08:00
|
|
|
// The rule is that the signed operand becomes unsigned, so isolate the
|
|
|
|
// signed operand.
|
2009-11-06 16:49:08 +08:00
|
|
|
Expr *signedOperand, *unsignedOperand;
|
2009-11-05 08:40:04 +08:00
|
|
|
if (lt->isSignedIntegerType()) {
|
|
|
|
if (rt->isSignedIntegerType()) return;
|
|
|
|
signedOperand = lex;
|
2009-11-06 16:49:08 +08:00
|
|
|
unsignedOperand = rex;
|
2009-11-05 08:40:04 +08:00
|
|
|
} else {
|
|
|
|
if (!rt->isSignedIntegerType()) return;
|
|
|
|
signedOperand = rex;
|
2009-11-06 16:49:08 +08:00
|
|
|
unsignedOperand = lex;
|
2009-11-05 08:40:04 +08:00
|
|
|
}
|
|
|
|
|
2009-11-06 16:49:08 +08:00
|
|
|
// If the unsigned type is strictly smaller than the signed type,
|
2009-11-06 16:53:51 +08:00
|
|
|
// then (1) the result type will be signed and (2) the unsigned
|
|
|
|
// value will fit fully within the signed type, and thus the result
|
2009-11-06 16:49:08 +08:00
|
|
|
// of the comparison will be exact.
|
|
|
|
if (Context.getIntWidth(signedOperand->getType()) >
|
|
|
|
Context.getIntWidth(unsignedOperand->getType()))
|
|
|
|
return;
|
|
|
|
|
2009-11-05 08:40:04 +08:00
|
|
|
// If the value is a non-negative integer constant, then the
|
|
|
|
// signed->unsigned conversion won't change it.
|
|
|
|
llvm::APSInt value;
|
2009-11-05 17:23:39 +08:00
|
|
|
if (signedOperand->isIntegerConstantExpr(value, Context)) {
|
2009-11-05 08:40:04 +08:00
|
|
|
assert(value.isSigned() && "result of signed expression not signed");
|
|
|
|
|
|
|
|
if (value.isNonNegative())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-11-06 16:49:08 +08:00
|
|
|
if (Equality) {
|
|
|
|
// For (in)equality comparisons, if the unsigned operand is a
|
2009-11-06 16:53:51 +08:00
|
|
|
// constant which cannot collide with a overflowed signed operand,
|
|
|
|
// then reinterpreting the signed operand as unsigned will not
|
|
|
|
// change the result of the comparison.
|
2009-11-06 16:49:08 +08:00
|
|
|
if (unsignedOperand->isIntegerConstantExpr(value, Context)) {
|
|
|
|
assert(!value.isSigned() && "result of unsigned expression is signed");
|
|
|
|
|
|
|
|
// 2's complement: test the top bit.
|
|
|
|
if (value.isNonNegative())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-05 17:23:39 +08:00
|
|
|
Diag(OpLoc, PD)
|
2009-11-05 08:40:04 +08:00
|
|
|
<< lex->getType() << rex->getType()
|
|
|
|
<< lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
}
|
|
|
|
|
Implement support for comparing pointers with <, >, <=, >=, ==, and !=
in C++, taking into account conversions to the "composite pointer
type" so that we can compare, e.g., a pointer to a derived class to a
pointer to a base class.
Also, upgrade the "comparing distinct pointer types" from a warning to
an error for C++, since this is clearly an error. Turns out that we
hadn't gone through and audited this code for C++, ever.
Fixes <rdar://problem/6816420>.
llvm-svn: 70829
2009-05-04 14:07:12 +08:00
|
|
|
// C99 6.5.8, C++ [expr.rel]
|
2008-11-18 09:30:42 +08:00
|
|
|
QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
|
2009-04-07 02:45:53 +08:00
|
|
|
unsigned OpaqueOpc, bool isRelational) {
|
|
|
|
BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)OpaqueOpc;
|
|
|
|
|
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
|
|
|
|
2009-11-06 16:49:08 +08:00
|
|
|
CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison,
|
|
|
|
(Opc == BinaryOperator::EQ || Opc == BinaryOperator::NE));
|
2009-11-05 08:40:04 +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
|
|
|
|
2009-05-08 02:43:07 +08:00
|
|
|
if (!lType->isFloatingType()
|
|
|
|
&& !(lType->isBlockPointerType() && isRelational)) {
|
2009-03-09 03:39:53 +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.
|
2009-09-09 23:08:12 +08:00
|
|
|
// NOTE: Don't warn about comparisons of enum constants. These can arise
|
2009-03-21 03:57:37 +08:00
|
|
|
// from macro expansions, and are usually quite deliberate.
|
2009-03-09 03:39:53 +08:00
|
|
|
Expr *LHSStripped = lex->IgnoreParens();
|
|
|
|
Expr *RHSStripped = rex->IgnoreParens();
|
|
|
|
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped))
|
|
|
|
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped))
|
2009-03-21 02:35:45 +08:00
|
|
|
if (DRL->getDecl() == DRR->getDecl() &&
|
|
|
|
!isa<EnumConstantDecl>(DRL->getDecl()))
|
2009-02-19 11:04:26 +08:00
|
|
|
Diag(Loc, diag::warn_selfcomparison);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-09 03:39:53 +08:00
|
|
|
if (isa<CastExpr>(LHSStripped))
|
|
|
|
LHSStripped = LHSStripped->IgnoreParenCasts();
|
|
|
|
if (isa<CastExpr>(RHSStripped))
|
|
|
|
RHSStripped = RHSStripped->IgnoreParenCasts();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-09 03:39:53 +08:00
|
|
|
// Warn about comparisons against a string constant (unless the other
|
|
|
|
// operand is null), the user probably wants strcmp.
|
2009-04-07 02:45:53 +08:00
|
|
|
Expr *literalString = 0;
|
|
|
|
Expr *literalStringStripped = 0;
|
2009-03-09 03:39:53 +08:00
|
|
|
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
|
2009-09-25 12:25:58 +08:00
|
|
|
!RHSStripped->isNullPointerConstant(Context,
|
|
|
|
Expr::NPC_ValueDependentIsNull)) {
|
2009-04-07 02:45:53 +08:00
|
|
|
literalString = lex;
|
|
|
|
literalStringStripped = LHSStripped;
|
2009-08-05 05:02:39 +08:00
|
|
|
} else if ((isa<StringLiteral>(RHSStripped) ||
|
|
|
|
isa<ObjCEncodeExpr>(RHSStripped)) &&
|
2009-09-25 12:25:58 +08:00
|
|
|
!LHSStripped->isNullPointerConstant(Context,
|
|
|
|
Expr::NPC_ValueDependentIsNull)) {
|
2009-04-07 02:45:53 +08:00
|
|
|
literalString = rex;
|
|
|
|
literalStringStripped = RHSStripped;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (literalString) {
|
|
|
|
std::string resultComparison;
|
|
|
|
switch (Opc) {
|
|
|
|
case BinaryOperator::LT: resultComparison = ") < 0"; break;
|
|
|
|
case BinaryOperator::GT: resultComparison = ") > 0"; break;
|
|
|
|
case BinaryOperator::LE: resultComparison = ") <= 0"; break;
|
|
|
|
case BinaryOperator::GE: resultComparison = ") >= 0"; break;
|
|
|
|
case BinaryOperator::EQ: resultComparison = ") == 0"; break;
|
|
|
|
case BinaryOperator::NE: resultComparison = ") != 0"; break;
|
|
|
|
default: assert(false && "Invalid comparison operator");
|
|
|
|
}
|
|
|
|
Diag(Loc, diag::warn_stringcompare)
|
|
|
|
<< isa<ObjCEncodeExpr>(literalStringStripped)
|
|
|
|
<< literalString->getSourceRange()
|
2009-04-02 07:51:29 +08:00
|
|
|
<< CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
|
|
|
|
<< CodeModificationHint::CreateInsertion(lex->getLocStart(),
|
|
|
|
"strcmp(")
|
|
|
|
<< CodeModificationHint::CreateInsertion(
|
|
|
|
PP.getLocForEndOfToken(rex->getLocEnd()),
|
2009-04-07 02:45:53 +08:00
|
|
|
resultComparison);
|
|
|
|
}
|
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.
|
2009-03-09 03:39:53 +08:00
|
|
|
QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy :Context.IntTy;
|
2008-11-19 11:25:36 +08:00
|
|
|
|
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()) {
|
2009-03-09 03:39:53 +08:00
|
|
|
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
|
|
|
|
2009-09-25 12:25:58 +08:00
|
|
|
bool LHSIsNull = lex->isNullPointerConstant(Context,
|
|
|
|
Expr::NPC_ValueDependentIsNull);
|
|
|
|
bool RHSIsNull = rex->isNullPointerConstant(Context,
|
|
|
|
Expr::NPC_ValueDependentIsNull);
|
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 =
|
2009-07-30 05:53:49 +08:00
|
|
|
Context.getCanonicalType(lType->getAs<PointerType>()->getPointeeType());
|
2008-04-03 13:07:25 +08:00
|
|
|
QualType RCanPointeeTy =
|
2009-07-30 05:53:49 +08:00
|
|
|
Context.getCanonicalType(rType->getAs<PointerType>()->getPointeeType());
|
2009-02-19 11:04:26 +08:00
|
|
|
|
Implement support for comparing pointers with <, >, <=, >=, ==, and !=
in C++, taking into account conversions to the "composite pointer
type" so that we can compare, e.g., a pointer to a derived class to a
pointer to a base class.
Also, upgrade the "comparing distinct pointer types" from a warning to
an error for C++, since this is clearly an error. Turns out that we
hadn't gone through and audited this code for C++, ever.
Fixes <rdar://problem/6816420>.
llvm-svn: 70829
2009-05-04 14:07:12 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
2009-08-23 08:27:47 +08:00
|
|
|
if (LCanPointeeTy == RCanPointeeTy)
|
|
|
|
return ResultTy;
|
|
|
|
|
Implement support for comparing pointers with <, >, <=, >=, ==, and !=
in C++, taking into account conversions to the "composite pointer
type" so that we can compare, e.g., a pointer to a derived class to a
pointer to a base class.
Also, upgrade the "comparing distinct pointer types" from a warning to
an error for C++, since this is clearly an error. Turns out that we
hadn't gone through and audited this code for C++, ever.
Fixes <rdar://problem/6816420>.
llvm-svn: 70829
2009-05-04 14:07:12 +08:00
|
|
|
// C++ [expr.rel]p2:
|
|
|
|
// [...] Pointer conversions (4.10) and qualification
|
|
|
|
// conversions (4.4) are performed on pointer operands (or on
|
|
|
|
// a pointer operand and a null pointer constant) to bring
|
|
|
|
// them to their composite pointer type. [...]
|
|
|
|
//
|
2009-08-25 01:42:35 +08:00
|
|
|
// C++ [expr.eq]p1 uses the same notion for (in)equality
|
Implement support for comparing pointers with <, >, <=, >=, ==, and !=
in C++, taking into account conversions to the "composite pointer
type" so that we can compare, e.g., a pointer to a derived class to a
pointer to a base class.
Also, upgrade the "comparing distinct pointer types" from a warning to
an error for C++, since this is clearly an error. Turns out that we
hadn't gone through and audited this code for C++, ever.
Fixes <rdar://problem/6816420>.
llvm-svn: 70829
2009-05-04 14:07:12 +08:00
|
|
|
// comparisons of pointers.
|
2009-05-05 12:50:50 +08:00
|
|
|
QualType T = FindCompositePointerType(lex, rex);
|
Implement support for comparing pointers with <, >, <=, >=, ==, and !=
in C++, taking into account conversions to the "composite pointer
type" so that we can compare, e.g., a pointer to a derived class to a
pointer to a base class.
Also, upgrade the "comparing distinct pointer types" from a warning to
an error for C++, since this is clearly an error. Turns out that we
hadn't gone through and audited this code for C++, ever.
Fixes <rdar://problem/6816420>.
llvm-svn: 70829
2009-05-04 14:07:12 +08:00
|
|
|
if (T.isNull()) {
|
|
|
|
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
|
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(lex, T, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(rex, T, CastExpr::CK_BitCast);
|
Implement support for comparing pointers with <, >, <=, >=, ==, and !=
in C++, taking into account conversions to the "composite pointer
type" so that we can compare, e.g., a pointer to a derived class to a
pointer to a base class.
Also, upgrade the "comparing distinct pointer types" from a warning to
an error for C++, since this is clearly an error. Turns out that we
hadn't gone through and audited this code for C++, ever.
Fixes <rdar://problem/6816420>.
llvm-svn: 70829
2009-05-04 14:07:12 +08:00
|
|
|
return ResultTy;
|
|
|
|
}
|
2009-08-23 08:27:47 +08:00
|
|
|
// C99 6.5.9p2 and C99 6.5.8p2
|
|
|
|
if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
|
|
|
|
RCanPointeeTy.getUnqualifiedType())) {
|
|
|
|
// Valid unless a relational comparison of function pointers
|
|
|
|
if (isRelational && LCanPointeeTy->isFunctionType()) {
|
|
|
|
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
|
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
}
|
|
|
|
} else if (!isRelational &&
|
|
|
|
(LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
|
|
|
|
// Valid unless comparison between non-null pointer and function pointer
|
|
|
|
if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
|
|
|
|
&& !LHSIsNull && !RHSIsNull) {
|
|
|
|
Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void)
|
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Invalid
|
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
|
|
|
}
|
2009-08-23 08:27:47 +08:00
|
|
|
if (LCanPointeeTy != RCanPointeeTy)
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lType, CastExpr::CK_BitCast);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2007-08-17 05:48:38 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-11 02:38:11 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
2009-09-09 23:08:12 +08:00
|
|
|
// Comparison of pointers with null pointer constants and equality
|
2009-08-25 01:42:35 +08:00
|
|
|
// comparisons of member pointers to null pointer constants.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (RHSIsNull &&
|
2009-08-25 01:42:35 +08:00
|
|
|
(lType->isPointerType() ||
|
|
|
|
(!isRelational && lType->isMemberPointerType()))) {
|
2009-08-25 02:03:14 +08:00
|
|
|
ImpCastExprToType(rex, lType, CastExpr::CK_NullToMemberPointer);
|
2009-05-11 02:38:11 +08:00
|
|
|
return ResultTy;
|
|
|
|
}
|
2009-08-25 01:42:35 +08:00
|
|
|
if (LHSIsNull &&
|
|
|
|
(rType->isPointerType() ||
|
|
|
|
(!isRelational && rType->isMemberPointerType()))) {
|
2009-08-25 02:03:14 +08:00
|
|
|
ImpCastExprToType(lex, rType, CastExpr::CK_NullToMemberPointer);
|
2009-05-11 02:38:11 +08:00
|
|
|
return ResultTy;
|
|
|
|
}
|
2009-08-25 01:42:35 +08:00
|
|
|
|
|
|
|
// Comparison of member pointers.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!isRelational &&
|
2009-08-25 01:42:35 +08:00
|
|
|
lType->isMemberPointerType() && rType->isMemberPointerType()) {
|
|
|
|
// C++ [expr.eq]p2:
|
2009-09-09 23:08:12 +08:00
|
|
|
// In addition, pointers to members can be compared, or a pointer to
|
|
|
|
// member and a null pointer constant. Pointer to member conversions
|
|
|
|
// (4.11) and qualification conversions (4.4) are performed to bring
|
|
|
|
// them to a common type. If one operand is a null pointer constant,
|
|
|
|
// the common type is the type of the other operand. Otherwise, the
|
|
|
|
// common type is a pointer to member type similar (4.4) to the type
|
|
|
|
// of one of the operands, with a cv-qualification signature (4.4)
|
|
|
|
// that is the union of the cv-qualification signatures of the operand
|
2009-08-25 01:42:35 +08:00
|
|
|
// types.
|
|
|
|
QualType T = FindCompositePointerType(lex, rex);
|
|
|
|
if (T.isNull()) {
|
|
|
|
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
|
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(lex, T, CastExpr::CK_BitCast);
|
|
|
|
ImpCastExprToType(rex, T, CastExpr::CK_BitCast);
|
2009-08-25 01:42:35 +08:00
|
|
|
return ResultTy;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-25 01:42:35 +08:00
|
|
|
// Comparison of nullptr_t with itself.
|
2009-05-11 02:38:11 +08:00
|
|
|
if (lType->isNullPtrType() && rType->isNullPtrType())
|
|
|
|
return ResultTy;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
// Handle block pointer types.
|
2009-05-07 11:14:14 +08:00
|
|
|
if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) {
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType();
|
|
|
|
QualType rpointee = rType->getAs<BlockPointerType>()->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2008-09-04 23:10:53 +08:00
|
|
|
if (!LHSIsNull && !RHSIsNull &&
|
2009-06-08 13:08:54 +08:00
|
|
|
!Context.typesAreCompatible(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
|
|
|
}
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lType, CastExpr::CK_BitCast);
|
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.
|
2009-05-07 11:14:14 +08:00
|
|
|
if (!isRelational
|
|
|
|
&& ((lType->isBlockPointerType() && rType->isPointerType())
|
|
|
|
|| (lType->isPointerType() && rType->isBlockPointerType()))) {
|
2008-09-28 09:11:11 +08:00
|
|
|
if (!LHSIsNull && !RHSIsNull) {
|
2009-07-30 05:53:49 +08:00
|
|
|
if (!((rType->isPointerType() && rType->getAs<PointerType>()
|
2009-05-07 11:14:14 +08:00
|
|
|
->getPointeeType()->isVoidType())
|
2009-07-30 05:53:49 +08:00
|
|
|
|| (lType->isPointerType() && lType->getAs<PointerType>()
|
2009-05-07 11:14:14 +08:00
|
|
|
->getPointeeType()->isVoidType())))
|
|
|
|
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
|
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2008-09-04 23:10:53 +08:00
|
|
|
}
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lType, CastExpr::CK_BitCast);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-09-04 23:10:53 +08:00
|
|
|
}
|
|
|
|
|
2009-07-11 07:34:53 +08:00
|
|
|
if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) {
|
2008-10-27 18:33:19 +08:00
|
|
|
if (lType->isPointerType() || rType->isPointerType()) {
|
2009-07-30 05:53:49 +08:00
|
|
|
const PointerType *LPT = lType->getAs<PointerType>();
|
|
|
|
const PointerType *RPT = rType->getAs<PointerType>();
|
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
|
|
|
}
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lType, CastExpr::CK_BitCast);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-10-21 02:19:10 +08:00
|
|
|
}
|
2009-07-11 07:34:53 +08:00
|
|
|
if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) {
|
2009-08-23 02:58:31 +08:00
|
|
|
if (!Context.areComparableObjCPointerTypes(lType, rType))
|
2009-07-11 07:34:53 +08:00
|
|
|
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
|
2008-11-24 13:29:24 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lType, CastExpr::CK_BitCast);
|
2009-07-11 07:34:53 +08:00
|
|
|
return ResultTy;
|
2008-06-03 22:04:54 +08:00
|
|
|
}
|
2007-12-20 09:06:58 +08:00
|
|
|
}
|
2009-07-15 02:25:06 +08:00
|
|
|
if (lType->isAnyPointerType() && rType->isIntegerType()) {
|
2009-08-23 08:03:44 +08:00
|
|
|
unsigned DiagID = 0;
|
|
|
|
if (RHSIsNull) {
|
|
|
|
if (isRelational)
|
|
|
|
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
|
|
|
|
} else if (isRelational)
|
|
|
|
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
|
|
|
|
else
|
|
|
|
DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-23 08:03:44 +08:00
|
|
|
if (DiagID) {
|
2009-08-23 02:58:31 +08:00
|
|
|
Diag(Loc, DiagID)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2009-08-23 02:58:31 +08:00
|
|
|
}
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lType, CastExpr::CK_IntegralToPointer);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2007-08-17 05:48:38 +08:00
|
|
|
}
|
2009-07-15 02:25:06 +08:00
|
|
|
if (lType->isIntegerType() && rType->isAnyPointerType()) {
|
2009-08-23 08:03:44 +08:00
|
|
|
unsigned DiagID = 0;
|
|
|
|
if (LHSIsNull) {
|
|
|
|
if (isRelational)
|
|
|
|
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
|
|
|
|
} else if (isRelational)
|
|
|
|
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
|
|
|
|
else
|
|
|
|
DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-23 08:03:44 +08:00
|
|
|
if (DiagID) {
|
2009-08-23 02:58:31 +08:00
|
|
|
Diag(Loc, DiagID)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
|
2009-08-23 02:58:31 +08:00
|
|
|
}
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(lex, rType, CastExpr::CK_IntegralToPointer);
|
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.
|
2009-05-08 02:43:07 +08:00
|
|
|
if (!isRelational && RHSIsNull
|
|
|
|
&& lType->isBlockPointerType() && rType->isIntegerType()) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(rex, lType, CastExpr::CK_IntegralToPointer);
|
2008-11-19 11:25:36 +08:00
|
|
|
return ResultTy;
|
2008-09-05 00:56:14 +08:00
|
|
|
}
|
2009-05-08 02:43:07 +08:00
|
|
|
if (!isRelational && LHSIsNull
|
|
|
|
&& lType->isIntegerType() && rType->isBlockPointerType()) {
|
2009-10-20 16:27:19 +08:00
|
|
|
ImpCastExprToType(lex, rType, CastExpr::CK_IntegralToPointer);
|
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
|
|
|
|
2009-09-22 07:43:11 +08:00
|
|
|
const VectorType *VTy = lType->getAs<VectorType>();
|
2008-07-15 02:02:46 +08:00
|
|
|
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-03-31 15:46:52 +08:00
|
|
|
if (TypeSize == Context.getTypeSize(Context.LongTy))
|
2009-01-18 11:20:47 +08:00
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
Expr *&lex, Expr *&rex, 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);
|
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-09-09 23:08:12 +08:00
|
|
|
Expr *&lex, Expr *&rex, SourceLocation Loc) {
|
2007-07-17 05:54:35 +08:00
|
|
|
UsualUnaryConversions(lex);
|
|
|
|
UsualUnaryConversions(rex);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-10-16 09:44:21 +08:00
|
|
|
if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType())
|
|
|
|
return InvalidOperands(Loc, lex, rex);
|
|
|
|
|
|
|
|
if (Context.getLangOptions().CPlusPlus) {
|
|
|
|
// C++ [expr.log.and]p2
|
|
|
|
// C++ [expr.log.or]p2
|
|
|
|
return Context.BoolTy;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Context.IntTy;
|
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-09-09 23:08:12 +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();
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const ObjCObjectPointerType *OPT =
|
2009-07-11 07:34:53 +08:00
|
|
|
BaseType->getAsObjCInterfacePointerType())
|
|
|
|
if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
|
|
|
|
if (S.isPropertyReadonly(PDecl, IFace))
|
|
|
|
return true;
|
2009-01-13 03:55:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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-04-15 08:08:05 +08:00
|
|
|
SourceLocation OrigLoc = Loc;
|
2009-09-09 23:08:12 +08:00
|
|
|
Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
|
2009-04-15 08:08:05 +08:00
|
|
|
&Loc);
|
2009-01-13 03:55:42 +08:00
|
|
|
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-03-10 00:13:40 +08:00
|
|
|
return S.RequireCompleteType(Loc, E->getType(),
|
2009-08-27 07:45:07 +08:00
|
|
|
PDiag(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
|
|
|
|
2009-04-15 08:08:05 +08:00
|
|
|
SourceRange Assign;
|
|
|
|
if (Loc != OrigLoc)
|
|
|
|
Assign = SourceRange(OrigLoc, OrigLoc);
|
2008-11-18 09:22:49 +08:00
|
|
|
if (NeedType)
|
2009-04-15 08:08:05 +08:00
|
|
|
S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign;
|
2008-11-18 09:22:49 +08:00
|
|
|
else
|
2009-09-09 23:08:12 +08:00
|
|
|
S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
|
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) &&
|
2009-07-16 23:41:00 +08:00
|
|
|
RHSType->isObjCObjectPointerType()) ||
|
2009-01-14 07:34:40 +08:00
|
|
|
(Context.isObjCNSObjectType(RHSType) &&
|
2009-07-16 23:41:00 +08:00
|
|
|
LHSType->isObjCObjectPointerType())))
|
2009-01-14 07:34:40 +08:00
|
|
|
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.
|
2009-03-08 14:51:10 +08:00
|
|
|
Loc.getFileLocWithOffset(1) == UO->getOperatorLoc() &&
|
|
|
|
// And there is a space or other character before the subexpr of the
|
|
|
|
// unary +/-. We don't want to warn on "x=-1".
|
2009-03-09 15:11:10 +08:00
|
|
|
Loc.getFileLocWithOffset(2) != UO->getSubExpr()->getLocStart() &&
|
|
|
|
UO->getSubExpr()->getLocStart().isFileID()) {
|
2008-11-20 14:06:08 +08:00
|
|
|
Diag(Loc, diag::warn_not_compound_assign)
|
|
|
|
<< (UO->getOpcode() == UnaryOperator::Plus ? "+" : "-")
|
|
|
|
<< SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc());
|
2009-03-08 14:51:10 +08:00
|
|
|
}
|
2008-08-22 02:04:13 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Compound assignment "x += y"
|
2009-05-16 13:56:02 +08:00
|
|
|
ConvTy = CheckAssignmentConstraints(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
|
2009-05-02 08:36:19 +08:00
|
|
|
// operand.
|
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) {
|
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);
|
2009-03-23 08:24:07 +08:00
|
|
|
|
|
|
|
// FIXME: Check that RHS type is complete in C mode (it's legal for it to be
|
|
|
|
// incomplete in C++).
|
|
|
|
|
2008-11-18 09:30:42 +08:00
|
|
|
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!
|
2009-07-15 02:25:06 +08:00
|
|
|
} else if (ResType->isAnyPointerType()) {
|
|
|
|
QualType PointeeTy = ResType->getPointeeType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-21 15:05:48 +08:00
|
|
|
// C99 6.5.2.4p2, 6.5.6p2
|
2009-07-11 07:34:53 +08:00
|
|
|
if (PointeeTy->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-07-11 07:34:53 +08:00
|
|
|
} else if (PointeeTy->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();
|
2009-07-11 07:34:53 +08:00
|
|
|
} else if (RequireCompleteType(OpLoc, PointeeTy,
|
2009-08-27 06:59:12 +08:00
|
|
|
PDiag(diag::err_typecheck_arithmetic_incomplete_type)
|
2009-09-09 23:08:12 +08:00
|
|
|
<< Op->getSourceRange()
|
2009-08-27 06:59:12 +08:00
|
|
|
<< ResType))
|
2009-01-20 03:26:10 +08:00
|
|
|
return QualType();
|
2009-07-17 01:59:14 +08:00
|
|
|
// Diagnose bad cases where we step over interface counts.
|
|
|
|
else if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) {
|
|
|
|
Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
|
|
|
|
<< PointeeTy << Op->getSourceRange();
|
|
|
|
return QualType();
|
|
|
|
}
|
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:
|
2008-04-02 12:24:33 +08:00
|
|
|
return cast<DeclRefExpr>(E)->getDecl();
|
2007-04-20 07:00:49 +08:00
|
|
|
case Stmt::MemberExprClass:
|
2009-04-20 16:23:18 +08:00
|
|
|
// If this is an arrow operator, the address is an offset from
|
|
|
|
// the base's value, so the object the base refers to is
|
|
|
|
// irrelevant.
|
2008-04-02 12:24:33 +08:00
|
|
|
if (cast<MemberExpr>(E)->isArrow())
|
2007-11-17 01:46:48 +08:00
|
|
|
return 0;
|
2009-04-20 16:23:18 +08:00
|
|
|
// Otherwise, the expression refers to a part of the base
|
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: {
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: This code shouldn't be necessary! We should catch the implicit
|
|
|
|
// promotion of register arrays earlier.
|
2009-04-20 16:23:18 +08:00
|
|
|
Expr* Base = cast<ArraySubscriptExpr>(E)->getBase();
|
|
|
|
if (ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(Base)) {
|
|
|
|
if (ICE->getSubExpr()->getType()->isArrayType())
|
|
|
|
return getPrimaryDecl(ICE->getSubExpr());
|
|
|
|
}
|
|
|
|
return 0;
|
2008-02-01 15:15:58 +08:00
|
|
|
}
|
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::Real:
|
|
|
|
case UnaryOperator::Imag:
|
|
|
|
case UnaryOperator::Extension:
|
|
|
|
return getPrimaryDecl(UO->getSubExpr());
|
|
|
|
default:
|
|
|
|
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:
|
2009-04-20 16:23:18 +08:00
|
|
|
// If the result of an implicit cast is an l-value, we care about
|
|
|
|
// the sub-expression; otherwise, the result here doesn't matter.
|
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) {
|
2009-04-20 16:23:18 +08:00
|
|
|
// Make sure to ignore parentheses in subsequent checks
|
|
|
|
op = op->IgnoreParens();
|
|
|
|
|
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
|
|
|
|
2009-05-17 07:27:50 +08:00
|
|
|
if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
|
|
|
|
// C99 6.5.3.2p1
|
2009-04-20 16:23:18 +08:00
|
|
|
// The operand must be either an l-value or a function designator
|
2009-05-17 07:27:50 +08:00
|
|
|
if (!op->getType()->isFunctionType()) {
|
2007-11-17 01:46:48 +08:00
|
|
|
// 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();
|
|
|
|
}
|
2009-05-02 10:18:30 +08:00
|
|
|
} else if (op->getBitField()) { // C99 6.5.3.2p1
|
2009-04-20 16:23:18 +08:00
|
|
|
// The operand cannot be a bit-field
|
|
|
|
Diag(OpLoc, diag::err_typecheck_address_of)
|
|
|
|
<< "bit-field" << op->getSourceRange();
|
2008-12-21 07:49:58 +08:00
|
|
|
return QualType();
|
2009-02-16 06:45:20 +08:00
|
|
|
} else if (isa<ExtVectorElementExpr>(op) || (isa<ArraySubscriptExpr>(op) &&
|
|
|
|
cast<ArraySubscriptExpr>(op)->getBase()->getType()->isVectorType())){
|
2009-04-20 16:23:18 +08:00
|
|
|
// The operand cannot be an element of a vector
|
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();
|
2009-07-08 02:50:52 +08:00
|
|
|
} else if (isa<ObjCPropertyRefExpr>(op)) {
|
|
|
|
// cannot take address of a property expression.
|
|
|
|
Diag(OpLoc, diag::err_typecheck_address_of)
|
|
|
|
<< "property expression" << op->getSourceRange();
|
|
|
|
return QualType();
|
2009-09-15 07:15:26 +08:00
|
|
|
} else if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(op)) {
|
|
|
|
// FIXME: Can LHS ever be null here?
|
2009-09-16 00:03:44 +08:00
|
|
|
if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull())
|
|
|
|
return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc);
|
2008-03-01 07:30:25 +08:00
|
|
|
} 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();
|
|
|
|
}
|
2009-07-09 04:55:45 +08:00
|
|
|
} else if (isa<OverloadedFunctionDecl>(dcl) ||
|
|
|
|
isa<FunctionTemplateDecl>(dcl)) {
|
2008-11-11 04:40:00 +08:00
|
|
|
return Context.OverloadTy;
|
2009-07-09 05:45:58 +08:00
|
|
|
} else if (FieldDecl *FD = dyn_cast<FieldDecl>(dcl)) {
|
2008-12-11 05:26:49 +08:00
|
|
|
// 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.
|
2009-10-24 02:54:35 +08:00
|
|
|
if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier()) {
|
2009-02-04 04:19:35 +08:00
|
|
|
DeclContext *Ctx = dcl->getDeclContext();
|
2009-07-09 05:45:58 +08:00
|
|
|
if (Ctx && Ctx->isRecord()) {
|
|
|
|
if (FD->getType()->isReferenceType()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(OpLoc,
|
2009-07-09 05:45:58 +08:00
|
|
|
diag::err_cannot_form_pointer_to_member_of_reference_type)
|
|
|
|
<< FD->getDeclName() << FD->getType();
|
|
|
|
return QualType();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-04 04:19:35 +08:00
|
|
|
return Context.getMemberPointerType(op->getType(),
|
|
|
|
Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
|
2009-07-09 05:45:58 +08:00
|
|
|
}
|
2009-02-04 04:19:35 +08:00
|
|
|
}
|
2009-05-17 05:43:42 +08:00
|
|
|
} else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) {
|
2008-12-17 06:58:26 +08:00
|
|
|
// Okay: we can take the address of a function.
|
2009-02-05 05:23:32 +08:00
|
|
|
// As above.
|
2009-10-24 02:54:35 +08:00
|
|
|
if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier() &&
|
|
|
|
MD->isInstance())
|
2009-05-17 05:43:42 +08:00
|
|
|
return Context.getMemberPointerType(op->getType(),
|
|
|
|
Context.getTypeDeclType(MD->getParent()).getTypePtr());
|
|
|
|
} else if (!isa<FunctionDecl>(dcl))
|
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
|
|
|
|
2009-05-17 07:27:50 +08:00
|
|
|
if (lval == Expr::LV_IncompleteVoidType) {
|
|
|
|
// Taking the address of a void variable is technically illegal, but we
|
|
|
|
// allow it in cases which are otherwise valid.
|
|
|
|
// Example: "extern void x; void* y = &x;".
|
|
|
|
Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange();
|
|
|
|
}
|
|
|
|
|
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.
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const PointerType *PT = Ty->getAs<PointerType>())
|
2008-01-14 01:10:08 +08:00
|
|
|
return PT->getPointeeType();
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const ObjCObjectPointerType *OPT = Ty->getAs<ObjCObjectPointerType>())
|
2009-09-03 08:43:07 +08:00
|
|
|
return OPT->getPointeeType();
|
2009-07-11 07:34:53 +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) {
|
2009-03-28 09:22:36 +08:00
|
|
|
QualType ResultTy; // Result type of the binary operator.
|
2008-11-07 07:29:22 +08:00
|
|
|
BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)Op;
|
2009-03-28 09:22:36 +08:00
|
|
|
// The following two variables are used for compound assignment operators
|
|
|
|
QualType CompLHSTy; // Type of LHS after promotions for computation
|
|
|
|
QualType CompResultTy; // Type of computation result
|
2008-11-07 07:29:22 +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
|
|
|
switch (Opc) {
|
|
|
|
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:
|
2009-04-07 02:45:53 +08:00
|
|
|
ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, 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:
|
2009-04-07 02:45:53 +08:00
|
|
|
ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, 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:
|
2009-03-28 09:22:36 +08:00
|
|
|
CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true);
|
|
|
|
CompLHSTy = CompResultTy;
|
|
|
|
if (!CompResultTy.isNull())
|
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
|
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:
|
2009-03-28 09:22:36 +08:00
|
|
|
CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true);
|
|
|
|
CompLHSTy = CompResultTy;
|
|
|
|
if (!CompResultTy.isNull())
|
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
|
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:
|
2009-03-28 09:22:36 +08:00
|
|
|
CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy);
|
|
|
|
if (!CompResultTy.isNull())
|
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
|
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:
|
2009-03-28 09:22:36 +08:00
|
|
|
CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy);
|
|
|
|
if (!CompResultTy.isNull())
|
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
|
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:
|
2009-03-28 09:22:36 +08:00
|
|
|
CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, true);
|
|
|
|
CompLHSTy = CompResultTy;
|
|
|
|
if (!CompResultTy.isNull())
|
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
|
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:
|
2009-03-28 09:22:36 +08:00
|
|
|
CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true);
|
|
|
|
CompLHSTy = CompResultTy;
|
|
|
|
if (!CompResultTy.isNull())
|
|
|
|
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
|
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-03-28 09:22:36 +08:00
|
|
|
if (CompResultTy.isNull())
|
2009-01-21 08:14:39 +08:00
|
|
|
return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, OpLoc));
|
|
|
|
else
|
|
|
|
return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy,
|
2009-03-28 09:22:36 +08:00
|
|
|
CompLHSTy, CompResultTy,
|
|
|
|
OpLoc));
|
2008-11-07 07:29:22 +08:00
|
|
|
}
|
|
|
|
|
2009-10-27 20:10:02 +08:00
|
|
|
/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps
|
|
|
|
/// ParenRange in parentheses.
|
2009-10-27 01:01:32 +08:00
|
|
|
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
|
|
|
|
const PartialDiagnostic &PD,
|
|
|
|
SourceRange ParenRange)
|
|
|
|
{
|
|
|
|
SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
|
|
|
|
if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
|
|
|
|
// We can't display the parentheses, so just dig the
|
|
|
|
// warning/error and return.
|
|
|
|
Self.Diag(Loc, PD);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Self.Diag(Loc, PD)
|
|
|
|
<< CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
|
|
|
|
<< CodeModificationHint::CreateInsertion(EndLoc, ")");
|
|
|
|
}
|
|
|
|
|
2009-10-27 20:10:02 +08:00
|
|
|
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
|
|
|
|
/// operators are mixed in a way that suggests that the programmer forgot that
|
|
|
|
/// comparison operators have higher precedence. The most typical example of
|
|
|
|
/// such code is "flags & 0x0020 != 0", which is equivalent to "flags & 1".
|
2009-10-26 23:24:15 +08:00
|
|
|
static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc,
|
|
|
|
SourceLocation OpLoc,Expr *lhs,Expr *rhs){
|
2009-10-27 20:10:02 +08:00
|
|
|
typedef BinaryOperator BinOp;
|
|
|
|
BinOp::Opcode lhsopc = static_cast<BinOp::Opcode>(-1),
|
|
|
|
rhsopc = static_cast<BinOp::Opcode>(-1);
|
|
|
|
if (BinOp *BO = dyn_cast<BinOp>(lhs))
|
2009-10-26 23:24:15 +08:00
|
|
|
lhsopc = BO->getOpcode();
|
2009-10-27 20:10:02 +08:00
|
|
|
if (BinOp *BO = dyn_cast<BinOp>(rhs))
|
2009-10-26 23:24:15 +08:00
|
|
|
rhsopc = BO->getOpcode();
|
|
|
|
|
|
|
|
// Subs are not binary operators.
|
|
|
|
if (lhsopc == -1 && rhsopc == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Bitwise operations are sometimes used as eager logical ops.
|
|
|
|
// Don't diagnose this.
|
2009-10-27 20:10:02 +08:00
|
|
|
if ((BinOp::isComparisonOp(lhsopc) || BinOp::isBitwiseOp(lhsopc)) &&
|
|
|
|
(BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc)))
|
2009-10-26 23:24:15 +08:00
|
|
|
return;
|
|
|
|
|
2009-10-27 20:10:02 +08:00
|
|
|
if (BinOp::isComparisonOp(lhsopc))
|
2009-10-27 01:01:32 +08:00
|
|
|
SuggestParentheses(Self, OpLoc,
|
|
|
|
PDiag(diag::warn_precedence_bitwise_rel)
|
2009-10-27 20:10:02 +08:00
|
|
|
<< SourceRange(lhs->getLocStart(), OpLoc)
|
|
|
|
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
|
|
|
|
SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
|
|
|
|
else if (BinOp::isComparisonOp(rhsopc))
|
2009-10-27 01:01:32 +08:00
|
|
|
SuggestParentheses(Self, OpLoc,
|
|
|
|
PDiag(diag::warn_precedence_bitwise_rel)
|
2009-10-27 20:10:02 +08:00
|
|
|
<< SourceRange(OpLoc, rhs->getLocEnd())
|
|
|
|
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
|
|
|
|
SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
|
2009-10-26 23:24:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
|
|
|
|
/// precedence. This currently diagnoses only "arg1 'bitwise' arg2 'eq' arg3".
|
|
|
|
/// But it could also warn about arg1 && arg2 || arg3, as GCC 4.3+ does.
|
|
|
|
static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperator::Opcode Opc,
|
|
|
|
SourceLocation OpLoc, Expr *lhs, Expr *rhs){
|
2009-10-27 20:10:02 +08:00
|
|
|
if (BinaryOperator::isBitwiseOp(Opc))
|
2009-10-26 23:24:15 +08:00
|
|
|
DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs);
|
|
|
|
}
|
|
|
|
|
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-05-02 03:49:17 +08:00
|
|
|
Expr *lhs = LHS.takeAs<Expr>(), *rhs = RHS.takeAs<Expr>();
|
2008-11-07 07:29:22 +08:00
|
|
|
|
|
|
|
assert((lhs != 0) && "ActOnBinOp(): missing left expression");
|
|
|
|
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
|
|
|
|
|
2009-10-26 23:24:15 +08:00
|
|
|
// Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0"
|
|
|
|
DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs);
|
|
|
|
|
2009-11-05 08:51:44 +08:00
|
|
|
return BuildBinOp(S, TokLoc, Opc, lhs, rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
|
|
|
|
BinaryOperator::Opcode Opc,
|
|
|
|
Expr *lhs, Expr *rhs) {
|
2009-03-14 02:40:31 +08:00
|
|
|
if (getLangOptions().CPlusPlus &&
|
2009-09-09 23:08:12 +08:00
|
|
|
(lhs->getType()->isOverloadableType() ||
|
2009-03-14 02:40:31 +08:00
|
|
|
rhs->getType()->isOverloadableType())) {
|
|
|
|
// Find all of the overloaded operators visible from this
|
|
|
|
// point. We perform both an operator-name lookup from the local
|
|
|
|
// scope and an argument-dependent lookup based on the types of
|
|
|
|
// the arguments.
|
2009-03-13 08:33:25 +08:00
|
|
|
FunctionSet Functions;
|
2009-03-14 02:40:31 +08:00
|
|
|
OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
|
|
|
|
if (OverOp != OO_None) {
|
2009-11-05 08:51:44 +08:00
|
|
|
if (S)
|
|
|
|
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
|
|
|
|
Functions);
|
2009-03-14 02:40:31 +08:00
|
|
|
Expr *Args[2] = { lhs, rhs };
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclarationName OpName
|
2009-03-14 02:40:31 +08:00
|
|
|
= Context.DeclarationNames.getCXXOperatorName(OverOp);
|
2009-10-24 03:23:15 +08:00
|
|
|
ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions);
|
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
|
|
|
}
|
2009-11-05 08:51:44 +08:00
|
|
|
|
2009-03-14 02:40:31 +08:00
|
|
|
// Build the (potentially-overloaded, potentially-dependent)
|
|
|
|
// binary operation.
|
2009-11-05 08:51:44 +08:00
|
|
|
return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs);
|
2009-01-20 06:31:54 +08:00
|
|
|
}
|
2009-11-05 08:51:44 +08:00
|
|
|
|
2008-11-07 07:29:22 +08:00
|
|
|
// Build a built-in binary operation.
|
2009-11-05 08:51:44 +08:00
|
|
|
return CreateBuiltinBinOp(OpLoc, 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
|
|
|
}
|
|
|
|
|
2009-03-14 07:49:33 +08:00
|
|
|
Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned OpcIn,
|
2009-03-14 07:49:33 +08:00
|
|
|
ExprArg InputArg) {
|
|
|
|
UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
|
|
|
|
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: Input is modified below, but InputArg is not updated appropriately.
|
2009-03-14 07:49:33 +08:00
|
|
|
Expr *Input = (Expr *)InputArg.get();
|
2007-05-07 08:24:15 +08:00
|
|
|
QualType resultType;
|
|
|
|
switch (Opc) {
|
2009-03-14 07:49:33 +08:00
|
|
|
case UnaryOperator::OffsetOf:
|
|
|
|
assert(false && "Invalid unary operator");
|
|
|
|
break;
|
|
|
|
|
2007-05-07 08:24:15 +08:00
|
|
|
case UnaryOperator::PreInc:
|
|
|
|
case UnaryOperator::PreDec:
|
2009-07-23 06:25:00 +08:00
|
|
|
case UnaryOperator::PostInc:
|
|
|
|
case UnaryOperator::PostDec:
|
2008-12-20 17:35:34 +08:00
|
|
|
resultType = CheckIncrementDecrementOperand(Input, OpLoc,
|
2009-07-23 06:25:00 +08:00
|
|
|
Opc == UnaryOperator::PreInc ||
|
|
|
|
Opc == UnaryOperator::PostInc);
|
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();
|
2009-03-14 07:49:33 +08:00
|
|
|
|
|
|
|
InputArg.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
|
|
|
|
2009-11-05 08:51:44 +08:00
|
|
|
Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
|
|
|
|
UnaryOperator::Opcode Opc,
|
|
|
|
ExprArg input) {
|
2009-03-14 07:49:33 +08:00
|
|
|
Expr *Input = (Expr*)input.get();
|
2009-11-15 05:26:41 +08:00
|
|
|
if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() &&
|
|
|
|
Opc != UnaryOperator::Extension) {
|
2009-03-14 07:49:33 +08:00
|
|
|
// Find all of the overloaded operators visible from this
|
|
|
|
// point. We perform both an operator-name lookup from the local
|
|
|
|
// scope and an argument-dependent lookup based on the types of
|
|
|
|
// the arguments.
|
|
|
|
FunctionSet Functions;
|
|
|
|
OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc);
|
|
|
|
if (OverOp != OO_None) {
|
2009-11-05 08:51:44 +08:00
|
|
|
if (S)
|
|
|
|
LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
|
|
|
|
Functions);
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclarationName OpName
|
2009-03-14 07:49:33 +08:00
|
|
|
= Context.DeclarationNames.getCXXOperatorName(OverOp);
|
2009-10-24 03:23:15 +08:00
|
|
|
ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions);
|
2009-03-14 07:49:33 +08:00
|
|
|
}
|
2009-11-05 08:51:44 +08:00
|
|
|
|
2009-03-14 07:49:33 +08:00
|
|
|
return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
|
|
|
|
}
|
2009-11-05 08:51:44 +08:00
|
|
|
|
2009-03-14 07:49:33 +08:00
|
|
|
return CreateBuiltinUnaryOp(OpLoc, Opc, move(input));
|
|
|
|
}
|
|
|
|
|
2009-11-05 08:51:44 +08:00
|
|
|
// Unary Operators. 'Tok' is the token for the operator.
|
|
|
|
Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
|
|
|
|
tok::TokenKind Op, ExprArg input) {
|
|
|
|
return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), move(input));
|
|
|
|
}
|
|
|
|
|
2007-09-16 22:56:35 +08:00
|
|
|
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
|
2009-03-16 01:47:39 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
|
|
|
|
SourceLocation LabLoc,
|
|
|
|
IdentifierInfo *LabelII) {
|
2007-05-28 14:56:27 +08:00
|
|
|
// Look up the record for this label identifier.
|
2009-04-19 04:01:55 +08:00
|
|
|
LabelStmt *&LabelDecl = getLabelMap()[LabelII];
|
2009-02-19 11:04:26 +08:00
|
|
|
|
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-13 23:38:40 +08:00
|
|
|
if (LabelDecl == 0)
|
2009-01-21 08:14:39 +08:00
|
|
|
LabelDecl = new (Context) LabelStmt(LabLoc, LabelII, 0);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2007-05-28 14:56:27 +08:00
|
|
|
// Create the AST node. The address of a label always has type 'void*'.
|
2009-03-16 01:47:39 +08:00
|
|
|
return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, LabelDecl,
|
|
|
|
Context.getPointerType(Context.VoidTy)));
|
2007-05-28 14:56:27 +08:00
|
|
|
}
|
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
Sema::OwningExprResult
|
|
|
|
Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt,
|
|
|
|
SourceLocation RPLoc) { // "({..})"
|
|
|
|
Stmt *SubStmt = static_cast<Stmt*>(substmt.get());
|
2007-07-25 00:58:17 +08:00
|
|
|
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;
|
2009-04-26 03:11:05 +08:00
|
|
|
if (isFileScope)
|
2009-03-16 01:47:39 +08:00
|
|
|
return ExprError(Diag(LPLoc, diag::err_stmtexpr_file_scope));
|
2009-01-25 07:09:00 +08:00
|
|
|
|
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
|
|
|
// 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-03-23 08:24:07 +08:00
|
|
|
// FIXME: Check that expression type is complete/non-abstract; statement
|
|
|
|
// expressions are not lvalues.
|
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
substmt.release();
|
|
|
|
return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc));
|
2007-07-25 00:58:17 +08:00
|
|
|
}
|
2007-08-02 06:05:33 +08:00
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
|
|
|
|
SourceLocation BuiltinLoc,
|
|
|
|
SourceLocation TypeLoc,
|
|
|
|
TypeTy *argty,
|
|
|
|
OffsetOfComponent *CompPtr,
|
|
|
|
unsigned NumComponents,
|
|
|
|
SourceLocation RPLoc) {
|
|
|
|
// FIXME: This function leaks all expressions in the offset components on
|
|
|
|
// error.
|
2009-08-19 09:28:28 +08:00
|
|
|
// FIXME: Preserve type source info.
|
|
|
|
QualType ArgTy = GetTypeFromParser(argty);
|
2007-08-31 01:45:32 +08:00
|
|
|
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())
|
2009-03-16 01:47:39 +08:00
|
|
|
return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-23 08:24:07 +08:00
|
|
|
// FIXME: Type must be complete per C99 7.17p3 because a declaring a variable
|
|
|
|
// with an incomplete type would be illegal.
|
2009-03-12 00:48:53 +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);
|
2009-03-16 01:47:39 +08:00
|
|
|
Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref,
|
2009-02-27 14:44:11 +08:00
|
|
|
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) {
|
2009-05-04 05:22:18 +08:00
|
|
|
bool DidWarnAboutNonPOD = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-04 11:03:43 +08:00
|
|
|
if (RequireCompleteType(TypeLoc, Res->getType(),
|
|
|
|
diag::err_offsetof_incomplete_type))
|
|
|
|
return ExprError();
|
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
// 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);
|
2009-03-16 01:47:39 +08:00
|
|
|
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
|
|
|
|
<< Res->getType());
|
2009-02-26 22:39:58 +08:00
|
|
|
}
|
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);
|
2009-03-16 01:47:39 +08:00
|
|
|
// FIXME: Leaks Res
|
2009-02-26 22:39:58 +08:00
|
|
|
if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType())
|
2009-03-16 01:47:39 +08:00
|
|
|
return ExprError(Diag(Idx->getLocStart(),
|
2009-04-26 06:50:55 +08:00
|
|
|
diag::err_typecheck_subscript_not_integer)
|
2009-03-16 01:47:39 +08:00
|
|
|
<< 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-07-30 05:53:49 +08:00
|
|
|
const RecordType *RC = Res->getType()->getAs<RecordType>();
|
2009-02-26 22:39:58 +08:00
|
|
|
if (!RC) {
|
|
|
|
Res->Destroy(Context);
|
2009-03-16 01:47:39 +08:00
|
|
|
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
|
|
|
|
<< Res->getType());
|
2009-02-26 22:39:58 +08:00
|
|
|
}
|
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();
|
2009-05-02 07:20:30 +08:00
|
|
|
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
|
2009-05-03 02:36:10 +08:00
|
|
|
if (!CRD->isPOD() && !DidWarnAboutNonPOD) {
|
2009-05-03 01:45:47 +08:00
|
|
|
ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type)
|
|
|
|
<< SourceRange(CompPtr[0].LocStart, OC.LocEnd)
|
|
|
|
<< Res->getType());
|
2009-05-03 02:36:10 +08:00
|
|
|
DidWarnAboutNonPOD = true;
|
|
|
|
}
|
2009-05-02 07:20:30 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-17 10:14:36 +08:00
|
|
|
LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
|
|
|
|
LookupQualifiedName(R, RD);
|
2009-10-10 05:13:30 +08:00
|
|
|
|
2009-02-26 22:39:58 +08:00
|
|
|
FieldDecl *MemberDecl
|
2009-10-10 05:13:30 +08:00
|
|
|
= dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context));
|
2009-03-16 01:47:39 +08:00
|
|
|
// FIXME: Leaks Res
|
2009-02-26 22:39:58 +08:00
|
|
|
if (!MemberDecl)
|
2009-10-14 05:16:44 +08:00
|
|
|
return ExprError(Diag(BuiltinLoc, diag::err_no_member)
|
|
|
|
<< OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
|
2009-02-26 22:39:58 +08:00
|
|
|
|
|
|
|
// FIXME: C++: Verify that MemberDecl isn't a static field.
|
|
|
|
// FIXME: Verify that MemberDecl isn't a bitfield.
|
2009-04-27 04:50:44 +08:00
|
|
|
if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) {
|
2009-05-02 03:30:39 +08:00
|
|
|
Res = BuildAnonymousStructUnionMemberReference(
|
2009-11-11 11:23:23 +08:00
|
|
|
OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
|
2009-04-27 04:50:44 +08:00
|
|
|
} else {
|
|
|
|
// MemberDecl->getType() doesn't get the right qualifiers, but it
|
|
|
|
// doesn't matter here.
|
|
|
|
Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
|
|
|
|
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
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf,
|
|
|
|
Context.getSizeType(), BuiltinLoc));
|
2007-08-31 01:45:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
|
|
|
|
TypeTy *arg1,TypeTy *arg2,
|
|
|
|
SourceLocation RPLoc) {
|
2009-08-19 09:28:28 +08:00
|
|
|
// FIXME: Preserve type source info.
|
|
|
|
QualType argT1 = GetTypeFromParser(arg1);
|
|
|
|
QualType argT2 = GetTypeFromParser(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
|
|
|
|
2009-05-20 06:28:02 +08:00
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
Diag(BuiltinLoc, diag::err_types_compatible_p_in_cplusplus)
|
|
|
|
<< SourceRange(BuiltinLoc, RPLoc);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
return Owned(new (Context) TypesCompatibleExpr(Context.IntTy, BuiltinLoc,
|
|
|
|
argT1, argT2, RPLoc));
|
2007-08-02 06:05:33 +08:00
|
|
|
}
|
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
|
|
|
|
ExprArg cond,
|
|
|
|
ExprArg expr1, ExprArg expr2,
|
|
|
|
SourceLocation RPLoc) {
|
|
|
|
Expr *CondExpr = static_cast<Expr*>(cond.get());
|
|
|
|
Expr *LHSExpr = static_cast<Expr*>(expr1.get());
|
|
|
|
Expr *RHSExpr = static_cast<Expr*>(expr2.get());
|
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;
|
2009-09-25 12:25:58 +08:00
|
|
|
bool ValueDependent = false;
|
2009-05-20 06:43:30 +08:00
|
|
|
if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
|
2009-02-26 22:39:58 +08:00
|
|
|
resType = Context.DependentTy;
|
2009-09-25 12:25:58 +08:00
|
|
|
ValueDependent = true;
|
2009-02-26 22:39:58 +08:00
|
|
|
} else {
|
|
|
|
// The conditional expression is required to be a constant expression.
|
|
|
|
llvm::APSInt condEval(32);
|
|
|
|
SourceLocation ExpLoc;
|
|
|
|
if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc))
|
2009-03-16 01:47:39 +08:00
|
|
|
return ExprError(Diag(ExpLoc,
|
|
|
|
diag::err_typecheck_choose_expr_requires_constant)
|
|
|
|
<< CondExpr->getSourceRange());
|
2009-02-26 22:39:58 +08:00
|
|
|
|
|
|
|
// If the condition is > zero, then the AST type is the same as the LSHExpr.
|
|
|
|
resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType();
|
2009-09-25 12:25:58 +08:00
|
|
|
ValueDependent = condEval.getZExtValue() ? LHSExpr->isValueDependent()
|
|
|
|
: RHSExpr->isValueDependent();
|
2009-02-26 22:39:58 +08:00
|
|
|
}
|
2007-08-04 05:21:27 +08:00
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
cond.release(); expr1.release(); expr2.release();
|
|
|
|
return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
|
2009-09-25 12:25:58 +08:00
|
|
|
resType, RPLoc,
|
|
|
|
resType->isDependentType(),
|
|
|
|
ValueDependent));
|
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-02-19 11:04:26 +08:00
|
|
|
|
2009-06-20 07:37:08 +08:00
|
|
|
BSI->ReturnType = QualType();
|
2008-09-04 02:15:37 +08:00
|
|
|
BSI->TheScope = BlockScope;
|
2009-02-20 06:01:56 +08:00
|
|
|
BSI->hasBlockDeclRefExprs = false;
|
2009-07-29 09:59:17 +08:00
|
|
|
BSI->hasPrototype = false;
|
2009-04-19 13:28:12 +08:00
|
|
|
BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
|
|
|
|
CurFunctionNeedsScopeChecking = 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) {
|
2009-05-08 02:43:07 +08:00
|
|
|
assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
|
2009-02-05 06:31:32 +08:00
|
|
|
|
|
|
|
if (ParamInfo.getNumTypeObjects() == 0
|
|
|
|
|| ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
|
2009-06-18 05:51:59 +08:00
|
|
|
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
|
2009-02-05 06:31:32 +08:00
|
|
|
QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
|
|
|
|
|
2009-04-28 09:10:27 +08:00
|
|
|
if (T->isArrayType()) {
|
|
|
|
Diag(ParamInfo.getSourceRange().getBegin(),
|
|
|
|
diag::err_block_returns_array);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
// 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;
|
2009-05-15 04:53:39 +08:00
|
|
|
// Check for a valid sentinel attribute on this block.
|
2009-06-30 10:34:44 +08:00
|
|
|
if (CurBlock->TheDecl->getAttr<SentinelAttr>()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(ParamInfo.getAttributes()->getLoc(),
|
2009-05-16 05:18:04 +08:00
|
|
|
diag::warn_attribute_sentinel_not_variadic) << 1;
|
2009-05-15 04:53:39 +08:00
|
|
|
// FIXME: remove the attribute.
|
|
|
|
}
|
2009-09-22 07:43:11 +08:00
|
|
|
QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 03:27:54 +08:00
|
|
|
// Do not allow returning a objc interface by-value.
|
|
|
|
if (RetTy->isObjCInterfaceType()) {
|
|
|
|
Diag(ParamInfo.getSourceRange().getBegin(),
|
|
|
|
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
|
|
|
|
return;
|
|
|
|
}
|
2009-02-05 06:31:32 +08:00
|
|
|
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 &&
|
2009-03-29 03:18:32 +08:00
|
|
|
(!FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType().getCVRQualifiers()&&
|
|
|
|
FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType()->isVoidType())) {
|
2008-09-04 02:15:37 +08:00
|
|
|
// 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)
|
2009-03-29 03:18:32 +08:00
|
|
|
CurBlock->Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>());
|
2008-10-10 09:28:17 +08:00
|
|
|
CurBlock->isVariadic = FTI.isVariadic;
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2009-05-21 17:52:38 +08:00
|
|
|
CurBlock->TheDecl->setParams(Context, CurBlock->Params.data(),
|
2009-04-12 03:27:54 +08:00
|
|
|
CurBlock->Params.size());
|
2009-05-20 01:08:59 +08:00
|
|
|
CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
|
2009-06-18 05:51:59 +08:00
|
|
|
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
|
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);
|
2009-04-12 03:27:54 +08:00
|
|
|
|
2009-05-15 04:53:39 +08:00
|
|
|
// Check for a valid sentinel attribute on this block.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!CurBlock->isVariadic &&
|
2009-06-30 10:34:44 +08:00
|
|
|
CurBlock->TheDecl->getAttr<SentinelAttr>()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(ParamInfo.getAttributes()->getLoc(),
|
2009-05-16 05:18:04 +08:00
|
|
|
diag::warn_attribute_sentinel_not_variadic) << 1;
|
2009-05-15 04:53:39 +08:00
|
|
|
// FIXME: remove the attribute.
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 03:27:54 +08:00
|
|
|
// Analyze the return type.
|
|
|
|
QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
|
2009-09-22 07:43:11 +08:00
|
|
|
QualType RetTy = T->getAs<FunctionType>()->getResultType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-12 03:27:54 +08:00
|
|
|
// Do not allow returning a objc interface by-value.
|
|
|
|
if (RetTy->isObjCInterfaceType()) {
|
|
|
|
Diag(ParamInfo.getSourceRange().getBegin(),
|
|
|
|
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
|
|
|
|
} else if (!RetTy->isDependentType())
|
2009-06-20 07:37:08 +08:00
|
|
|
CurBlock->ReturnType = RetTy;
|
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
|
|
|
|
2009-04-19 13:28:12 +08:00
|
|
|
CurFunctionNeedsScopeChecking = CurBlock->SavedFunctionNeedsScopeChecking;
|
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// Pop off CurBlock, handle nested blocks.
|
2009-04-22 06:38:46 +08:00
|
|
|
PopDeclContext();
|
2008-09-04 02:15:37 +08:00
|
|
|
CurBlock = CurBlock->PrevBlockInfo;
|
|
|
|
// FIXME: Delete the ParmVarDecl objects as well???
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ActOnBlockStmtExpr - This is called when the body of a block statement
|
|
|
|
/// literal was successfully completed. ^(int x){...}
|
2009-03-16 01:47:39 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
|
|
|
|
StmtArg body, Scope *CurScope) {
|
2009-03-27 12:18:06 +08:00
|
|
|
// If blocks are disabled, emit an error.
|
|
|
|
if (!LangOpts.Blocks)
|
|
|
|
Diag(CaretLoc, diag::err_blocks_disable);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// Ensure that CurBlock is deleted.
|
|
|
|
llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
|
|
|
|
|
2008-10-10 09:28:17 +08:00
|
|
|
PopDeclContext();
|
|
|
|
|
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;
|
2009-06-20 07:37:08 +08:00
|
|
|
if (!BSI->ReturnType.isNull())
|
|
|
|
RetTy = BSI->ReturnType;
|
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
|
|
|
|
2009-07-29 06:04:01 +08:00
|
|
|
bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>();
|
2008-09-04 02:15:37 +08:00
|
|
|
QualType BlockTy;
|
|
|
|
if (!BSI->hasPrototype)
|
2009-07-29 06:04:01 +08:00
|
|
|
BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
|
|
|
|
NoReturn);
|
2008-09-04 02:15:37 +08:00
|
|
|
else
|
2009-05-21 17:52:38 +08:00
|
|
|
BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
|
2009-07-29 06:04:01 +08:00
|
|
|
BSI->isVariadic, 0, false, false, 0, 0,
|
|
|
|
NoReturn);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-23 08:24:07 +08:00
|
|
|
// FIXME: Check that return/parameter types are complete/non-abstract
|
2009-06-20 07:52:42 +08:00
|
|
|
DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
|
2008-09-04 02:15:37 +08:00
|
|
|
BlockTy = Context.getBlockPointerType(BlockTy);
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-04-19 13:28:12 +08:00
|
|
|
// If needed, diagnose invalid gotos and switches in the block.
|
|
|
|
if (CurFunctionNeedsScopeChecking)
|
|
|
|
DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get()));
|
|
|
|
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-02 03:49:17 +08:00
|
|
|
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
|
2009-07-29 06:04:01 +08:00
|
|
|
CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody());
|
2009-03-16 01:47:39 +08:00
|
|
|
return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
|
|
|
|
BSI->hasBlockDeclRefExprs));
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
|
|
|
|
ExprArg expr, TypeTy *type,
|
|
|
|
SourceLocation RPLoc) {
|
2009-08-19 09:28:28 +08:00
|
|
|
QualType T = GetTypeFromParser(type);
|
2009-04-05 23:49:53 +08:00
|
|
|
Expr *E = static_cast<Expr*>(expr.get());
|
|
|
|
Expr *OrigExpr = E;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-16 04:28:48 +08:00
|
|
|
InitBuiltinVaListType();
|
2008-08-10 07:32:40 +08:00
|
|
|
|
|
|
|
// Get the va_list type
|
|
|
|
QualType VaListType = Context.getBuiltinVaListType();
|
2009-05-16 20:46:54 +08:00
|
|
|
if (VaListType->isArrayType()) {
|
|
|
|
// 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.
|
2008-08-10 07:32:40 +08:00
|
|
|
VaListType = Context.getArrayDecayedType(VaListType);
|
2009-05-16 20:46:54 +08:00
|
|
|
// Make sure the input expression also decays appropriately.
|
|
|
|
UsualUnaryConversions(E);
|
|
|
|
} else {
|
|
|
|
// Otherwise, the va_list argument must be an l-value because
|
|
|
|
// it is modified by va_arg.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!E->isTypeDependent() &&
|
2009-05-20 07:10:31 +08:00
|
|
|
CheckForModifiableLvalue(E, BuiltinLoc, *this))
|
2009-05-16 20:46:54 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2008-08-10 07:32:40 +08:00
|
|
|
|
2009-05-20 07:10:31 +08:00
|
|
|
if (!E->isTypeDependent() &&
|
|
|
|
!Context.hasSameType(VaListType, E->getType())) {
|
2009-03-16 01:47:39 +08:00
|
|
|
return ExprError(Diag(E->getLocStart(),
|
|
|
|
diag::err_first_argument_to_va_arg_not_of_type_va_list)
|
2009-04-05 23:49:53 +08:00
|
|
|
<< OrigExpr->getType() << E->getSourceRange());
|
2009-04-05 08:59:53 +08:00
|
|
|
}
|
2009-02-19 11:04:26 +08:00
|
|
|
|
2009-03-23 08:24:07 +08:00
|
|
|
// FIXME: Check that type is complete/non-abstract
|
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-03-16 01:47:39 +08:00
|
|
|
expr.release();
|
|
|
|
return Owned(new (Context) VAArgExpr(BuiltinLoc, E, T.getNonReferenceType(),
|
|
|
|
RPLoc));
|
2007-10-16 04:28:48 +08:00
|
|
|
}
|
|
|
|
|
2009-03-16 01:47:39 +08:00
|
|
|
Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
|
2008-11-29 12:51:27 +08:00
|
|
|
// 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-03-16 01:47:39 +08:00
|
|
|
return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
|
2008-11-29 12:51:27 +08:00
|
|
|
}
|
|
|
|
|
2009-11-10 12:46:30 +08:00
|
|
|
static void
|
|
|
|
MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
|
|
|
|
QualType DstType,
|
|
|
|
Expr *SrcExpr,
|
|
|
|
CodeModificationHint &Hint) {
|
|
|
|
if (!SemaRef.getLangOptions().ObjC1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>();
|
|
|
|
if (!PT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Check if the destination is of type 'id'.
|
|
|
|
if (!PT->isObjCIdType()) {
|
|
|
|
// Check if the destination is the 'NSString' interface.
|
|
|
|
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
|
|
|
|
if (!ID || !ID->getIdentifier()->isStr("NSString"))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Strip off any parens and casts.
|
|
|
|
StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts());
|
|
|
|
if (!SL || SL->isWide())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@");
|
|
|
|
}
|
|
|
|
|
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;
|
2009-11-10 12:46:30 +08:00
|
|
|
CodeModificationHint Hint;
|
|
|
|
|
2008-01-05 02:04:52 +08:00
|
|
|
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:
|
2009-11-10 12:46:30 +08:00
|
|
|
MakeObjCStringLiteralCodeModificationHint(*this, DstType, SrcExpr, Hint);
|
2008-01-05 02:04:52 +08:00
|
|
|
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
|
|
|
|
break;
|
2009-03-23 07:59:44 +08:00
|
|
|
case IncompatiblePointerSign:
|
|
|
|
DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
|
|
|
|
break;
|
2008-01-05 02:04:52 +08:00
|
|
|
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;
|
2009-11-08 15:46:34 +08:00
|
|
|
case IncompatibleNestedPointerQualifiers:
|
2009-11-10 06:16:37 +08:00
|
|
|
DiagKind = diag::ext_nested_pointer_qualifier_mismatch;
|
2009-11-08 04:20:40 +08:00
|
|
|
break;
|
2008-09-04 23:10:53 +08:00
|
|
|
case IntToBlockPointer:
|
|
|
|
DiagKind = diag::err_int_to_block_pointer;
|
|
|
|
break;
|
|
|
|
case IncompatibleBlockPointer:
|
2009-04-22 06:51:42 +08:00
|
|
|
DiagKind = diag::err_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
|
2009-11-10 12:46:30 +08:00
|
|
|
<< SrcExpr->getSourceRange() << Hint;
|
2008-01-05 02:04:52 +08:00
|
|
|
return isInvalid;
|
|
|
|
}
|
2008-12-01 03:50:32 +08:00
|
|
|
|
2009-04-26 05:59:05 +08:00
|
|
|
bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
|
2009-04-26 06:26:58 +08:00
|
|
|
llvm::APSInt ICEResult;
|
|
|
|
if (E->isIntegerConstantExpr(ICEResult, Context)) {
|
|
|
|
if (Result)
|
|
|
|
*Result = ICEResult;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-12-01 03:50:32 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-04-26 06:26:58 +08:00
|
|
|
Diag(E->getExprLoc(), diag::ext_expr_not_ice) <<
|
|
|
|
E->getSourceRange();
|
2008-12-01 03:50:32 +08:00
|
|
|
|
2009-04-26 06:26:58 +08:00
|
|
|
if (EvalResult.Diag &&
|
|
|
|
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;
|
|
|
|
}
|
2009-06-20 07:52:42 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
Sema::ExpressionEvaluationContext
|
|
|
|
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
|
2009-06-23 04:57:11 +08:00
|
|
|
// Introduce a new set of potentially referenced declarations to the stack.
|
|
|
|
if (NewContext == PotentiallyPotentiallyEvaluated)
|
|
|
|
PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-23 04:57:11 +08:00
|
|
|
std::swap(ExprEvalContext, NewContext);
|
|
|
|
return NewContext;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
void
|
2009-06-23 04:57:11 +08:00
|
|
|
Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
|
|
|
|
ExpressionEvaluationContext NewContext) {
|
|
|
|
ExprEvalContext = NewContext;
|
|
|
|
|
|
|
|
if (OldContext == PotentiallyPotentiallyEvaluated) {
|
|
|
|
// Mark any remaining declarations in the current position of the stack
|
|
|
|
// as "referenced". If they were not meant to be referenced, semantic
|
|
|
|
// analysis would have eliminated them (e.g., in ActOnCXXTypeId).
|
|
|
|
PotentiallyReferencedDecls RemainingDecls;
|
|
|
|
RemainingDecls.swap(PotentiallyReferencedDeclStack.back());
|
|
|
|
PotentiallyReferencedDeclStack.pop_back();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-23 04:57:11 +08:00
|
|
|
for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(),
|
|
|
|
IEnd = RemainingDecls.end();
|
|
|
|
I != IEnd; ++I)
|
|
|
|
MarkDeclarationReferenced(I->first, I->second);
|
|
|
|
}
|
|
|
|
}
|
2009-06-20 07:52:42 +08:00
|
|
|
|
|
|
|
/// \brief Note that the given declaration was referenced in the source code.
|
|
|
|
///
|
|
|
|
/// This routine should be invoke whenever a given declaration is referenced
|
|
|
|
/// in the source code, and where that reference occurred. If this declaration
|
|
|
|
/// reference means that the the declaration is used (C++ [basic.def.odr]p2,
|
|
|
|
/// C99 6.9p3), then the declaration will be marked as used.
|
|
|
|
///
|
|
|
|
/// \param Loc the location where the declaration was referenced.
|
|
|
|
///
|
|
|
|
/// \param D the declaration that has been referenced by the source code.
|
|
|
|
void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
|
|
|
|
assert(D && "No declaration?");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-23 07:06:13 +08:00
|
|
|
if (D->isUsed())
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-09 05:35:42 +08:00
|
|
|
// Mark a parameter or variable declaration "used", regardless of whether we're in a
|
|
|
|
// template or not. The reason for this is that unevaluated expressions
|
|
|
|
// (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and
|
|
|
|
// -Wunused-parameters)
|
|
|
|
if (isa<ParmVarDecl>(D) ||
|
|
|
|
(isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod()))
|
2009-06-20 07:52:42 +08:00
|
|
|
D->setUsed(true);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
// Do not mark anything as "used" within a dependent context; wait for
|
|
|
|
// an instantiation.
|
|
|
|
if (CurContext->isDependentContext())
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-23 04:57:11 +08:00
|
|
|
switch (ExprEvalContext) {
|
|
|
|
case Unevaluated:
|
|
|
|
// We are in an expression that is not potentially evaluated; do nothing.
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-23 04:57:11 +08:00
|
|
|
case PotentiallyEvaluated:
|
|
|
|
// We are in a potentially-evaluated expression, so this declaration is
|
|
|
|
// "used"; handle this below.
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-23 04:57:11 +08:00
|
|
|
case PotentiallyPotentiallyEvaluated:
|
|
|
|
// We are in an expression that may be potentially evaluated; queue this
|
|
|
|
// declaration reference until we know whether the expression is
|
|
|
|
// potentially evaluated.
|
|
|
|
PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D));
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
// Note that this declaration has been used.
|
2009-06-23 01:30:33 +08:00
|
|
|
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
2009-06-23 07:34:40 +08:00
|
|
|
unsigned TypeQuals;
|
2009-06-23 04:37:23 +08:00
|
|
|
if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
|
|
|
|
if (!Constructor->isUsed())
|
|
|
|
DefineImplicitDefaultConstructor(Loc, Constructor);
|
2009-09-09 23:08:12 +08:00
|
|
|
} else if (Constructor->isImplicit() &&
|
2009-08-05 05:02:39 +08:00
|
|
|
Constructor->isCopyConstructor(Context, TypeQuals)) {
|
2009-06-23 07:34:40 +08:00
|
|
|
if (!Constructor->isUsed())
|
|
|
|
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
|
|
|
|
}
|
2009-06-27 07:49:16 +08:00
|
|
|
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
|
|
|
|
if (Destructor->isImplicit() && !Destructor->isUsed())
|
|
|
|
DefineImplicitDestructor(Loc, Destructor);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-26 05:45:19 +08:00
|
|
|
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
|
|
|
|
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
|
|
|
|
MethodDecl->getOverloadedOperator() == OO_Equal) {
|
|
|
|
if (!MethodDecl->isUsed())
|
|
|
|
DefineImplicitOverloadedAssign(Loc, MethodDecl);
|
|
|
|
}
|
|
|
|
}
|
2009-06-25 06:09:44 +08:00
|
|
|
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
// Implicit instantiation of function templates and member functions of
|
2009-06-26 08:10:03 +08:00
|
|
|
// class templates.
|
2009-10-28 04:53:28 +08:00
|
|
|
if (!Function->getBody() && Function->isImplicitlyInstantiable()) {
|
2009-10-13 04:18:28 +08:00
|
|
|
bool AlreadyInstantiated = false;
|
|
|
|
if (FunctionTemplateSpecializationInfo *SpecInfo
|
|
|
|
= Function->getTemplateSpecializationInfo()) {
|
|
|
|
if (SpecInfo->getPointOfInstantiation().isInvalid())
|
|
|
|
SpecInfo->setPointOfInstantiation(Loc);
|
2009-10-28 04:53:28 +08:00
|
|
|
else if (SpecInfo->getTemplateSpecializationKind()
|
|
|
|
== TSK_ImplicitInstantiation)
|
2009-10-13 04:18:28 +08:00
|
|
|
AlreadyInstantiated = true;
|
|
|
|
} else if (MemberSpecializationInfo *MSInfo
|
|
|
|
= Function->getMemberSpecializationInfo()) {
|
|
|
|
if (MSInfo->getPointOfInstantiation().isInvalid())
|
|
|
|
MSInfo->setPointOfInstantiation(Loc);
|
2009-10-28 04:53:28 +08:00
|
|
|
else if (MSInfo->getTemplateSpecializationKind()
|
|
|
|
== TSK_ImplicitInstantiation)
|
2009-10-13 04:18:28 +08:00
|
|
|
AlreadyInstantiated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!AlreadyInstantiated)
|
|
|
|
PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc));
|
|
|
|
}
|
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
// FIXME: keep track of references to static functions
|
|
|
|
Function->setUsed(true);
|
|
|
|
return;
|
2009-06-23 07:06:13 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
2009-07-25 04:34:43 +08:00
|
|
|
// Implicit instantiation of static data members of class templates.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (Var->isStaticDataMember() &&
|
2009-10-13 04:18:28 +08:00
|
|
|
Var->getInstantiatedFromStaticDataMember()) {
|
|
|
|
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
|
|
|
|
assert(MSInfo && "Missing member specialization information?");
|
|
|
|
if (MSInfo->getPointOfInstantiation().isInvalid() &&
|
|
|
|
MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
|
|
|
|
MSInfo->setPointOfInstantiation(Loc);
|
|
|
|
PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc));
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
// FIXME: keep track of references to static data?
|
2009-07-25 04:34:43 +08:00
|
|
|
|
2009-06-20 07:52:42 +08:00
|
|
|
D->setUsed(true);
|
2009-07-25 04:34:43 +08:00
|
|
|
return;
|
2009-09-11 11:29:30 +08:00
|
|
|
}
|
2009-06-20 07:52:42 +08:00
|
|
|
}
|
2009-10-10 07:51:55 +08:00
|
|
|
|
|
|
|
bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
|
|
|
|
CallExpr *CE, FunctionDecl *FD) {
|
|
|
|
if (ReturnType->isVoidType() || !ReturnType->isIncompleteType())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
PartialDiagnostic Note =
|
|
|
|
FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here)
|
|
|
|
<< FD->getDeclName() : PDiag();
|
|
|
|
SourceLocation NoteLoc = FD ? FD->getLocation() : SourceLocation();
|
|
|
|
|
|
|
|
if (RequireCompleteType(Loc, ReturnType,
|
|
|
|
FD ?
|
|
|
|
PDiag(diag::err_call_function_incomplete_return)
|
|
|
|
<< CE->getSourceRange() << FD->getDeclName() :
|
|
|
|
PDiag(diag::err_call_incomplete_return)
|
|
|
|
<< CE->getSourceRange(),
|
|
|
|
std::make_pair(NoteLoc, Note)))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-13 05:59:07 +08:00
|
|
|
// Diagnose the common s/=/==/ typo. Note that adding parentheses
|
|
|
|
// will prevent this condition from triggering, which is what we want.
|
|
|
|
void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
|
2009-11-11 10:41:58 +08:00
|
|
|
unsigned diagnostic = diag::warn_condition_is_assignment;
|
|
|
|
|
2009-10-13 05:59:07 +08:00
|
|
|
if (isa<BinaryOperator>(E)) {
|
|
|
|
BinaryOperator *Op = cast<BinaryOperator>(E);
|
|
|
|
if (Op->getOpcode() != BinaryOperator::Assign)
|
|
|
|
return;
|
|
|
|
|
2009-11-12 08:06:05 +08:00
|
|
|
// Greylist some idioms by putting them into a warning subcategory.
|
|
|
|
if (ObjCMessageExpr *ME
|
|
|
|
= dyn_cast<ObjCMessageExpr>(Op->getRHS()->IgnoreParenCasts())) {
|
|
|
|
Selector Sel = ME->getSelector();
|
|
|
|
|
|
|
|
// self = [<foo> init...]
|
|
|
|
if (isSelfExpr(Op->getLHS())
|
|
|
|
&& Sel.getIdentifierInfoForSlot(0)->getName().startswith("init"))
|
|
|
|
diagnostic = diag::warn_condition_is_idiomatic_assignment;
|
|
|
|
|
|
|
|
// <foo> = [<bar> nextObject]
|
|
|
|
else if (Sel.isUnarySelector() &&
|
|
|
|
Sel.getIdentifierInfoForSlot(0)->getName() == "nextObject")
|
|
|
|
diagnostic = diag::warn_condition_is_idiomatic_assignment;
|
|
|
|
}
|
2009-11-11 10:41:58 +08:00
|
|
|
|
2009-10-13 05:59:07 +08:00
|
|
|
Loc = Op->getOperatorLoc();
|
|
|
|
} else if (isa<CXXOperatorCallExpr>(E)) {
|
|
|
|
CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E);
|
|
|
|
if (Op->getOperator() != OO_Equal)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Loc = Op->getOperatorLoc();
|
|
|
|
} else {
|
|
|
|
// Not an assignment.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation Open = E->getSourceRange().getBegin();
|
2009-10-13 06:25:59 +08:00
|
|
|
SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
|
2009-10-13 05:59:07 +08:00
|
|
|
|
2009-11-11 10:41:58 +08:00
|
|
|
Diag(Loc, diagnostic)
|
2009-10-13 05:59:07 +08:00
|
|
|
<< E->getSourceRange()
|
|
|
|
<< CodeModificationHint::CreateInsertion(Open, "(")
|
|
|
|
<< CodeModificationHint::CreateInsertion(Close, ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
|
|
|
|
DiagnoseAssignmentAsCondition(E);
|
|
|
|
|
|
|
|
if (!E->isTypeDependent()) {
|
|
|
|
DefaultFunctionArrayConversion(E);
|
|
|
|
|
|
|
|
QualType T = E->getType();
|
|
|
|
|
|
|
|
if (getLangOptions().CPlusPlus) {
|
|
|
|
if (CheckCXXBooleanCondition(E)) // C++ 6.4p4
|
|
|
|
return true;
|
|
|
|
} else if (!T->isScalarType()) { // C99 6.8.4.1p1
|
|
|
|
Diag(Loc, diag::err_typecheck_statement_requires_scalar)
|
|
|
|
<< T << E->getSourceRange();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|