summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r--lib/Sema/SemaExpr.cpp2800
1 files changed, 1703 insertions, 1097 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a5e5083964222..d8e49c7d69410 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14,18 +14,20 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LiteralSupport.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Designator.h"
#include "clang/Parse/Scope.h"
using namespace clang;
+
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
@@ -44,12 +46,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
// stuff. Don't warn if we are implementing a deprecated
// construct.
bool isSilenced = false;
-
+
if (NamedDecl *ND = getCurFunctionOrMethodDecl()) {
// If this reference happens *in* a deprecated function or method, don't
// warn.
isSilenced = ND->getAttr<DeprecatedAttr>();
-
+
// If this is an Objective-C method implementation, check to see if the
// method was deprecated on the declaration, not the definition.
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) {
@@ -57,14 +59,14 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
// ObjCImplementationDecl.
if (ObjCImplementationDecl *Impl
= dyn_cast<ObjCImplementationDecl>(MD->getParent())) {
-
+
MD = Impl->getClassInterface()->getMethod(MD->getSelector(),
MD->isInstanceMethod());
isSilenced |= MD && MD->getAttr<DeprecatedAttr>();
}
}
}
-
+
if (!isSilenced)
Diag(Loc, diag::warn_deprecated) << D->getDeclName();
}
@@ -88,18 +90,17 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
}
/// DiagnoseSentinelCalls - This routine checks on method dispatch calls
-/// (and other functions in future), which have been declared with sentinel
+/// (and other functions in future), which have been declared with sentinel
/// attribute. It warns if call does not have the sentinel argument.
///
void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
- Expr **Args, unsigned NumArgs)
-{
+ Expr **Args, unsigned NumArgs) {
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
- if (!attr)
+ if (!attr)
return;
int sentinelPos = attr->getSentinel();
int nullPos = attr->getNullPos();
-
+
// 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.
unsigned int i = 0;
@@ -116,8 +117,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
warnNotEnoughArgs = (P != E || i >= NumArgs);
isMethod = 1;
- }
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// skip over named parameters.
ObjCMethodDecl::param_iterator P, E = FD->param_end();
for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) {
@@ -127,14 +127,13 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
++i;
}
warnNotEnoughArgs = (P != E || i >= NumArgs);
- }
- else if (VarDecl *V = dyn_cast<VarDecl>(D)) {
+ } else if (VarDecl *V = dyn_cast<VarDecl>(D)) {
// block or function pointer call.
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType()
- ? Ty->getAsPointerType()->getPointeeType()->getAsFunctionType()
- : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
+ const FunctionType *FT = Ty->isFunctionPointerType()
+ ? Ty->getAs<PointerType>()->getPointeeType()->getAs<FunctionType>()
+ : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) {
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned k;
@@ -148,11 +147,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
if (Ty->isBlockPointerType())
isMethod = 2;
- }
- else
+ } else
return;
- }
- else
+ } else
return;
if (warnNotEnoughArgs) {
@@ -176,7 +173,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
Expr *sentinelExpr = Args[sentinel];
if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
- !sentinelExpr->isNullPointerConstant(Context))) {
+ !sentinelExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull))) {
Diag(Loc, diag::warn_missing_sentinel) << isMethod;
Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
}
@@ -198,7 +196,8 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
if (Ty->isFunctionType())
- ImpCastExprToType(E, Context.getPointerType(Ty));
+ ImpCastExprToType(E, Context.getPointerType(Ty),
+ CastExpr::CK_FunctionToPointerDecay);
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
@@ -213,54 +212,20 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
//
if (getLangOptions().C99 || getLangOptions().CPlusPlus ||
E->isLvalue(Context) == Expr::LV_Valid)
- ImpCastExprToType(E, Context.getArrayDecayedType(Ty));
+ ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
+ CastExpr::CK_ArrayToPointerDecay);
}
}
-/// \brief Whether this is a promotable bitfield reference according
-/// to C99 6.3.1.1p2, bullet 2.
-///
-/// \returns the type this bit-field will promote to, or NULL if no
-/// promotion occurs.
-static QualType isPromotableBitField(Expr *E, ASTContext &Context) {
- FieldDecl *Field = E->getBitField();
- if (!Field)
- return QualType();
-
- const BuiltinType *BT = Field->getType()->getAsBuiltinType();
- if (!BT)
- return QualType();
-
- if (BT->getKind() != BuiltinType::Bool &&
- BT->getKind() != BuiltinType::Int &&
- BT->getKind() != BuiltinType::UInt)
- return QualType();
-
- llvm::APSInt BitWidthAP;
- if (!Field->getBitWidth()->isIntegerConstantExpr(BitWidthAP, Context))
- return QualType();
-
- uint64_t BitWidth = BitWidthAP.getZExtValue();
- uint64_t IntSize = Context.getTypeSize(Context.IntTy);
- if (BitWidth < IntSize ||
- (Field->getType()->isSignedIntegerType() && BitWidth == IntSize))
- return Context.IntTy;
-
- if (BitWidth == IntSize && Field->getType()->isUnsignedIntegerType())
- return Context.UnsignedIntTy;
-
- return QualType();
-}
-
/// UsualUnaryConversions - Performs various conversions that are common to most
-/// operators (C99 6.3). The conversions of array and function types are
+/// operators (C99 6.3). The conversions of array and function types are
/// sometimes surpressed. For example, the array->pointer conversion doesn't
/// apply if the array is an argument to the sizeof or address (&) operators.
/// In these instances, this routine should *not* be called.
Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
QualType Ty = Expr->getType();
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
-
+
// C99 6.3.1.1p2:
//
// The following may be used in an expression wherever an int or
@@ -274,33 +239,33 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
// 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.
+ QualType PTy = Context.isPromotableBitField(Expr);
+ if (!PTy.isNull()) {
+ ImpCastExprToType(Expr, PTy);
+ return Expr;
+ }
if (Ty->isPromotableIntegerType()) {
- ImpCastExprToType(Expr, Context.IntTy);
+ QualType PT = Context.getPromotedIntegerType(Ty);
+ ImpCastExprToType(Expr, PT);
return Expr;
- } else {
- QualType T = isPromotableBitField(Expr, Context);
- if (!T.isNull()) {
- ImpCastExprToType(Expr, T);
- return Expr;
- }
- }
-
+ }
+
DefaultFunctionArrayConversion(Expr);
return Expr;
}
/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
-/// do not have a prototype. Arguments that have type float are promoted to
+/// do not have a prototype. Arguments that have type float are promoted to
/// double. All other argument types are converted by UsualUnaryConversions().
void Sema::DefaultArgumentPromotion(Expr *&Expr) {
QualType Ty = Expr->getType();
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
-
+
// If this is a 'float' (CVR qualified or typedef) promote to double.
- if (const BuiltinType *BT = Ty->getAsBuiltinType())
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
if (BT->getKind() == BuiltinType::Float)
return ImpCastExprToType(Expr, Context.DoubleTy);
-
+
UsualUnaryConversions(Expr);
}
@@ -310,14 +275,14 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) {
/// completely illegal.
bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
DefaultArgumentPromotion(Expr);
-
+
if (Expr->getType()->isObjCInterfaceType()) {
Diag(Expr->getLocStart(),
diag::err_cannot_pass_objc_interface_to_vararg)
<< Expr->getType() << CT;
return true;
}
-
+
if (!Expr->getType()->isPODType())
Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg)
<< Expr->getType() << CT;
@@ -328,7 +293,7 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) {
/// UsualArithmeticConversions - Performs various conversions that are common to
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
-/// routine returns the first non-arithmetic type found. The client is
+/// routine returns the first non-arithmetic type found. The client is
/// responsible for emitting appropriate error diagnostics.
/// FIXME: verify the conversion rules for "complex int" are consistent with
/// GCC.
@@ -339,11 +304,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
UsualUnaryConversions(rhsExpr);
- // For conversion purposes, we ignore any qualifiers.
+ // For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhs =
Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType();
- QualType rhs =
+ QualType rhs =
Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType();
// If both types are identical, no conversion is needed.
@@ -356,159 +321,20 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
return lhs;
// Perform bitfield promotions.
- QualType LHSBitfieldPromoteTy = isPromotableBitField(lhsExpr, Context);
+ QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr);
if (!LHSBitfieldPromoteTy.isNull())
lhs = LHSBitfieldPromoteTy;
- QualType RHSBitfieldPromoteTy = isPromotableBitField(rhsExpr, Context);
+ QualType RHSBitfieldPromoteTy = Context.isPromotableBitField(rhsExpr);
if (!RHSBitfieldPromoteTy.isNull())
rhs = RHSBitfieldPromoteTy;
- QualType destType = UsualArithmeticConversionsType(lhs, rhs);
+ QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs);
if (!isCompAssign)
ImpCastExprToType(lhsExpr, destType);
ImpCastExprToType(rhsExpr, destType);
return destType;
}
-QualType Sema::UsualArithmeticConversionsType(QualType lhs, QualType rhs) {
- // Perform the usual unary conversions. We do this early so that
- // integral promotions to "int" can allow us to exit early, in the
- // lhs == rhs check. Also, for conversion purposes, we ignore any
- // qualifiers. For example, "const float" and "float" are
- // equivalent.
- if (lhs->isPromotableIntegerType())
- lhs = Context.IntTy;
- else
- lhs = lhs.getUnqualifiedType();
- if (rhs->isPromotableIntegerType())
- rhs = Context.IntTy;
- else
- rhs = rhs.getUnqualifiedType();
-
- // If both types are identical, no conversion is needed.
- if (lhs == rhs)
- return lhs;
-
- // If either side is a non-arithmetic type (e.g. a pointer), we are done.
- // The caller can deal with this (e.g. pointer + int).
- if (!lhs->isArithmeticType() || !rhs->isArithmeticType())
- return lhs;
-
- // At this point, we have two different arithmetic types.
-
- // Handle complex types first (C99 6.3.1.8p1).
- if (lhs->isComplexType() || rhs->isComplexType()) {
- // if we have an integer operand, the result is the complex type.
- if (rhs->isIntegerType() || rhs->isComplexIntegerType()) {
- // convert the rhs to the lhs complex type.
- return lhs;
- }
- if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
- // convert the lhs to the rhs complex type.
- return rhs;
- }
- // This handles complex/complex, complex/float, or float/complex.
- // When both operands are complex, the shorter operand is converted to the
- // type of the longer, and that is the type of the result. This corresponds
- // to what is done when combining two real floating-point operands.
- // The fun begins when size promotion occur across type domains.
- // From H&S 6.3.4: When one operand is complex and the other is a real
- // floating-point type, the less precise type is converted, within it's
- // real or complex domain, to the precision of the other type. For example,
- // when combining a "long double" with a "double _Complex", the
- // "double _Complex" is promoted to "long double _Complex".
- int result = Context.getFloatingTypeOrder(lhs, rhs);
-
- if (result > 0) { // The left side is bigger, convert rhs.
- rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs);
- } else if (result < 0) { // The right side is bigger, convert lhs.
- lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs);
- }
- // At this point, lhs and rhs have the same rank/size. Now, make sure the
- // domains match. This is a requirement for our implementation, C99
- // does not require this promotion.
- if (lhs != rhs) { // Domains don't match, we have complex/float mix.
- if (lhs->isRealFloatingType()) { // handle "double, _Complex double".
- return rhs;
- } else { // handle "_Complex double, double".
- return lhs;
- }
- }
- return lhs; // The domain/size match exactly.
- }
- // Now handle "real" floating types (i.e. float, double, long double).
- if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) {
- // if we have an integer operand, the result is the real floating type.
- if (rhs->isIntegerType()) {
- // convert rhs to the lhs floating point type.
- return lhs;
- }
- if (rhs->isComplexIntegerType()) {
- // convert rhs to the complex floating point type.
- return Context.getComplexType(lhs);
- }
- if (lhs->isIntegerType()) {
- // convert lhs to the rhs floating point type.
- return rhs;
- }
- if (lhs->isComplexIntegerType()) {
- // convert lhs to the complex floating point type.
- return Context.getComplexType(rhs);
- }
- // We have two real floating types, float/complex combos were handled above.
- // Convert the smaller operand to the bigger result.
- int result = Context.getFloatingTypeOrder(lhs, rhs);
- if (result > 0) // convert the rhs
- return lhs;
- assert(result < 0 && "illegal float comparison");
- return rhs; // convert the lhs
- }
- if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) {
- // Handle GCC complex int extension.
- const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType();
- const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType();
-
- if (lhsComplexInt && rhsComplexInt) {
- if (Context.getIntegerTypeOrder(lhsComplexInt->getElementType(),
- rhsComplexInt->getElementType()) >= 0)
- return lhs; // convert the rhs
- return rhs;
- } else if (lhsComplexInt && rhs->isIntegerType()) {
- // convert the rhs to the lhs complex type.
- return lhs;
- } else if (rhsComplexInt && lhs->isIntegerType()) {
- // convert the lhs to the rhs complex type.
- return rhs;
- }
- }
- // Finally, we have two differing integer types.
- // The rules for this case are in C99 6.3.1.8
- int compare = Context.getIntegerTypeOrder(lhs, rhs);
- bool lhsSigned = lhs->isSignedIntegerType(),
- rhsSigned = rhs->isSignedIntegerType();
- QualType destType;
- if (lhsSigned == rhsSigned) {
- // Same signedness; use the higher-ranked type
- destType = compare >= 0 ? lhs : rhs;
- } else if (compare != (lhsSigned ? 1 : -1)) {
- // The unsigned type has greater than or equal rank to the
- // signed type, so use the unsigned type
- destType = lhsSigned ? rhs : lhs;
- } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) {
- // The two types are different widths; if we are here, that
- // means the signed type is larger than the unsigned type, so
- // use the signed type.
- destType = lhsSigned ? lhs : rhs;
- } else {
- // The signed type is higher-ranked than the unsigned type,
- // but isn't actually any bigger (like unsigned int and long
- // on most 32-bit systems). Use the unsigned type corresponding
- // to the signed type.
- destType = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
- }
- return destType;
-}
-
//===----------------------------------------------------------------------===//
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
@@ -546,9 +372,9 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
StrTy = Context.getConstantArrayType(StrTy,
llvm::APInt(32, Literal.GetNumStringChars()+1),
ArrayType::Normal, 0);
-
+
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
- return Owned(StringLiteral::Create(Context, Literal.GetString(),
+ return Owned(StringLiteral::Create(Context, Literal.GetString(),
Literal.GetStringLength(),
Literal.AnyWide, StrTy,
&StringTokLocs[0],
@@ -569,7 +395,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
// we wanted to.
if (CurBlock->TheDecl == VD->getDeclContext())
return false;
-
+
// If this is an enum constant or function, it is constant, don't snapshot.
if (isa<EnumConstantDecl>(VD) || isa<FunctionDecl>(VD))
return false;
@@ -580,7 +406,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
if (const VarDecl *Var = dyn_cast<VarDecl>(VD))
if (!Var->hasLocalStorage())
return false;
-
+
// Blocks that have these can't be constant.
CurBlock->hasBlockDeclRefExprs = true;
@@ -594,15 +420,15 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
// having a reference outside it.
if (NextBlock->TheDecl == VD->getDeclContext())
break;
-
+
// Otherwise, the DeclRef from the inner block causes the outer one to need
// a snapshot as well.
NextBlock->hasBlockDeclRefExprs = true;
}
-
+
return true;
-}
-
+}
+
/// ActOnIdentifierExpr - The parser read an identifier in expression context,
@@ -628,35 +454,35 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
const CXXScopeSpec *SS) {
if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
Diag(Loc,
- diag::err_auto_variable_cannot_appear_in_own_initializer)
+ diag::err_auto_variable_cannot_appear_in_own_initializer)
<< D->getDeclName();
return ExprError();
}
-
+
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) {
- Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
+ Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
<< D->getIdentifier() << FD->getDeclName();
- Diag(D->getLocation(), diag::note_local_variable_declared_here)
+ Diag(D->getLocation(), diag::note_local_variable_declared_here)
<< D->getIdentifier();
return ExprError();
}
}
}
}
-
+
MarkDeclarationReferenced(Loc, D);
-
+
Expr *E;
if (SS && !SS->isEmpty()) {
- E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
+ E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
ValueDependent, SS->getRange(),
static_cast<NestedNameSpecifier *>(SS->getScopeRep()));
} else
E = new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
-
+
return Owned(E);
}
@@ -665,14 +491,14 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
/// is Record.
static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
RecordDecl *Record) {
- assert(Record->isAnonymousStructOrUnion() &&
+ assert(Record->isAnonymousStructOrUnion() &&
"Record must be an anonymous struct or union!");
-
+
// 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.
DeclContext *Ctx = Record->getDeclContext();
- for (DeclContext::decl_iterator D = Ctx->decls_begin(),
+ for (DeclContext::decl_iterator D = Ctx->decls_begin(),
DEnd = Ctx->decls_end();
D != DEnd; ++D) {
if (*D == Record) {
@@ -721,7 +547,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
break;
}
Ctx = Ctx->getParent();
- } while (Ctx->isRecord() &&
+ } while (Ctx->isRecord() &&
cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
return BaseObject;
@@ -733,7 +559,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
Expr *BaseObjectExpr,
SourceLocation OpLoc) {
llvm::SmallVector<FieldDecl *, 4> AnonFields;
- VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
+ VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
AnonFields);
// Build the expression that refers to the base object, from
@@ -741,7 +567,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
// of the anonymous union objects and, eventually, the field we
// found via name lookup.
bool BaseObjectIsPointer = false;
- unsigned ExtraQuals = 0;
+ Qualifiers BaseQuals;
if (BaseObject) {
// BaseObject is an anonymous struct/union variable (and is,
// therefore, not part of another non-anonymous record).
@@ -749,29 +575,30 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
MarkDeclarationReferenced(Loc, BaseObject);
BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(),
SourceLocation());
- ExtraQuals
- = Context.getCanonicalType(BaseObject->getType()).getCVRQualifiers();
+ BaseQuals
+ = Context.getCanonicalType(BaseObject->getType()).getQualifiers();
} else if (BaseObjectExpr) {
// The caller provided the base object expression. Determine
// whether its a pointer and whether it adds any qualifiers to the
// anonymous struct/union fields we're looking into.
QualType ObjectType = BaseObjectExpr->getType();
- if (const PointerType *ObjectPtr = ObjectType->getAsPointerType()) {
+ if (const PointerType *ObjectPtr = ObjectType->getAs<PointerType>()) {
BaseObjectIsPointer = true;
ObjectType = ObjectPtr->getPointeeType();
}
- ExtraQuals = Context.getCanonicalType(ObjectType).getCVRQualifiers();
+ BaseQuals
+ = Context.getCanonicalType(ObjectType).getQualifiers();
} else {
// We've found a member of an anonymous struct/union that is
// inside a non-anonymous struct/union, so in a well-formed
// program our base object expression is "this".
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (!MD->isStatic()) {
- QualType AnonFieldType
+ QualType AnonFieldType
= Context.getTagDeclType(
cast<RecordDecl>(AnonFields.back()->getDeclContext()));
QualType ThisType = Context.getTagDeclType(MD->getParent());
- if ((Context.getCanonicalType(AnonFieldType)
+ if ((Context.getCanonicalType(AnonFieldType)
== Context.getCanonicalType(ThisType)) ||
IsDerivedFrom(ThisType, AnonFieldType)) {
// Our base object expression is "this".
@@ -783,10 +610,10 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method)
<< Field->getDeclName());
}
- ExtraQuals = MD->getTypeQualifiers();
+ BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
}
- if (!BaseObjectExpr)
+ if (!BaseObjectExpr)
return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use)
<< Field->getDeclName());
}
@@ -794,20 +621,35 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
// Build the implicit member references to the field of the
// anonymous struct/union.
Expr *Result = BaseObjectExpr;
+ Qualifiers ResultQuals = BaseQuals;
for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
FI = AnonFields.rbegin(), FIEnd = AnonFields.rend();
FI != FIEnd; ++FI) {
QualType MemberType = (*FI)->getType();
- if (!(*FI)->isMutable()) {
- unsigned combinedQualifiers
- = MemberType.getCVRQualifiers() | ExtraQuals;
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
- }
+ 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);
+
MarkDeclarationReferenced(Loc, *FI);
+ // FIXME: Might this end up being a qualified name?
Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
OpLoc, MemberType);
BaseObjectIsPointer = false;
- ExtraQuals = Context.getCanonicalType(MemberType).getCVRQualifiers();
+ ResultQuals = NewQuals;
}
return Owned(Result);
@@ -835,7 +677,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
Sema::OwningExprResult
Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
DeclarationName Name, bool HasTrailingLParen,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
bool isAddressOfOperand) {
// Could be enum-constant, value decl, instance variable, etc.
if (SS && SS->isInvalid())
@@ -848,12 +690,13 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// FIXME: Member of the current instantiation.
if (SS && isDependentScopeSpecifier(*SS)) {
return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy,
- Loc, SS->getRange(),
- static_cast<NestedNameSpecifier *>(SS->getScopeRep())));
+ Loc, SS->getRange(),
+ static_cast<NestedNameSpecifier *>(SS->getScopeRep()),
+ isAddressOfOperand));
}
- LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName,
- false, true, Loc);
+ LookupResult Lookup;
+ LookupParsedName(Lookup, S, SS, Name, LookupOrdinaryName, false, true, Loc);
if (Lookup.isAmbiguous()) {
DiagnoseAmbiguousLookup(Lookup, Name, Loc,
@@ -861,8 +704,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
: SourceRange());
return ExprError();
}
-
- NamedDecl *D = Lookup.getAsDecl();
+
+ NamedDecl *D = Lookup.getAsSingleDecl(Context);
// If this reference is in an Objective-C method, then ivar lookup happens as
// well.
@@ -870,8 +713,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
if (II && getCurMethodDecl()) {
// 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
- // 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
+ // found a decl, but that decl is outside the current instance method (i.e.
+ // a global variable). In these two cases, we do a lookup for an ivar with
// this name, if the lookup sucedes, we replace it our current decl.
if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) {
ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
@@ -880,12 +723,12 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// Check if referencing a field with __attribute__((deprecated)).
if (DiagnoseUseOfDecl(IV, Loc))
return ExprError();
-
+
// 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();
-
+
bool IsClsMethod = getCurMethodDecl()->isClassMethod();
// If a class method attemps to use a free standing ivar, this is
// an error.
@@ -901,15 +744,15 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// FIXME: This should use a new expr for a direct reference, don't
// turn this into Self->ivar, just return a BareIVarExpr or something.
IdentifierInfo &II = Context.Idents.get("self");
- OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false);
+ OwningExprResult SelfExpr = ActOnIdentifierExpr(S, SourceLocation(),
+ II, false);
MarkDeclarationReferenced(Loc, IV);
- return Owned(new (Context)
- ObjCIvarRefExpr(IV, IV->getType(), Loc,
+ return Owned(new (Context)
+ ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.takeAs<Expr>(), true, true));
}
}
- }
- else if (getCurMethodDecl()->isInstanceMethod()) {
+ } else if (getCurMethodDecl()->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
@@ -922,10 +765,10 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// Needed to implement property "super.method" notation.
if (D == 0 && II->isStr("super")) {
QualType T;
-
+
if (getCurMethodDecl()->isInstanceMethod())
- T = Context.getPointerType(Context.getObjCInterfaceType(
- getCurMethodDecl()->getClassInterface()));
+ T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
+ getCurMethodDecl()->getClassInterface()));
else
T = Context.getObjCClassType();
return Owned(new (Context) ObjCSuperExpr(Loc, T));
@@ -934,7 +777,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// Determine whether this name might be a candidate for
// argument-dependent lookup.
- bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
+ bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
HasTrailingLParen;
if (ADL && D == 0) {
@@ -960,8 +803,9 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// If this name wasn't predeclared and if this is not a function call,
// diagnose the problem.
if (SS && !SS->isEmpty())
- return ExprError(Diag(Loc, diag::err_typecheck_no_member)
- << Name << SS->getRange());
+ return ExprError(Diag(Loc, diag::err_no_member)
+ << Name << computeDeclContext(*SS, false)
+ << SS->getRange());
else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
return ExprError(Diag(Loc, diag::err_undeclared_use)
@@ -970,18 +814,18 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name);
}
}
-
+
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.
-
+
// FIXME: In a template instantiation, we don't have scope
// information to check this property.
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
Scope *CheckS = S;
while (CheckS) {
- if (CheckS->isWithinElse() &&
+ if (CheckS->isWithinElse() &&
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
if (Var->getType()->isBooleanType())
ExprError(Diag(Loc, diag::warn_value_always_false)
@@ -991,7 +835,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
<< Var->getDeclName());
break;
}
-
+
// Move up one more control parent to check again.
CheckS = CheckS->getControlParent();
if (CheckS)
@@ -1010,24 +854,66 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
QualType T = Func->getType();
QualType NoProtoType = T;
- if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
+ if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>())
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
return BuildDeclRefExpr(Func, NoProtoType, Loc, false, false, SS);
}
}
-
+
return BuildDeclarationNameExpr(Loc, D, HasTrailingLParen, SS, isAddressOfOperand);
}
+/// \brief Cast member's object to its own class if necessary.
+bool
+Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) {
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(Member))
+ if (CXXRecordDecl *RD =
+ dyn_cast<CXXRecordDecl>(FD->getDeclContext())) {
+ QualType DestType =
+ Context.getCanonicalType(Context.getTypeDeclType(RD));
+ if (DestType->isDependentType() || From->getType()->isDependentType())
+ return false;
+ QualType FromRecordType = From->getType();
+ QualType DestRecordType = DestType;
+ if (FromRecordType->getAs<PointerType>()) {
+ DestType = Context.getPointerType(DestType);
+ FromRecordType = FromRecordType->getPointeeType();
+ }
+ if (!Context.hasSameUnqualifiedType(FromRecordType, DestRecordType) &&
+ CheckDerivedToBaseConversion(FromRecordType,
+ DestRecordType,
+ From->getSourceRange().getBegin(),
+ From->getSourceRange()))
+ return true;
+ ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
+ /*isLvalue=*/true);
+ }
+ return false;
+}
+
+/// \brief Build a MemberExpr AST node.
+static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
+ const CXXScopeSpec *SS, NamedDecl *Member,
+ SourceLocation Loc, QualType Ty) {
+ if (SS && SS->isSet())
+ return MemberExpr::Create(C, Base, isArrow,
+ (NestedNameSpecifier *)SS->getScopeRep(),
+ SS->getRange(), Member, Loc,
+ // FIXME: Explicit template argument lists
+ false, SourceLocation(), 0, 0, SourceLocation(),
+ Ty);
+
+ return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty);
+}
/// \brief Complete semantic analysis for a reference to the given declaration.
Sema::OwningExprResult
Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
bool HasTrailingLParen,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec *SS,
bool isAddressOfOperand) {
assert(D && "Cannot refer to a NULL declaration");
DeclarationName Name = D->getDeclName();
-
+
// 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.
@@ -1060,7 +946,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (!MD->isStatic()) {
- // C++ [class.mfct.nonstatic]p2:
+ // C++ [class.mfct.nonstatic]p2:
// [...] if name lookup (3.4.1) resolves the name in the
// id-expression to a nonstatic nontype member of class X or of
// a base class of X, the id-expression is transformed into a
@@ -1072,45 +958,74 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
Ctx = FD->getDeclContext();
MemberType = FD->getType();
- if (const ReferenceType *RefType = MemberType->getAsReferenceType())
+ if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>())
MemberType = RefType->getPointeeType();
- else if (!FD->isMutable()) {
- unsigned combinedQualifiers
- = MemberType.getCVRQualifiers() | MD->getTypeQualifiers();
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
- }
+ else if (!FD->isMutable())
+ MemberType
+ = Context.getQualifiedType(MemberType,
+ Qualifiers::fromCVRMask(MD->getTypeQualifiers()));
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (!Method->isStatic()) {
Ctx = Method->getParent();
MemberType = Method->getType();
}
- } else if (OverloadedFunctionDecl *Ovl
+ } else if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D)) {
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())) {
+ if (!Method->isStatic()) {
+ Ctx = Method->getParent();
+ MemberType = Context.OverloadTy;
+ }
+ }
+ } else if (OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(D)) {
- for (OverloadedFunctionDecl::function_iterator
+ // FIXME: We need an abstraction for iterating over one or more function
+ // templates or functions. This code is far too repetitive!
+ for (OverloadedFunctionDecl::function_iterator
Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
- if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(*Func))
- if (!DMethod->isStatic()) {
- Ctx = Ovl->getDeclContext();
- MemberType = Context.OverloadTy;
- break;
- }
+ CXXMethodDecl *DMethod = 0;
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(*Func))
+ DMethod = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ DMethod = dyn_cast<CXXMethodDecl>(*Func);
+
+ if (DMethod && !DMethod->isStatic()) {
+ Ctx = DMethod->getDeclContext();
+ MemberType = Context.OverloadTy;
+ break;
+ }
}
}
if (Ctx && Ctx->isRecord()) {
QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx));
QualType ThisType = Context.getTagDeclType(MD->getParent());
- if ((Context.getCanonicalType(CtxType)
+ if ((Context.getCanonicalType(CtxType)
== Context.getCanonicalType(ThisType)) ||
IsDerivedFrom(ThisType, CtxType)) {
// Build the implicit member access expression.
Expr *This = new (Context) CXXThisExpr(SourceLocation(),
MD->getThisType(Context));
MarkDeclarationReferenced(Loc, D);
- return Owned(new (Context) MemberExpr(This, true, D,
- Loc, MemberType));
+ 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;
+ }
+
+ if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc))
+ return ExprError();
+ return Owned(BuildMemberExpr(Context, This, true, SS, D,
+ Loc, MemberType));
}
}
}
@@ -1145,13 +1060,18 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
false, false, SS);
+ else if (UnresolvedUsingDecl *UD = dyn_cast<UnresolvedUsingDecl>(D))
+ return BuildDeclRefExpr(UD, Context.DependentTy, Loc,
+ /*TypeDependent=*/true,
+ /*ValueDependent=*/true, SS);
+
ValueDecl *VD = cast<ValueDecl>(D);
// 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.
- bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
+ bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
HasTrailingLParen;
if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
return ExprError();
@@ -1177,9 +1097,9 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
// This is to record that a 'const' was actually synthesize and added.
bool constAdded = !ExprTy.isConstQualified();
// Variable will be bound by-copy, make it const within the closure.
-
+
ExprTy.addConst();
- return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false,
+ return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false,
constAdded));
}
// If this reference is not in a block or if the referenced variable is
@@ -1189,7 +1109,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
bool ValueDependent = false;
if (getLangOptions().CPlusPlus) {
// C++ [temp.dep.expr]p3:
- // An id-expression is type-dependent if it contains:
+ // An id-expression is type-dependent if it contains:
// - an identifier that was declared with a dependent type,
if (VD->getType()->isDependentType())
TypeDependent = true;
@@ -1226,7 +1146,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
// - a constant with integral or enumeration type and is
// initialized with an expression that is value-dependent
else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) {
- if (Dcl->getType().getCVRQualifiers() == QualType::Const &&
+ if (Dcl->getType().getCVRQualifiers() == Qualifiers::Const &&
Dcl->getInit()) {
ValueDependent = Dcl->getInit()->isValueDependent();
}
@@ -1250,21 +1170,24 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
// Pre-defined identifiers are of type char[x], where x is the length of the
// string.
- unsigned Length;
- if (FunctionDecl *FD = getCurFunctionDecl())
- Length = FD->getIdentifier()->getLength();
- else if (ObjCMethodDecl *MD = getCurMethodDecl())
- Length = MD->getSynthesizedMethodSize();
- else {
+
+ Decl *currentDecl = getCurFunctionOrMethodDecl();
+ if (!currentDecl) {
Diag(Loc, diag::ext_predef_outside_function);
- // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string.
- Length = IT == PredefinedExpr::PrettyFunction ? strlen("top level") : 0;
+ currentDecl = Context.getTranslationUnitDecl();
}
+ QualType ResTy;
+ if (cast<DeclContext>(currentDecl)->isDependentContext()) {
+ ResTy = Context.DependentTy;
+ } else {
+ unsigned Length =
+ PredefinedExpr::ComputeName(Context, IT, currentDecl).length();
- llvm::APInt LengthI(32, Length + 1);
- QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const);
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ llvm::APInt LengthI(32, Length + 1);
+ ResTy = Context.CharTy.withConst();
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ }
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
}
@@ -1304,7 +1227,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// Get the spelling of the token, which eliminates trigraphs, etc.
unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin);
- NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
+ NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
Tok.getLocation(), PP);
if (Literal.hadError)
return ExprError();
@@ -1417,7 +1340,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// If this is an imaginary literal, create the ImaginaryLiteral wrapper.
if (Literal.isImaginary)
- Res = new (Context) ImaginaryLiteral(Res,
+ Res = new (Context) ImaginaryLiteral(Res,
Context.getComplexType(Res->getType()));
return Owned(Res);
@@ -1446,27 +1369,27 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange;
return false;
}
-
+
// Allow sizeof(void)/alignof(void) as an extension.
if (exprType->isVoidType()) {
Diag(OpLoc, diag::ext_sizeof_void_type)
<< (isSizeof ? "sizeof" : "__alignof") << ExprRange;
return false;
}
-
+
if (RequireCompleteType(OpLoc, exprType,
- isSizeof ? diag::err_sizeof_incomplete_type :
- diag::err_alignof_incomplete_type,
- ExprRange))
+ isSizeof ? diag::err_sizeof_incomplete_type :
+ PDiag(diag::err_alignof_incomplete_type)
+ << ExprRange))
return true;
-
+
// Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) {
Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
<< exprType << isSizeof << ExprRange;
return true;
}
-
+
return false;
}
@@ -1474,7 +1397,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
const SourceRange &ExprRange) {
E = E->IgnoreParens();
- // alignof decl is always ok.
+ // alignof decl is always ok.
if (isa<DeclRefExpr>(E))
return false;
@@ -1490,15 +1413,15 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
// Alignment of a field access is always okay, so long as it isn't a
// bit-field.
if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
- if (dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (isa<FieldDecl>(ME->getMemberDecl()))
return false;
return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
}
/// \brief Build a sizeof or alignof expression given a type operand.
-Action::OwningExprResult
-Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
+Action::OwningExprResult
+Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
bool isSizeOf, SourceRange R) {
if (T.isNull())
return ExprError();
@@ -1515,8 +1438,8 @@ Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
/// \brief Build a sizeof or alignof expression given an expression
/// operand.
-Action::OwningExprResult
-Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
+Action::OwningExprResult
+Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
bool isSizeOf, SourceRange R) {
// Verify that the operand is valid.
bool isInvalid = false;
@@ -1550,9 +1473,10 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
if (TyOrEx == 0) return ExprError();
if (isType) {
- QualType ArgTy = QualType::getFromOpaquePtr(TyOrEx);
+ // FIXME: Preserve type source info.
+ QualType ArgTy = GetTypeFromParser(TyOrEx);
return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange);
- }
+ }
// Get the end location.
Expr *ArgEx = (Expr *)TyOrEx;
@@ -1568,15 +1492,15 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
if (V->isTypeDependent())
return Context.DependentTy;
-
+
// These operators return the element type of a complex type.
- if (const ComplexType *CT = V->getType()->getAsComplexType())
+ if (const ComplexType *CT = V->getType()->getAs<ComplexType>())
return CT->getElementType();
-
+
// Otherwise they pass through real integer and floating point types here.
if (V->getType()->isArithmeticType())
return V->getType();
-
+
// Reject anything else.
Diag(Loc, diag::err_realimag_invalid_type) << V->getType()
<< (isReal ? "__real" : "__imag");
@@ -1588,6 +1512,8 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
Action::OwningExprResult
Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Kind, ExprArg Input) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Input = MaybeConvertParenListExprToParenExpr(S, move(Input));
Expr *Arg = (Expr *)Input.get();
UnaryOperator::Opcode Opc;
@@ -1612,9 +1538,9 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// for objects of that type. When the postfix increment is
// called as a result of using the ++ operator, the int
// argument will have value zero.
- Expr *Args[2] = {
- Arg,
- new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,
+ Expr *Args[2] = {
+ Arg,
+ new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0,
/*isSigned=*/true), Context.IntTy, SourceLocation())
};
@@ -1646,9 +1572,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
}
// Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
+ QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -1657,9 +1581,17 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
Input.release();
Args[0] = Arg;
- return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
- Args, 2, ResultTy,
- OpLoc));
+
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OverOp,
+ FnExpr, Args, 2,
+ ResultTy, OpLoc));
+
+ if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+ return Owned(TheCall.release());
+
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -1672,11 +1604,19 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
}
}
- case OR_No_Viable_Function:
- // No viable function; fall through to handling this as a
- // built-in operator, which will produce an error message for us.
- break;
-
+ case OR_No_Viable_Function: {
+ // No viable function; try checking this as a built-in operator, which
+ // will fail and provide a diagnostic. Then, print the overload
+ // candidates.
+ OwningExprResult Result = CreateBuiltinUnaryOp(OpLoc, Opc, move(Input));
+ assert(Result.isInvalid() &&
+ "C++ postfix-unary operator overloading is missing candidates!");
+ if (Result.isInvalid())
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+
+ return move(Result);
+ }
+
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< UnaryOperator::getOpcodeStr(Opc)
@@ -1698,17 +1638,17 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// build a built-in operation.
}
- QualType result = CheckIncrementDecrementOperand(Arg, OpLoc,
- Opc == UnaryOperator::PostInc);
- if (result.isNull())
- return ExprError();
Input.release();
- return Owned(new (Context) UnaryOperator(Arg, Opc, result, OpLoc));
+ Input = Arg;
+ return CreateBuiltinUnaryOp(OpLoc, Opc, move(Input));
}
Action::OwningExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
ExprArg Idx, SourceLocation RLoc) {
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
Expr *LHSExp = static_cast<Expr*>(Base.get()),
*RHSExp = static_cast<Expr*>(Idx.get());
@@ -1720,12 +1660,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
Context.DependentTy, RLoc));
}
- if (getLangOptions().CPlusPlus &&
+ if (getLangOptions().CPlusPlus &&
(LHSExp->getType()->isRecordType() ||
LHSExp->getType()->isEnumeralType() ||
RHSExp->getType()->isRecordType() ||
RHSExp->getType()->isEnumeralType())) {
- // Add the appropriate overloaded operators (C++ [over.match.oper])
+ // Add the appropriate overloaded operators (C++ [over.match.oper])
// to the candidate set.
OverloadCandidateSet CandidateSet;
Expr *Args[2] = { LHSExp, RHSExp };
@@ -1746,7 +1686,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
if (PerformObjectArgumentInitialization(LHSExp, Method) ||
- PerformCopyInitialization(RHSExp,
+ PerformCopyInitialization(RHSExp,
FnDecl->getParamDecl(0)->getType(),
"passing"))
return ExprError();
@@ -1762,9 +1702,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
}
// Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
+ QualType ResultTy = FnDecl->getResultType().getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
@@ -1775,9 +1713,16 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
Idx.release();
Args[0] = LHSExp;
Args[1] = RHSExp;
- return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
- FnExpr, Args, 2,
- ResultTy, LLoc));
+
+ ExprOwningPtr<CXXOperatorCallExpr>
+ TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
+ FnExpr, Args, 2,
+ ResultTy, RLoc));
+ if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(),
+ FnDecl))
+ return ExprError();
+
+ return Owned(TheCall.release());
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -1834,16 +1779,27 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = LHSExp;
IndexExpr = RHSExp;
ResultType = Context.DependentTy;
- } else if (const PointerType *PTy = LHSTy->getAsPointerType()) {
+ } else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) {
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ ResultType = PTy->getPointeeType();
+ } else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
+ // Handle the uncommon case of "123[Ptr]".
+ BaseExpr = RHSExp;
+ IndexExpr = LHSExp;
+ ResultType = PTy->getPointeeType();
+ } else if (const ObjCObjectPointerType *PTy =
+ LHSTy->getAs<ObjCObjectPointerType>()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
ResultType = PTy->getPointeeType();
- } else if (const PointerType *PTy = RHSTy->getAsPointerType()) {
+ } else if (const ObjCObjectPointerType *PTy =
+ RHSTy->getAs<ObjCObjectPointerType>()) {
// Handle the uncommon case of "123[Ptr]".
BaseExpr = RHSExp;
IndexExpr = LHSExp;
ResultType = PTy->getPointeeType();
- } else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
+ } else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) {
BaseExpr = LHSExp; // vectors: V[123]
IndexExpr = RHSExp;
@@ -1862,7 +1818,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = LHSExp;
IndexExpr = RHSExp;
- ResultType = LHSTy->getAsPointerType()->getPointeeType();
+ ResultType = LHSTy->getAs<PointerType>()->getPointeeType();
} else if (RHSTy->isArrayType()) {
// Same as previous, except for 123[f().a] case
Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
@@ -1872,38 +1828,45 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
BaseExpr = RHSExp;
IndexExpr = LHSExp;
- ResultType = RHSTy->getAsPointerType()->getPointeeType();
+ ResultType = RHSTy->getAs<PointerType>()->getPointeeType();
} else {
return ExprError(Diag(LLoc, diag::err_typecheck_subscript_value)
<< LHSExp->getSourceRange() << RHSExp->getSourceRange());
}
// C99 6.5.2.1p1
- if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent())
+ if (!(IndexExpr->getType()->isIntegerType() &&
+ IndexExpr->getType()->isScalarType()) && !IndexExpr->isTypeDependent())
return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer)
<< IndexExpr->getSourceRange());
+ if ((IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
+ && !IndexExpr->isTypeDependent())
+ Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange();
+
// C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
- // 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)
+ // 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)
// incomplete types are not object types.
if (ResultType->isFunctionType()) {
Diag(BaseExpr->getLocStart(), diag::err_subscript_function_type)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
}
-
+
if (!ResultType->isDependentType() &&
- RequireCompleteType(LLoc, ResultType, diag::err_subscript_incomplete_type,
- BaseExpr->getSourceRange()))
+ RequireCompleteType(LLoc, ResultType,
+ PDiag(diag::err_subscript_incomplete_type)
+ << BaseExpr->getSourceRange()))
return ExprError();
-
+
// 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();
}
-
+
Base.release();
Idx.release();
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
@@ -1912,11 +1875,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
QualType Sema::
CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
- IdentifierInfo &CompName, SourceLocation CompLoc) {
- const ExtVectorType *vecType = baseType->getAsExtVectorType();
+ const IdentifierInfo *CompName,
+ SourceLocation CompLoc) {
+ const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
// The vector accessor can't exceed the number of elements.
- const char *compStr = CompName.getName();
+ const char *compStr = CompName->getName();
// This flag determines whether or not the component is one of the four
// special names that indicate a subset of exactly half the elements are
@@ -1953,7 +1917,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
// Ensure no component accessor exceeds the width of the vector type it
// operates on.
if (!HalvingSwizzle) {
- compStr = CompName.getName();
+ compStr = CompName->getName();
if (HexSwizzle)
compStr++;
@@ -1981,7 +1945,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
// vec4.s0 is a float, vec4.s23 is a vec3, etc.
// vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2.
unsigned CompSize = HalvingSwizzle ? vecType->getNumElements() / 2
- : CompName.getLength();
+ : CompName->getLength();
if (HexSwizzle)
CompSize--;
@@ -1999,18 +1963,18 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc,
}
static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
- IdentifierInfo &Member,
+ IdentifierInfo *Member,
const Selector &Sel,
ASTContext &Context) {
-
- if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(&Member))
+
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
return PD;
if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
return OMD;
-
+
for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
E = PDecl->protocol_end(); I != E; ++I) {
- if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel,
+ if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel,
Context))
return D;
}
@@ -2018,14 +1982,14 @@ static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
}
static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
- IdentifierInfo &Member,
+ IdentifierInfo *Member,
const Selector &Sel,
ASTContext &Context) {
// Check protocols on qualified interfaces.
Decl *GDecl = 0;
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
E = QIdTy->qual_end(); I != E; ++I) {
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
GDecl = PD;
break;
}
@@ -2047,101 +2011,213 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
return GDecl;
}
-/// FindMethodInNestedImplementations - Look up a method in current and
-/// all base class implementations.
-///
-ObjCMethodDecl *Sema::FindMethodInNestedImplementations(
- const ObjCInterfaceDecl *IFace,
- const Selector &Sel) {
- ObjCMethodDecl *Method = 0;
- if (ObjCImplementationDecl *ImpDecl
- = LookupObjCImplementation(IFace->getIdentifier()))
- Method = ImpDecl->getInstanceMethod(Sel);
-
- if (!Method && IFace->getSuperClass())
- return FindMethodInNestedImplementations(IFace->getSuperClass(), Sel);
- return Method;
-}
-
Action::OwningExprResult
-Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
+Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
tok::TokenKind OpKind, SourceLocation MemberLoc,
- IdentifierInfo &Member,
- DeclPtrTy ObjCImpDecl) {
+ DeclarationName MemberName,
+ bool HasExplicitTemplateArgs,
+ SourceLocation LAngleLoc,
+ const TemplateArgument *ExplicitTemplateArgs,
+ unsigned NumExplicitTemplateArgs,
+ SourceLocation RAngleLoc,
+ DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS,
+ NamedDecl *FirstQualifierInScope) {
+ if (SS && SS->isInvalid())
+ return ExprError();
+
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
+
Expr *BaseExpr = Base.takeAs<Expr>();
- assert(BaseExpr && "no record expression");
+ assert(BaseExpr && "no base expression");
// Perform default conversions.
DefaultFunctionArrayConversion(BaseExpr);
QualType BaseType = BaseExpr->getType();
+ // 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;
+ ImpCastExprToType(BaseExpr, BaseType);
+ }
+ }
assert(!BaseType.isNull() && "no type for member expression");
+ // 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.
+ Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
+ }
+ // 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;
+ ImpCastExprToType(BaseExpr, BaseType);
+ }
+
// 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.
if (OpKind == tok::arrow) {
- if (BaseType->isDependentType())
- return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
- BaseExpr, true,
- OpLoc,
- DeclarationName(&Member),
- MemberLoc));
- else if (const PointerType *PT = BaseType->getAsPointerType())
+ if (BaseType->isDependentType()) {
+ NestedNameSpecifier *Qualifier = 0;
+ if (SS) {
+ Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (!FirstQualifierInScope)
+ FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
+ }
+
+ return Owned(CXXUnresolvedMemberExpr::Create(Context, BaseExpr, true,
+ OpLoc, Qualifier,
+ SS? SS->getRange() : SourceRange(),
+ FirstQualifierInScope,
+ MemberName,
+ MemberLoc,
+ HasExplicitTemplateArgs,
+ LAngleLoc,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ RAngleLoc));
+ }
+ else if (const PointerType *PT = BaseType->getAs<PointerType>())
BaseType = PT->getPointeeType();
- else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
- return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc,
- MemberLoc, Member));
+ else if (BaseType->isObjCObjectPointerType())
+ ;
else
return ExprError(Diag(MemberLoc,
diag::err_typecheck_member_reference_arrow)
<< BaseType << BaseExpr->getSourceRange());
- } else {
- if (BaseType->isDependentType()) {
- // Require that the base type isn't a pointer type
+ } else if (BaseType->isDependentType()) {
+ // Require that the base type isn't a pointer type
// (so we'll report an error for)
// T* t;
// t.f;
- //
+ //
// 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.
- const PointerType *PT = BaseType->getAsPointerType();
+ const PointerType *PT = BaseType->getAs<PointerType>();
+
+ if (!PT || (getLangOptions().ObjC1 &&
+ !PT->getPointeeType()->isRecordType())) {
+ NestedNameSpecifier *Qualifier = 0;
+ if (SS) {
+ Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ if (!FirstQualifierInScope)
+ FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
+ }
- if (!PT || (getLangOptions().ObjC1 &&
- !PT->getPointeeType()->isRecordType()))
- return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
- BaseExpr, false,
- OpLoc,
- DeclarationName(&Member),
- MemberLoc));
+ return Owned(CXXUnresolvedMemberExpr::Create(Context,
+ BaseExpr, false,
+ OpLoc,
+ Qualifier,
+ SS? SS->getRange() : SourceRange(),
+ FirstQualifierInScope,
+ MemberName,
+ MemberLoc,
+ HasExplicitTemplateArgs,
+ LAngleLoc,
+ ExplicitTemplateArgs,
+ NumExplicitTemplateArgs,
+ RAngleLoc));
+ }
}
- }
// Handle field access to simple records. This also handles access to fields
// of the ObjC 'id' struct.
- if (const RecordType *RTy = BaseType->getAsRecordType()) {
+ if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
RecordDecl *RDecl = RTy->getDecl();
if (RequireCompleteType(OpLoc, BaseType,
- diag::err_typecheck_incomplete_tag,
- BaseExpr->getSourceRange()))
+ PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseExpr->getSourceRange()))
return ExprError();
+ 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);
+
+ // FIXME: If DC is not computable, we should build a
+ // CXXUnresolvedMemberExpr.
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+ }
+
// The record definition is complete, now make sure the member is valid.
- // FIXME: Qualified name lookup for C++ is a bit more complicated than this.
- LookupResult Result
- = LookupQualifiedName(RDecl, DeclarationName(&Member),
- LookupMemberName, false);
-
- if (!Result)
- return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member)
- << &Member << BaseExpr->getSourceRange());
+ LookupResult Result;
+ LookupQualifiedName(Result, DC, MemberName, LookupMemberName, false);
+
+ if (Result.empty())
+ return ExprError(Diag(MemberLoc, diag::err_no_member)
+ << MemberName << DC << BaseExpr->getSourceRange());
if (Result.isAmbiguous()) {
- DiagnoseAmbiguousLookup(Result, DeclarationName(&Member),
- MemberLoc, BaseExpr->getSourceRange());
+ DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
+ BaseExpr->getSourceRange());
return ExprError();
}
-
- NamedDecl *MemberDecl = Result;
+
+ NamedDecl *MemberDecl = Result.getAsSingleDecl(Context);
+
+ if (SS && SS->isSet()) {
+ TypeDecl* TyD = cast<TypeDecl>(MemberDecl->getDeclContext());
+ QualType BaseTypeCanon
+ = Context.getCanonicalType(BaseType).getUnqualifiedType();
+ QualType MemberTypeCanon
+ = Context.getCanonicalType(Context.getTypeDeclType(TyD));
+
+ if (BaseTypeCanon != MemberTypeCanon &&
+ !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon))
+ return ExprError(Diag(SS->getBeginLoc(),
+ diag::err_not_direct_base_or_virtual)
+ << MemberTypeCanon << BaseTypeCanon);
+ }
// If the decl being referenced had an error, return an error for this
// sub-expr without emitting another error, in order to avoid cascading
@@ -2149,8 +2225,16 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
if (MemberDecl->isInvalidDecl())
return ExprError();
+ 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;
+ }
+
// Check the use of this field
- if (DiagnoseUseOfDecl(MemberDecl, MemberLoc))
+ if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc))
return ExprError();
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
@@ -2161,137 +2245,253 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
BaseExpr, OpLoc);
// Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
- // FIXME: Handle address space modifiers
QualType MemberType = FD->getType();
- if (const ReferenceType *Ref = MemberType->getAsReferenceType())
+ if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>())
MemberType = Ref->getPointeeType();
else {
- unsigned combinedQualifiers =
- MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
- if (FD->isMutable())
- combinedQualifiers &= ~QualType::Const;
- MemberType = MemberType.getQualifiedType(combinedQualifiers);
+ 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);
}
MarkDeclarationReferenced(MemberLoc, FD);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD,
- MemberLoc, MemberType));
+ if (PerformObjectMemberConversion(BaseExpr, FD))
+ return ExprError();
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ FD, MemberLoc, MemberType));
}
-
+
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- Var, MemberLoc,
- Var->getType().getNonReferenceType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Var, MemberLoc,
+ Var->getType().getNonReferenceType()));
}
if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- MemberFn, MemberLoc,
- MemberFn->getType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ MemberFn, MemberLoc,
+ MemberFn->getType()));
+ }
+ if (FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+
+ if (HasExplicitTemplateArgs)
+ return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ FunTmpl, MemberLoc, true,
+ LAngleLoc, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs, RAngleLoc,
+ Context.OverloadTy));
+
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ FunTmpl, MemberLoc,
+ Context.OverloadTy));
}
if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(MemberDecl))
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
- MemberLoc, Context.OverloadTy));
+ = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) {
+ if (HasExplicitTemplateArgs)
+ return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ Ovl, MemberLoc, true,
+ LAngleLoc, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs, RAngleLoc,
+ Context.OverloadTy));
+
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Ovl, MemberLoc, Context.OverloadTy));
+ }
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
- Enum, MemberLoc, Enum->getType()));
+ return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+ Enum, MemberLoc, Enum->getType()));
}
if (isa<TypeDecl>(MemberDecl))
return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
- << DeclarationName(&Member) << int(OpKind == tok::arrow));
+ << MemberName << int(OpKind == tok::arrow));
// 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 '->'.
return ExprError(Diag(MemberLoc,
diag::err_typecheck_member_reference_unknown)
- << DeclarationName(&Member) << int(OpKind == tok::arrow));
+ << MemberName << int(OpKind == tok::arrow));
+ }
+
+ // 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:
+ // 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
+ // type.
+ if (!BaseType->isScalarType())
+ return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
+ << BaseType << BaseExpr->getSourceRange());
+
+ // [...] 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));
+
+ // [...] Furthermore, the two type-names in a pseudo-destructor-name of
+ // the form
+ //
+ // ::[opt] nested-name-specifier[opt] type-name :: ̃ type-name
+ //
+ // shall designate the same scalar type.
+ //
+ // FIXME: DPG can't see any way to trigger this particular clause, so it
+ // isn't checked here.
+
+ // 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,
+ OpKind == tok::arrow,
+ OpLoc,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ MemberName.getCXXNameType(),
+ MemberLoc));
}
// Handle access to Objective-C instance variables, such as "Obj->ivar" and
// (*Obj).ivar.
- if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) {
- ObjCInterfaceDecl *ClassDeclared;
- if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(&Member,
- ClassDeclared)) {
- // 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();
+ if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) ||
+ (OpKind == tok::period && BaseType->isObjCInterfaceType())) {
+ const ObjCObjectPointerType *OPT = BaseType->getAs<ObjCObjectPointerType>();
+ const ObjCInterfaceType *IFaceT =
+ OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>();
+ if (IFaceT) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+
+ ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
+ ObjCInterfaceDecl *ClassDeclared;
+ ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
- // 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>();
- if (ObjCImplementationDecl *IMPD =
- dyn_cast<ObjCImplementationDecl>(ImplDecl))
- ClassOfMethodDecl = IMPD->getClassInterface();
- else if (ObjCCategoryImplDecl* CatImplClass =
- dyn_cast<ObjCCategoryImplDecl>(ImplDecl))
- ClassOfMethodDecl = CatImplClass->getClassInterface();
- }
-
- if (IV->getAccessControl() == ObjCIvarDecl::Private) {
- if (ClassDeclared != IFTy->getDecl() ||
- ClassOfMethodDecl != ClassDeclared)
- Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName();
+ 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();
+
+ // 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>();
+ if (ObjCImplementationDecl *IMPD =
+ dyn_cast<ObjCImplementationDecl>(ImplDecl))
+ ClassOfMethodDecl = IMPD->getClassInterface();
+ else if (ObjCCategoryImplDecl* CatImplClass =
+ dyn_cast<ObjCCategoryImplDecl>(ImplDecl))
+ ClassOfMethodDecl = CatImplClass->getClassInterface();
+ }
+
+ if (IV->getAccessControl() == ObjCIvarDecl::Private) {
+ if (ClassDeclared != IDecl ||
+ ClassOfMethodDecl != ClassDeclared)
+ Diag(MemberLoc, diag::error_private_ivar_access)
+ << IV->getDeclName();
+ } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
+ // @protected
+ Diag(MemberLoc, diag::error_protected_ivar_access)
+ << IV->getDeclName();
}
- // @protected
- else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl))
- Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName();
- }
- return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr,
- OpKind == tok::arrow));
+ return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc, BaseExpr,
+ OpKind == tok::arrow));
+ }
+ return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
+ << IDecl->getDeclName() << MemberName
+ << BaseExpr->getSourceRange());
}
- return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
- << IFTy->getDecl()->getDeclName() << &Member
- << BaseExpr->getSourceRange());
}
+ // Handle properties on 'id' and qualified "id".
+ if (OpKind == tok::period && (BaseType->isObjCIdType() ||
+ BaseType->isObjCQualifiedIdType())) {
+ const ObjCObjectPointerType *QIdTy = BaseType->getAs<ObjCObjectPointerType>();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ // Check protocols on qualified interfaces.
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ 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();
+
+ 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();
+
+ return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
+ OMD->getResultType(),
+ OMD, OpLoc, MemberLoc,
+ NULL, 0));
+ }
+ }
+
+ return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << BaseType);
+ }
// Handle Objective-C property access, which is "Obj.property" where Obj is a
// pointer to a (potentially qualified) interface type.
- const PointerType *PTy;
- const ObjCInterfaceType *IFTy;
- if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) &&
- (IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) {
- ObjCInterfaceDecl *IFace = IFTy->getDecl();
+ const ObjCObjectPointerType *OPT;
+ if (OpKind == tok::period &&
+ (OPT = BaseType->getAsObjCInterfacePointerType())) {
+ const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
+ ObjCInterfaceDecl *IFace = IFaceT->getDecl();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
// Search for a declared property first.
- if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) {
+ if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
QualType ResTy = PD->getType();
- Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
ResTy = Getter->getResultType();
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
MemberLoc, BaseExpr));
}
-
// Check protocols on qualified interfaces.
- for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(),
- E = IFTy->qual_end(); I != E; ++I)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
@@ -2299,27 +2499,32 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
MemberLoc, BaseExpr));
}
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
+ // Check whether we can reference this property.
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ MemberLoc, BaseExpr));
+ }
// If that failed, look for an "implicit" property by seeing if the nullary
// selector is implemented.
// FIXME: The logic for looking up nullary and unary selectors should be
// shared with the code in ActOnInstanceMessage.
- Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
// If this reference is in an @implementation, check for 'private' methods.
if (!Getter)
- Getter = FindMethodInNestedImplementations(IFace, Sel);
+ Getter = IFace->lookupPrivateInstanceMethod(Sel);
// Look through local category implementations associated with the class.
- if (!Getter) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Getter; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
- Getter = ObjCCategoryImpls[i]->getInstanceMethod(Sel);
- }
- }
+ if (!Getter)
+ Getter = IFace->getCategoryInstanceMethod(Sel);
if (Getter) {
// Check if we can reference this property.
if (DiagnoseUseOfDecl(Getter, MemberLoc))
@@ -2327,22 +2532,18 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
}
// 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);
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
// methods.
- Setter = FindMethodInNestedImplementations(IFace, SetterSel);
+ Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
}
// Look through local category implementations associated with the class.
- if (!Setter) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
- Setter = ObjCCategoryImpls[i]->getInstanceMethod(SetterSel);
- }
- }
+ if (!Setter)
+ Setter = IFace->getCategoryInstanceMethod(SetterSel);
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
@@ -2352,107 +2553,31 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
if (Getter)
PType = Getter->getResultType();
- else {
- for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
- E = Setter->param_end(); PI != E; ++PI)
- PType = (*PI)->getType();
- }
+ 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) ObjCKVCRefExpr(Getter, PType,
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
Setter, MemberLoc, BaseExpr));
}
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << &Member << BaseType);
- }
- // Handle properties on qualified "id" protocols.
- const ObjCObjectPointerType *QIdTy;
- if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) {
- // Check protocols on qualified interfaces.
- Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
- 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();
-
- 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();
-
- return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
- OMD->getResultType(),
- OMD, OpLoc, MemberLoc,
- NULL, 0));
- }
- }
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << &Member << BaseType);
+ << MemberName << BaseType);
}
- // Handle properties on ObjC 'Class' types.
- if (OpKind == tok::period && (BaseType == Context.getObjCClassType())) {
- // Also must look for a getter name which uses property syntax.
- 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.
- Setter = FindMethodInNestedImplementations(IFace, SetterSel);
- }
- // Look through local category implementations associated with the class.
- if (!Setter) {
- for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
- if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
- Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel);
- }
- }
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
+ // Handle the following exceptional case (*Obj).isa.
+ if (OpKind == tok::period &&
+ BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
+ MemberName.getAsIdentifierInfo()->isStr("isa"))
+ return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
+ Context.getObjCIdType()));
- if (Getter || Setter) {
- QualType PType;
-
- if (Getter)
- PType = Getter->getResultType();
- else {
- for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
- E = Setter->param_end(); PI != E; ++PI)
- PType = (*PI)->getType();
- }
- // FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCKVCRefExpr(Getter, PType,
- Setter, MemberLoc, BaseExpr));
- }
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << &Member << BaseType);
- }
- }
-
// Handle 'field access' to vectors, such as 'V.xx'.
if (BaseType->isExtVectorType()) {
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc);
if (ret.isNull())
return ExprError();
- return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, Member,
+ return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member,
MemberLoc));
}
@@ -2462,10 +2587,10 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
// If the user is trying to apply -> or . to a function or function
// pointer, it's probably because they forgot parentheses to call
// the function. Suggest the addition of those parentheses.
- if (BaseType == Context.OverloadTy ||
+ if (BaseType == Context.OverloadTy ||
BaseType->isFunctionType() ||
- (BaseType->isPointerType() &&
- BaseType->getAsPointerType()->isFunctionType())) {
+ (BaseType->isPointerType() &&
+ BaseType->getAs<PointerType>()->isFunctionType())) {
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
Diag(Loc, diag::note_member_reference_needs_call)
<< CodeModificationHint::CreateInsertion(Loc, "()");
@@ -2474,6 +2599,63 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return ExprError();
}
+Action::OwningExprResult
+Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) {
+ return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
+ DeclarationName(&Member), ObjCImpDecl, SS);
+}
+
+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();
+ Diag(UnparsedDefaultArgLocs[Param],
+ diag::note_default_argument_declared_here);
+ } else {
+ if (Param->hasUninstantiatedDefaultArg()) {
+ Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
+
+ // Instantiate the expression.
+ MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD);
+
+ InstantiatingTemplate Inst(*this, CallLoc, Param,
+ ArgList.getInnermost().getFlatArgumentList(),
+ ArgList.getInnermost().flat_size());
+
+ OwningExprResult Result = SubstExpr(UninstExpr, ArgList);
+ if (Result.isInvalid())
+ return ExprError();
+
+ if (SetParamDefaultArgument(Param, move(Result),
+ /*FIXME:EqualLoc*/
+ UninstExpr->getSourceRange().getBegin()))
+ return ExprError();
+ }
+
+ Expr *DefaultExpr = Param->getDefaultArg();
+
+ // If the default expression creates temporaries, we need to
+ // push them to the current stack of expression temporaries so they'll
+ // be properly destroyed.
+ if (CXXExprWithTemporaries *E
+ = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) {
+ assert(!E->shouldDestroyTemporaries() &&
+ "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));
+}
+
/// 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
@@ -2529,40 +2711,24 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
ProtoArgType,
- diag::err_call_incomplete_argument,
- Arg->getSourceRange()))
+ PDiag(diag::err_call_incomplete_argument)
+ << Arg->getSourceRange()))
return true;
// Pass the argument.
if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
return true;
} else {
- if (FDecl->getParamDecl(i)->hasUnparsedDefaultArg()) {
- Diag (Call->getSourceRange().getBegin(),
- diag::err_use_of_default_argument_to_function_declared_later) <<
- FDecl << cast<CXXRecordDecl>(FDecl->getDeclContext())->getDeclName();
- Diag(UnparsedDefaultArgLocs[FDecl->getParamDecl(i)],
- diag::note_default_argument_declared_here);
- } else {
- Expr *DefaultExpr = FDecl->getParamDecl(i)->getDefaultArg();
-
- // If the default expression creates temporaries, we need to
- // push them to the current stack of expression temporaries so they'll
- // be properly destroyed.
- if (CXXExprWithTemporaries *E
- = dyn_cast_or_null<CXXExprWithTemporaries>(DefaultExpr)) {
- assert(!E->shouldDestroyTemporaries() &&
- "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.
- Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i));
+ ParmVarDecl *Param = FDecl->getParamDecl(i);
+
+ OwningExprResult ArgExpr =
+ BuildCXXDefaultArgExpr(Call->getSourceRange().getBegin(),
+ FDecl, Param);
+ if (ArgExpr.isInvalid())
+ return true;
+
+ Arg = ArgExpr.takeAs<Expr>();
}
-
- QualType ArgType = Arg->getType();
Call->setArg(i, Arg);
}
@@ -2586,6 +2752,96 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
return Invalid;
}
+/// \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,
+ const TemplateArgument *&ExplicitTemplateArgs,
+ 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 (QualifiedDeclRefExpr *QDRExpr
+ = dyn_cast<QualifiedDeclRefExpr>(FnExpr)) {
+ // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
+ ArgumentDependentLookup = false;
+ Qualifier = QDRExpr->getQualifier();
+ QualifierRange = QDRExpr->getQualifierRange();
+ Function = dyn_cast<NamedDecl>(QDRExpr->getDecl());
+ break;
+ } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
+ Function = dyn_cast<NamedDecl>(DRExpr->getDecl());
+ 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;
+ }
+ }
+}
+
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -2594,6 +2850,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
MultiExprArg args,
SourceLocation *CommaLocs, SourceLocation RParenLoc) {
unsigned NumArgs = args.size();
+
+ // Since this might be a postfix expression, get rid of ParenListExprs.
+ fn = MaybeConvertParenListExprToParenExpr(S, move(fn));
+
Expr *Fn = fn.takeAs<Expr>();
Expr **Args = reinterpret_cast<Expr**>(args.release());
assert(Fn && "no function call expression");
@@ -2602,6 +2862,25 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
DeclarationName UnqualifiedName;
if (getLangOptions().CPlusPlus) {
+ // 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()));
+
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Destroy(Context);
+
+ NumArgs = 0;
+ }
+
+ return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy,
+ RParenLoc));
+ }
+
// Determine whether this is a dependent call inside a C++ template,
// in which case we won't do any semantic analysis now.
// FIXME: Will need to cache the results of name lookup (including ADL) in
@@ -2632,70 +2911,42 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
}
+
+ // 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) {
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(BO->getType());
+ QualType ReturnTy = FPT->getResultType();
+
+ CXXMemberCallExpr *CE =
+ new (Context) CXXMemberCallExpr(Context, BO, Args, NumArgs,
+ ReturnTy.getNonReferenceType(),
+ RParenLoc);
+
+ ExprOwningPtr<CXXMemberCallExpr> TheCall(this, CE);
+
+ if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs,
+ RParenLoc))
+ return ExprError();
+
+ return Owned(MaybeBindToTemporary(TheCall.release()).release());
+ }
+ }
}
// If we're directly calling a function, get the appropriate declaration.
- // Also, in C++, keep track of whether we should perform argument-dependent
+ // Also, in C++, keep track of whether we should perform argument-dependent
// lookup and whether there were any explicitly-specified template arguments.
- Expr *FnExpr = Fn;
bool ADL = true;
bool HasExplicitTemplateArgs = 0;
const TemplateArgument *ExplicitTemplateArgs = 0;
unsigned NumExplicitTemplateArgs = 0;
- 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).
- ADL = 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)) {
- // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
- ADL &= !isa<QualifiedDeclRefExpr>(DRExpr);
- NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
- break;
- } else if (UnresolvedFunctionNameExpr *DepName
- = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
- UnqualifiedName = DepName->getName();
- break;
- } else if (TemplateIdRefExpr *TemplateIdRef
- = dyn_cast<TemplateIdRefExpr>(FnExpr)) {
- NDecl = TemplateIdRef->getTemplateName().getAsTemplateDecl();
- HasExplicitTemplateArgs = 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 (TemplateIdRef->getQualifier())
- ADL = false;
- 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).
- ADL = false;
- break;
- }
- }
+ NestedNameSpecifier *Qualifier = 0;
+ SourceRange QualifierRange;
+ DeconstructCallFunction(Fn, NDecl, UnqualifiedName, Qualifier, QualifierRange,
+ ADL,HasExplicitTemplateArgs, ExplicitTemplateArgs,
+ NumExplicitTemplateArgs);
OverloadedFunctionDecl *Ovl = 0;
FunctionTemplateDecl *FunctionTemplate = 0;
@@ -2708,10 +2959,10 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Ovl = dyn_cast<OverloadedFunctionDecl>(NDecl);
}
- if (Ovl || FunctionTemplate ||
+ if (Ovl || FunctionTemplate ||
(getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
// We don't perform ADL for implicit declarations of builtins.
- if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
+ if (FDecl && FDecl->getBuiltinID() && FDecl->isImplicit())
ADL = false;
// We don't perform ADL in C.
@@ -2719,27 +2970,26 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
ADL = false;
if (Ovl || FunctionTemplate || ADL) {
- FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
+ FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName,
HasExplicitTemplateArgs,
ExplicitTemplateArgs,
NumExplicitTemplateArgs,
- LParenLoc, Args, NumArgs, CommaLocs,
+ LParenLoc, Args, NumArgs, CommaLocs,
RParenLoc, ADL);
if (!FDecl)
return ExprError();
// Update Fn to refer to the actual function selected.
Expr *NewFn = 0;
- if (QualifiedDeclRefExpr *QDRExpr
- = dyn_cast<QualifiedDeclRefExpr>(FnExpr))
+ if (Qualifier)
NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
- QDRExpr->getLocation(),
+ Fn->getLocStart(),
false, false,
- QDRExpr->getQualifierRange(),
- QDRExpr->getQualifier());
+ QualifierRange,
+ Qualifier);
else
NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
- Fn->getSourceRange().getBegin());
+ Fn->getLocStart());
Fn->Destroy(Context);
Fn = NewFn;
}
@@ -2759,25 +3009,23 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
if (!Fn->getType()->isBlockPointerType()) {
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
// have type pointer to function".
- const PointerType *PT = Fn->getType()->getAsPointerType();
+ const PointerType *PT = Fn->getType()->getAs<PointerType>();
if (PT == 0)
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
- FuncT = PT->getPointeeType()->getAsFunctionType();
+ FuncT = PT->getPointeeType()->getAs<FunctionType>();
} else { // This is a block call.
- FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()->
- getAsFunctionType();
+ FuncT = Fn->getType()->getAs<BlockPointerType>()->getPointeeType()->
+ getAs<FunctionType>();
}
if (FuncT == 0)
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
// Check for a valid return type
- if (!FuncT->getResultType()->isVoidType() &&
- RequireCompleteType(Fn->getSourceRange().getBegin(),
- FuncT->getResultType(),
- diag::err_call_incomplete_return,
- TheCall->getSourceRange()))
+ if (CheckCallReturnType(FuncT->getResultType(),
+ Fn->getSourceRange().getBegin(), TheCall.get(),
+ FDecl))
return ExprError();
// We know the result type of the call, set it.
@@ -2796,7 +3044,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
const FunctionDecl *Def = 0;
if (FDecl->getBody(Def) && NumArgs != Def->param_size()) {
const FunctionProtoType *Proto =
- Def->getType()->getAsFunctionProtoType();
+ Def->getType()->getAs<FunctionProtoType>();
if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) {
Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
<< (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
@@ -2810,8 +3058,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
DefaultArgumentPromotion(Arg);
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
Arg->getType(),
- diag::err_call_incomplete_argument,
- Arg->getSourceRange()))
+ PDiag(diag::err_call_incomplete_argument)
+ << Arg->getSourceRange()))
return ExprError();
TheCall->setArg(i, Arg);
}
@@ -2825,20 +3073,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
// Check for sentinels
if (NDecl)
DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs);
+
// Do special checking on direct calls to functions.
- if (FDecl)
- return CheckFunctionCall(FDecl, TheCall.take());
- if (NDecl)
- return CheckBlockCall(NDecl, TheCall.take());
+ if (FDecl) {
+ if (CheckFunctionCall(FDecl, TheCall.get()))
+ return ExprError();
- return Owned(TheCall.take());
+ if (unsigned BuiltinID = FDecl->getBuiltinID())
+ return CheckBuiltinFunctionCall(BuiltinID, TheCall.take());
+ } else if (NDecl) {
+ if (CheckBlockCall(NDecl, TheCall.get()))
+ return ExprError();
+ }
+
+ return MaybeBindToTemporary(TheCall.take());
}
Action::OwningExprResult
Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg InitExpr) {
assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
- QualType literalType = QualType::getFromOpaquePtr(Ty);
+ //FIXME: Preserve type source info.
+ QualType literalType = GetTypeFromParser(Ty);
// FIXME: put back this assert when initializers are worked out.
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
@@ -2849,8 +3105,9 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
<< SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()));
} else if (!literalType->isDependentType() &&
RequireCompleteType(LParenLoc, literalType,
- diag::err_typecheck_decl_incomplete_type,
- SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())))
+ PDiag(diag::err_typecheck_decl_incomplete_type)
+ << SourceRange(LParenLoc,
+ literalExpr->getSourceRange().getEnd())))
return ExprError();
if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
@@ -2883,15 +3140,20 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
}
/// CheckCastTypes - Check type constraints for casting between types.
-bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
- UsualUnaryConversions(castExpr);
+bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
+ CastExpr::CastKind& Kind,
+ CXXMethodDecl *& ConversionDecl,
+ bool FunctionalStyle) {
+ if (getLangOptions().CPlusPlus)
+ return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
+ ConversionDecl);
+
+ DefaultFunctionArrayConversion(castExpr);
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
if (castType->isVoidType()) {
// Cast to void allows any expr type.
- } else if (castType->isDependentType() || castExpr->isTypeDependent()) {
- // We can't check any more until template instantiation time.
} else if (!castType->isScalarType() && !castType->isVectorType()) {
if (Context.getCanonicalType(castType).getUnqualifiedType() ==
Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) &&
@@ -2900,9 +3162,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
// FIXME: Check that the cast destination type is complete.
Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar)
<< castType << castExpr->getSourceRange();
+ Kind = CastExpr::CK_NoOp;
} else if (castType->isUnionType()) {
// GCC cast to union extension
- RecordDecl *RD = castType->getAsRecordType()->getDecl();
+ RecordDecl *RD = castType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator Field, FieldEnd;
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
@@ -2916,6 +3179,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
if (Field == FieldEnd)
return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type)
<< castExpr->getType() << castExpr->getSourceRange();
+ Kind = CastExpr::CK_ToUnion;
} else {
// Reject any other conversions to non-scalar types.
return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
@@ -2974,7 +3238,7 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) {
bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
-
+
// If SrcTy is a VectorType, the total size must match to explicitly cast to
// an ExtVectorType.
if (SrcTy->isVectorType()) {
@@ -2995,20 +3259,104 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType SrcTy) {
}
Action::OwningExprResult
-Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg Op) {
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+
assert((Ty != 0) && (Op.get() != 0) &&
"ActOnCastExpr(): missing type or expr");
- Expr *castExpr = Op.takeAs<Expr>();
- QualType castType = QualType::getFromOpaquePtr(Ty);
+ Expr *castExpr = (Expr *)Op.get();
+ //FIXME: Preserve type source info.
+ QualType castType = GetTypeFromParser(Ty);
- if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr))
+ // If the Expr being casted is a ParenListExpr, handle it specially.
+ if (isa<ParenListExpr>(castExpr))
+ return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType);
+ CXXMethodDecl *Method = 0;
+ if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr,
+ Kind, Method))
return ExprError();
- return Owned(new (Context) CStyleCastExpr(castType, castExpr, castType,
+
+ if (Method) {
+ OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind,
+ Method, move(Op));
+
+ if (CastArg.isInvalid())
+ return ExprError();
+
+ castExpr = CastArg.takeAs<Expr>();
+ } else {
+ Op.release();
+ }
+
+ return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(),
+ Kind, castExpr, castType,
LParenLoc, RParenLoc));
}
+/// 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);
+
+ OwningExprResult Result(*this, E->getExpr(0));
+
+ 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)));
+
+ 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();
+
+ // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')'
+ // 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();
+ InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0],
+ initExprs.size(), RParenLoc);
+ E->setType(Ty);
+ return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,
+ Owned(E));
+ } else {
+ // This is not an AltiVec-style cast, so turn the ParenListExpr into a
+ // 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);
+}
+
/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension.
/// In that case, lhs = cond.
/// C99 6.5.15
@@ -3033,6 +3381,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
}
// Now check the two expressions.
+ if (LHSTy->isVectorType() || RHSTy->isVectorType())
+ return CheckVectorOperands(QuestionLoc, LHS, RHS);
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
@@ -3043,8 +3393,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// If both operands are the same structure or union type, the result is that
// type.
- if (const RecordType *LHSRT = LHSTy->getAsRecordType()) { // C99 6.5.15p3
- if (const RecordType *RHSRT = RHSTy->getAsRecordType())
+ if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3
+ if (const RecordType *RHSRT = RHSTy->getAs<RecordType>())
if (LHSRT->getDecl() == RHSRT->getDecl())
// "If both the operands have structure or union type, the result has
// that type." This implies that CV qualifiers are dropped.
@@ -3067,24 +3417,46 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
}
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
// the type of the other operand."
- if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() ||
- Context.isObjCObjectPointerType(LHSTy)) &&
- RHS->isNullPointerConstant(Context)) {
+ if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) &&
+ RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer.
return LHSTy;
}
- if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() ||
- Context.isObjCObjectPointerType(RHSTy)) &&
- LHS->isNullPointerConstant(Context)) {
+ if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) &&
+ LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
return RHSTy;
}
+ // 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)) {
+ ImpCastExprToType(RHS, LHSTy);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCClassType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy);
+ return RHSTy;
+ }
+ // And the same for struct objc_object* / id
+ if (LHSTy->isObjCIdType() &&
+ (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(RHS, LHSTy);
+ return LHSTy;
+ }
+ if (RHSTy->isObjCIdType() &&
+ (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+ ImpCastExprToType(LHS, RHSTy);
+ return RHSTy;
+ }
// 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);
- ImpCastExprToType(LHS, destType);
+ ImpCastExprToType(LHS, destType);
ImpCastExprToType(RHS, destType);
return destType;
}
@@ -3098,8 +3470,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
return LHSTy;
}
// The block pointer types aren't identical, continue checking.
- QualType lhptee = LHSTy->getAsBlockPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsBlockPointerType()->getPointeeType();
+ QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
@@ -3118,48 +3490,17 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, LHSTy);
return LHSTy;
}
- // Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type
- // evaluates to "struct objc_object *" (and is handled above when comparing
- // id with statically typed objects).
- if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) {
- // 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.
- if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) ||
- (LHSTy->isObjCQualifiedIdType() &&
- Context.isObjCObjectPointerType(RHSTy)) ||
- (RHSTy->isObjCQualifiedIdType() &&
- Context.isObjCObjectPointerType(LHSTy))) {
- // FIXME: This is not the correct composite type. This only happens to
- // work because id can more or less be used anywhere, however this may
- // change the type of method sends.
-
- // FIXME: gcc adds some type-checking of the arguments and emits
- // (confusing) incompatible comparison warnings in some
- // cases. Investigate.
- QualType compositeType = Context.getObjCIdType();
- ImpCastExprToType(LHS, compositeType);
- ImpCastExprToType(RHS, compositeType);
- return compositeType;
- }
- }
// Check constraints for Objective-C object pointers types.
- if (Context.isObjCObjectPointerType(LHSTy) &&
- Context.isObjCObjectPointerType(RHSTy)) {
-
+ if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) {
+
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
// Two identical object pointer types are always compatible.
return LHSTy;
}
- // No need to check for block pointer types or qualified id types (they
- // were handled above).
- assert((LHSTy->isPointerType() && RHSTy->isPointerType()) &&
- "Sema::CheckConditionalOperands(): Unexpected type");
- QualType lhptee = LHSTy->getAsPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsPointerType()->getPointeeType();
-
+ const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>();
QualType compositeType = LHSTy;
-
+
// If both operands are interfaces and either operand can be
// assigned to the other, use that type as the composite
// type. This allows
@@ -3173,16 +3514,19 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// FIXME: Consider unifying with 'areComparableObjCPointerTypes'.
// It could return the composite type.
- const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType();
- const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType();
- if (LHSIface && RHSIface &&
- Context.canAssignObjCInterfaces(LHSIface, RHSIface)) {
- compositeType = LHSTy;
- } else if (LHSIface && RHSIface &&
- Context.canAssignObjCInterfaces(RHSIface, LHSIface)) {
- compositeType = RHSTy;
- } else if (Context.isObjCIdStructType(lhptee) ||
- Context.isObjCIdStructType(rhptee)) {
+ if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) {
+ compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
+ } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
+ compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
+ } else if ((LHSTy->isObjCQualifiedIdType() ||
+ RHSTy->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+ // Need to handle "id<xx>" explicitly.
+ // 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()) {
compositeType = Context.getObjCIdType();
} else {
Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
@@ -3198,23 +3542,46 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, compositeType);
return compositeType;
}
+ // Check Objective-C object pointer types and 'void *'
+ if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) {
+ QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType destPointee
+ = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(LHS, destType); // add qualifiers if necessary
+ ImpCastExprToType(RHS, destType); // promote to void*
+ return destType;
+ }
+ if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
+ QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType destPointee
+ = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(RHS, destType); // add qualifiers if necessary
+ ImpCastExprToType(LHS, destType); // promote to void*
+ return destType;
+ }
// Check constraints for C object pointers types (C99 6.5.15p3,6).
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
// get the "pointed to" types
- QualType lhptee = LHSTy->getAsPointerType()->getPointeeType();
- QualType rhptee = RHSTy->getAsPointerType()->getPointeeType();
+ QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
// Figure out necessary qualifiers (C99 6.5.15p6)
- QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers());
+ QualType destPointee
+ = Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
ImpCastExprToType(LHS, destType); // add qualifiers if necessary
ImpCastExprToType(RHS, destType); // promote to void*
return destType;
}
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
- QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers());
+ QualType destPointee
+ = Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
ImpCastExprToType(LHS, destType); // add qualifiers if necessary
ImpCastExprToType(RHS, destType); // promote to void*
@@ -3248,7 +3615,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
ImpCastExprToType(RHS, LHSTy);
return LHSTy;
}
-
+
// GCC compatibility: soften pointer/integer mismatch.
if (RHSTy->isPointerType() && LHSTy->isIntegerType()) {
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
@@ -3292,12 +3659,11 @@ Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
Cond.release();
LHS.release();
RHS.release();
- return Owned(new (Context) ConditionalOperator(CondExpr,
+ return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc,
isLHSNull ? 0 : LHSExpr,
- RHSExpr, result));
+ ColonLoc, RHSExpr, result));
}
-
// CheckPointerTypesForAssignment - This is a very tricky routine (despite
// being closely modeled after the C99 spec:-). The odd characteristic of this
// routine is it effectively iqnores the qualifiers on the top level pointee.
@@ -3307,9 +3673,16 @@ Sema::AssignConvertType
Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
QualType lhptee, rhptee;
+ if ((lhsType->isObjCClassType() &&
+ (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+ (rhsType->isObjCClassType() &&
+ (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+ return Compatible;
+ }
+
// get the "pointed to" type (ignoring qualifiers at the top level)
- lhptee = lhsType->getAsPointerType()->getPointeeType();
- rhptee = rhsType->getAsPointerType()->getPointeeType();
+ lhptee = lhsType->getAs<PointerType>()->getPointeeType();
+ rhptee = rhsType->getAs<PointerType>()->getPointeeType();
// make sure we operate on the canonical type
lhptee = Context.getCanonicalType(lhptee);
@@ -3371,7 +3744,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
return IncompatiblePointerSign;
}
// General pointer incompatibility takes priority over qualifiers.
- return IncompatiblePointer;
+ return IncompatiblePointer;
}
return ConvTy;
}
@@ -3386,8 +3759,8 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
QualType lhptee, rhptee;
// get the "pointed to" type (ignoring qualifiers at the top level)
- lhptee = lhsType->getAsBlockPointerType()->getPointeeType();
- rhptee = rhsType->getAsBlockPointerType()->getPointeeType();
+ lhptee = lhsType->getAs<BlockPointerType>()->getPointeeType();
+ rhptee = rhsType->getAs<BlockPointerType>()->getPointeeType();
// make sure we operate on the canonical type
lhptee = Context.getCanonicalType(lhptee);
@@ -3430,6 +3803,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (lhsType == rhsType)
return Compatible; // Common case: fast path an exact match.
+ if ((lhsType->isObjCClassType() &&
+ (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+ (rhsType->isObjCClassType() &&
+ (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+ return Compatible;
+ }
+
// 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,
@@ -3437,23 +3817,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
// right-hand side type. The caller is responsible for adjusting
// lhsType so that the resulting expression does not have reference
// type.
- if (const ReferenceType *lhsTypeRef = lhsType->getAsReferenceType()) {
+ if (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) {
if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType))
return Compatible;
return Incompatible;
}
-
- if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
- if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
- return Compatible;
- // Relax integer conversions like we do for pointers below.
- if (rhsType->isIntegerType())
- return IntToPointer;
- if (lhsType->isIntegerType())
- return PointerToInt;
- return IncompatibleObjCQualifiedId;
- }
-
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
// to the same ExtVector type.
if (lhsType->isExtVectorType()) {
@@ -3462,7 +3830,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (!rhsType->isVectorType() && rhsType->isArithmeticType())
return Compatible;
}
-
+
if (lhsType->isVectorType() || rhsType->isVectorType()) {
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a bitcast;
@@ -3485,13 +3853,18 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
if (isa<PointerType>(rhsType))
return CheckPointerTypesForAssignment(lhsType, rhsType);
- if (rhsType->getAsBlockPointerType()) {
- if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<ObjCObjectPointerType>(rhsType)) {
+ if (lhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (rhsType->getAs<BlockPointerType>()) {
+ if (lhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
return Compatible;
// Treat block pointers as objects.
- if (getLangOptions().ObjC1 &&
- lhsType == Context.getCanonicalType(Context.getObjCIdType()))
+ if (getLangOptions().ObjC1 && lhsType->isObjCIdType())
return Compatible;
}
return Incompatible;
@@ -3502,20 +3875,47 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return IntToBlockPointer;
// Treat block pointers as objects.
- if (getLangOptions().ObjC1 &&
- rhsType == Context.getCanonicalType(Context.getObjCIdType()))
+ if (getLangOptions().ObjC1 && rhsType->isObjCIdType())
return Compatible;
if (rhsType->isBlockPointerType())
return CheckBlockPointerTypesForAssignment(lhsType, rhsType);
- if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
+ if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
if (RHSPT->getPointeeType()->isVoidType())
return Compatible;
}
return Incompatible;
}
+ if (isa<ObjCObjectPointerType>(lhsType)) {
+ if (rhsType->isIntegerType())
+ return IntToPointer;
+
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<PointerType>(rhsType)) {
+ if (rhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (rhsType->isObjCObjectPointerType()) {
+ if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType())
+ return Compatible;
+ if (Context.typesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
+ return IncompatibleObjCQualifiedId;
+ return IncompatiblePointer;
+ }
+ if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) {
+ if (RHSPT->getPointeeType()->isVoidType())
+ return Compatible;
+ }
+ // Treat block pointers as objects.
+ if (rhsType->isBlockPointerType())
+ return Compatible;
+ return Incompatible;
+ }
if (isa<PointerType>(rhsType)) {
// C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
if (lhsType == Context.BoolTy)
@@ -3528,7 +3928,26 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
return CheckPointerTypesForAssignment(lhsType, rhsType);
if (isa<BlockPointerType>(lhsType) &&
- rhsType->getAsPointerType()->getPointeeType()->isVoidType())
+ rhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
+ return Compatible;
+ return Incompatible;
+ }
+ 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;
+
+ // In general, C pointers are not compatible with ObjC object pointers.
+ if (isa<PointerType>(lhsType)) {
+ if (lhsType->isVoidPointerType()) // an exception to the rule.
+ return Compatible;
+ return IncompatiblePointer;
+ }
+ if (isa<BlockPointerType>(lhsType) &&
+ rhsType->getAs<PointerType>()->getPointeeType()->isVoidType())
return Compatible;
return Incompatible;
}
@@ -3542,7 +3961,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
/// \brief Constructs a transparent union from an expression that is
/// used to initialize the transparent union.
-static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
+static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
QualType UnionType, FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
@@ -3562,7 +3981,7 @@ Sema::AssignConvertType
Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
QualType FromType = rExpr->getType();
- // If the ArgType is a Union type, we want to handle a potential
+ // If the ArgType is a Union type, we want to handle a potential
// transparent_union GCC extension.
const RecordType *UT = ArgType->getAsUnionType();
if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
@@ -3580,13 +3999,14 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
// 1) void pointer
// 2) null pointer constant
if (FromType->isPointerType())
- if (FromType->getAsPointerType()->getPointeeType()->isVoidType()) {
+ if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
ImpCastExprToType(rExpr, it->getType());
InitField = *it;
break;
}
-
- if (rExpr->isNullPointerConstant(Context)) {
+
+ if (rExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(rExpr, it->getType());
InitField = *it;
break;
@@ -3626,10 +4046,11 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
- if ((lhsType->isPointerType() ||
- lhsType->isObjCQualifiedIdType() ||
+ if ((lhsType->isPointerType() ||
+ lhsType->isObjCObjectPointerType() ||
lhsType->isBlockPointerType())
- && rExpr->isNullPointerConstant(Context)) {
+ && rExpr->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
ImpCastExprToType(rExpr, lhsType);
return Compatible;
}
@@ -3681,8 +4102,8 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
// type. It would be nice if we only had one vector type someday.
if (getLangOptions().LaxVectorConversions) {
// FIXME: Should we warn here?
- if (const VectorType *LV = lhsType->getAsVectorType()) {
- if (const VectorType *RV = rhsType->getAsVectorType())
+ if (const VectorType *LV = lhsType->getAs<VectorType>()) {
+ if (const VectorType *RV = rhsType->getAs<VectorType>())
if (LV->getElementType() == RV->getElementType() &&
LV->getNumElements() == RV->getNumElements()) {
return lhsType->isExtVectorType() ? lhsType : rhsType;
@@ -3698,9 +4119,9 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
std::swap(rex, lex);
std::swap(rhsType, lhsType);
}
-
+
// Handle the case of an ext vector and scalar.
- if (const ExtVectorType *LV = lhsType->getAsExtVectorType()) {
+ if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) {
QualType EltTy = LV->getElementType();
if (EltTy->isIntegralType() && rhsType->isIntegralType()) {
if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) {
@@ -3718,7 +4139,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
}
}
}
-
+
// Vectors of different size or scalar and non-ext-vector are errors.
Diag(Loc, diag::err_typecheck_vector_not_convertable)
<< lex->getType() << rex->getType()
@@ -3727,8 +4148,7 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
}
inline QualType Sema::CheckMultiplyDivideOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
@@ -3740,8 +4160,7 @@ inline QualType Sema::CheckMultiplyDivideOperands(
}
inline QualType Sema::CheckRemainderOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
return CheckVectorOperands(Loc, lex, rex);
@@ -3756,8 +4175,7 @@ inline QualType Sema::CheckRemainderOperands(
}
inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
QualType compType = CheckVectorOperands(Loc, lex, rex);
if (CompLHSTy) *CompLHSTy = compType;
@@ -3775,12 +4193,14 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
// Put any potential pointer into PExp
Expr* PExp = lex, *IExp = rex;
- if (IExp->getType()->isPointerType())
+ if (IExp->getType()->isAnyPointerType())
std::swap(PExp, IExp);
- if (const PointerType *PTy = PExp->getType()->getAsPointerType()) {
+ if (PExp->getType()->isAnyPointerType()) {
+
if (IExp->getType()->isIntegerType()) {
- QualType PointeeTy = PTy->getPointeeType();
+ QualType PointeeTy = PExp->getType()->getPointeeType();
+
// Check for arithmetic on pointers to incomplete types.
if (PointeeTy->isVoidType()) {
if (getLangOptions().CPlusPlus) {
@@ -3802,30 +4222,31 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
// GNU extension: arithmetic on pointer to function
Diag(Loc, diag::ext_gnu_ptr_func_arith)
<< lex->getType() << lex->getSourceRange();
- } else if (!PTy->isDependentType() &&
- RequireCompleteType(Loc, PointeeTy,
- diag::err_typecheck_arithmetic_incomplete_type,
- PExp->getSourceRange(), SourceRange(),
- PExp->getType()))
- return QualType();
-
+ } else {
+ // Check if we require a complete type.
+ if (((PExp->getType()->isPointerType() &&
+ !PExp->getType()->isDependentType()) ||
+ PExp->getType()->isObjCObjectPointerType()) &&
+ RequireCompleteType(Loc, PointeeTy,
+ PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PExp->getSourceRange()
+ << PExp->getType()))
+ return QualType();
+ }
// 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();
}
-
+
if (CompLHSTy) {
- QualType LHSTy = lex->getType();
- if (LHSTy->isPromotableIntegerType())
- LHSTy = Context.IntTy;
- else {
- QualType T = isPromotableBitField(lex, Context);
- if (!T.isNull())
- LHSTy = T;
+ QualType LHSTy = Context.isPromotableBitField(lex);
+ if (LHSTy.isNull()) {
+ LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
}
-
*CompLHSTy = LHSTy;
}
return PExp->getType();
@@ -3856,8 +4277,8 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
}
// Either ptr - int or ptr - ptr.
- if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
- QualType lpointee = LHSPTy->getPointeeType();
+ if (lex->getType()->isAnyPointerType()) {
+ QualType lpointee = lex->getType()->getPointeeType();
// The LHS must be an completely-defined object type.
@@ -3882,11 +4303,10 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
// GNU C extension: arithmetic on pointer to function
ComplainAboutFunc = lex;
} else if (!lpointee->isDependentType() &&
- RequireCompleteType(Loc, lpointee,
- diag::err_typecheck_sub_ptr_object,
- lex->getSourceRange(),
- SourceRange(),
- lex->getType()))
+ RequireCompleteType(Loc, lpointee,
+ PDiag(diag::err_typecheck_sub_ptr_object)
+ << lex->getSourceRange()
+ << lex->getType()))
return QualType();
// Diagnose bad cases where we step over interface counts.
@@ -3895,7 +4315,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lpointee << lex->getSourceRange();
return QualType();
}
-
+
// The result type of a pointer-int computation is the pointer type.
if (rex->getType()->isIntegerType()) {
if (ComplainAboutVoid)
@@ -3903,7 +4323,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lex->getSourceRange() << rex->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
+ << ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
if (CompLHSTy) *CompLHSTy = lex->getType();
@@ -3911,7 +4331,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
}
// Handle pointer-pointer subtractions.
- if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) {
+ if (const PointerType *RHSPTy = rex->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
// RHS must be a completely-type object type.
@@ -3936,10 +4356,9 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
ComplainAboutFunc = rex;
} else if (!rpointee->isDependentType() &&
RequireCompleteType(Loc, rpointee,
- diag::err_typecheck_sub_ptr_object,
- rex->getSourceRange(),
- SourceRange(),
- rex->getType()))
+ PDiag(diag::err_typecheck_sub_ptr_object)
+ << rex->getSourceRange()
+ << rex->getType()))
return QualType();
if (getLangOptions().CPlusPlus) {
@@ -3967,7 +4386,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
<< lex->getSourceRange() << rex->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
+ << ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
if (CompLHSTy) *CompLHSTy = lex->getType();
@@ -3987,19 +4406,32 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
- QualType LHSTy;
- if (lex->getType()->isPromotableIntegerType())
- LHSTy = Context.IntTy;
- else {
- LHSTy = isPromotableBitField(lex, Context);
- if (LHSTy.isNull())
- LHSTy = lex->getType();
+ QualType LHSTy = Context.isPromotableBitField(lex);
+ if (LHSTy.isNull()) {
+ LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
}
if (!isCompAssign)
ImpCastExprToType(lex, LHSTy);
UsualUnaryConversions(rex);
+ // Sanity-check shift operands
+ llvm::APSInt Right;
+ // Check right/shifter operand
+ if (!rex->isValueDependent() &&
+ rex->isIntegerConstantExpr(Right, Context)) {
+ if (Right.isNegative())
+ 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();
+ }
+ }
+
// "The type of the result is that of the promoted left operand."
return LHSTy;
}
@@ -4027,7 +4459,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// 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.
- // NOTE: Don't warn about comparisons of enum constants. These can arise
+ // NOTE: Don't warn about comparisons of enum constants. These can arise
// from macro expansions, and are usually quite deliberate.
Expr *LHSStripped = lex->IgnoreParens();
Expr *RHSStripped = rex->IgnoreParens();
@@ -4036,24 +4468,25 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (DRL->getDecl() == DRR->getDecl() &&
!isa<EnumConstantDecl>(DRL->getDecl()))
Diag(Loc, diag::warn_selfcomparison);
-
+
if (isa<CastExpr>(LHSStripped))
LHSStripped = LHSStripped->IgnoreParenCasts();
if (isa<CastExpr>(RHSStripped))
RHSStripped = RHSStripped->IgnoreParenCasts();
-
+
// Warn about comparisons against a string constant (unless the other
// operand is null), the user probably wants strcmp.
Expr *literalString = 0;
Expr *literalStringStripped = 0;
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
- !RHSStripped->isNullPointerConstant(Context)) {
+ !RHSStripped->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
literalString = lex;
literalStringStripped = LHSStripped;
- }
- else if ((isa<StringLiteral>(RHSStripped) ||
- isa<ObjCEncodeExpr>(RHSStripped)) &&
- !LHSStripped->isNullPointerConstant(Context)) {
+ } else if ((isa<StringLiteral>(RHSStripped) ||
+ isa<ObjCEncodeExpr>(RHSStripped)) &&
+ !LHSStripped->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull)) {
literalString = rex;
literalStringStripped = RHSStripped;
}
@@ -4098,41 +4531,31 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return ResultTy;
}
- bool LHSIsNull = lex->isNullPointerConstant(Context);
- bool RHSIsNull = rex->isNullPointerConstant(Context);
+ bool LHSIsNull = lex->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull);
+ bool RHSIsNull = rex->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull);
// 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).
if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2
QualType LCanPointeeTy =
- Context.getCanonicalType(lType->getAsPointerType()->getPointeeType());
+ Context.getCanonicalType(lType->getAs<PointerType>()->getPointeeType());
QualType RCanPointeeTy =
- Context.getCanonicalType(rType->getAsPointerType()->getPointeeType());
-
- if (rType->isFunctionPointerType() || lType->isFunctionPointerType()) {
- if (isRelational) {
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- }
- }
- if (((!LHSIsNull || isRelational) && LCanPointeeTy->isVoidType()) !=
- ((!RHSIsNull || isRelational) && RCanPointeeTy->isVoidType())) {
- Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- }
- // Simple check: if the pointee types are identical, we're done.
- if (LCanPointeeTy == RCanPointeeTy)
- return ResultTy;
+ Context.getCanonicalType(rType->getAs<PointerType>()->getPointeeType());
if (getLangOptions().CPlusPlus) {
+ if (LCanPointeeTy == RCanPointeeTy)
+ return ResultTy;
+
// 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. [...]
//
- // C++ [expr.eq]p2 uses the same notion for (in)equality
+ // C++ [expr.eq]p1 uses the same notion for (in)equality
// comparisons of pointers.
QualType T = FindCompositePointerType(lex, rex);
if (T.isNull()) {
@@ -4145,36 +4568,82 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
ImpCastExprToType(rex, T);
return ResultTy;
}
-
- if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2
- !LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() &&
- !Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
- RCanPointeeTy.getUnqualifiedType()) &&
- !Context.areComparableObjCPointerTypes(lType, rType)) {
+ // 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
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
}
- ImpCastExprToType(rex, lType); // promote the pointer to pointer
+ if (LCanPointeeTy != RCanPointeeTy)
+ ImpCastExprToType(rex, lType); // promote the pointer to pointer
return ResultTy;
}
- // C++ allows comparison of pointers with null pointer constants.
+
if (getLangOptions().CPlusPlus) {
- if (lType->isPointerType() && RHSIsNull) {
- ImpCastExprToType(rex, lType);
+ // Comparison of pointers with null pointer constants and equality
+ // comparisons of member pointers to null pointer constants.
+ if (RHSIsNull &&
+ (lType->isPointerType() ||
+ (!isRelational && lType->isMemberPointerType()))) {
+ ImpCastExprToType(rex, lType, CastExpr::CK_NullToMemberPointer);
+ return ResultTy;
+ }
+ if (LHSIsNull &&
+ (rType->isPointerType() ||
+ (!isRelational && rType->isMemberPointerType()))) {
+ ImpCastExprToType(lex, rType, CastExpr::CK_NullToMemberPointer);
return ResultTy;
}
- if (rType->isPointerType() && LHSIsNull) {
- ImpCastExprToType(lex, rType);
+
+ // Comparison of member pointers.
+ if (!isRelational &&
+ lType->isMemberPointerType() && rType->isMemberPointerType()) {
+ // C++ [expr.eq]p2:
+ // 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
+ // 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();
+ }
+
+ ImpCastExprToType(lex, T);
+ ImpCastExprToType(rex, T);
return ResultTy;
}
- // And comparison of nullptr_t with itself.
+
+ // Comparison of nullptr_t with itself.
if (lType->isNullPtrType() && rType->isNullPtrType())
return ResultTy;
}
+
// Handle block pointer types.
if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) {
- QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
- QualType rpointee = rType->getAsBlockPointerType()->getPointeeType();
+ QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType();
+ QualType rpointee = rType->getAs<BlockPointerType>()->getPointeeType();
if (!LHSIsNull && !RHSIsNull &&
!Context.typesAreCompatible(lpointee, rpointee)) {
@@ -4189,9 +4658,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
&& ((lType->isBlockPointerType() && rType->isPointerType())
|| (lType->isPointerType() && rType->isBlockPointerType()))) {
if (!LHSIsNull && !RHSIsNull) {
- if (!((rType->isPointerType() && rType->getAsPointerType()
+ if (!((rType->isPointerType() && rType->getAs<PointerType>()
->getPointeeType()->isVoidType())
- || (lType->isPointerType() && lType->getAsPointerType()
+ || (lType->isPointerType() && lType->getAs<PointerType>()
->getPointeeType()->isVoidType())))
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
@@ -4200,10 +4669,10 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return ResultTy;
}
- if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
+ if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) {
if (lType->isPointerType() || rType->isPointerType()) {
- const PointerType *LPT = lType->getAsPointerType();
- const PointerType *RPT = rType->getAsPointerType();
+ const PointerType *LPT = lType->getAs<PointerType>();
+ const PointerType *RPT = rType->getAs<PointerType>();
bool LPtrToVoid = LPT ?
Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false;
bool RPtrToVoid = RPT ?
@@ -4213,43 +4682,49 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
!Context.typesAreCompatible(lType, rType)) {
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
- ImpCastExprToType(rex, lType);
- return ResultTy;
}
ImpCastExprToType(rex, lType);
return ResultTy;
}
- if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
+ if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) {
+ if (!Context.areComparableObjCPointerTypes(lType, rType))
+ Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
+ << lType << rType << lex->getSourceRange() << rex->getSourceRange();
ImpCastExprToType(rex, lType);
return ResultTy;
- } else {
- if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) {
- Diag(Loc, diag::warn_incompatible_qualified_id_operands)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- ImpCastExprToType(rex, lType);
- return ResultTy;
- }
}
}
- if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) &&
- rType->isIntegerType()) {
- if (isRelational)
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- else if (!RHSIsNull)
- Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
+ if (lType->isAnyPointerType() && rType->isIntegerType()) {
+ 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;
+
+ if (DiagID) {
+ Diag(Loc, DiagID)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
ImpCastExprToType(rex, lType); // promote the integer to pointer
return ResultTy;
}
- if (lType->isIntegerType() &&
- (rType->isPointerType() || rType->isObjCQualifiedIdType())) {
- if (isRelational)
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- else if (!LHSIsNull)
- Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer)
+ if (lType->isIntegerType() && rType->isAnyPointerType()) {
+ 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;
+
+ if (DiagID) {
+ Diag(Loc, DiagID)
<< lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ }
ImpCastExprToType(lex, rType); // promote the integer to pointer
return ResultTy;
}
@@ -4299,21 +4774,13 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
CheckFloatComparison(Loc,lex,rex);
}
- // FIXME: Vector compare support in the LLVM backend is not fully reliable,
- // just reject all vector comparisons for now.
- if (1) {
- Diag(Loc, diag::err_typecheck_vector_comparison)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- return QualType();
- }
-
// 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;
- const VectorType *VTy = lType->getAsVectorType();
+ const VectorType *VTy = lType->getAs<VectorType>();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (TypeSize == Context.getTypeSize(Context.IntTy))
return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
@@ -4326,8 +4793,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
}
inline QualType Sema::CheckBitwiseOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
@@ -4339,8 +4805,7 @@ inline QualType Sema::CheckBitwiseOperands(
}
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
- Expr *&lex, Expr *&rex, SourceLocation Loc)
-{
+ Expr *&lex, Expr *&rex, SourceLocation Loc) {
UsualUnaryConversions(lex);
UsualUnaryConversions(rex);
@@ -4353,18 +4818,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
/// is a read-only property; return true if so. A readonly property expression
/// depends on various declarations and thus must be treated specially.
///
-static bool IsReadonlyProperty(Expr *E, Sema &S)
-{
+static bool IsReadonlyProperty(Expr *E, Sema &S) {
if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
QualType BaseType = PropExpr->getBase()->getType();
- if (const PointerType *PTy = BaseType->getAsPointerType())
- if (const ObjCInterfaceType *IFTy =
- PTy->getPointeeType()->getAsObjCInterfaceType())
- if (ObjCInterfaceDecl *IFace = IFTy->getDecl())
- if (S.isPropertyReadonly(PDecl, IFace))
- return true;
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAsObjCInterfacePointerType())
+ if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
+ if (S.isPropertyReadonly(PDecl, IFace))
+ return true;
}
}
return false;
@@ -4374,7 +4837,7 @@ static bool IsReadonlyProperty(Expr *E, Sema &S)
/// emit an error and return true. If so, return false.
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
SourceLocation OrigLoc = Loc;
- Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
+ Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
&Loc);
if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
IsLV = Expr::MLV_ReadonlyProperty;
@@ -4403,8 +4866,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_IncompleteType:
case Expr::MLV_IncompleteVoidType:
return S.RequireCompleteType(Loc, E->getType(),
- diag::err_typecheck_incomplete_type_not_modifiable_lvalue,
- E->getSourceRange());
+ PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue)
+ << E->getSourceRange());
case Expr::MLV_DuplicateVectorComponents:
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
break;
@@ -4425,7 +4888,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
if (NeedType)
S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign;
else
- S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
return true;
}
@@ -4449,9 +4912,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
// Special case of NSObject attributes on c-style pointer types.
if (ConvTy == IncompatiblePointer &&
((Context.isObjCNSObjectType(LHSType) &&
- Context.isObjCObjectPointerType(RHSType)) ||
+ RHSType->isObjCObjectPointerType()) ||
(Context.isObjCNSObjectType(RHSType) &&
- Context.isObjCObjectPointerType(LHSType))))
+ LHSType->isObjCObjectPointerType())))
ConvTy = Compatible;
// If the RHS is a unary plus or minus, check to see if they = and + are
@@ -4525,9 +4988,11 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
} else if (ResType->isRealType()) {
// OK!
- } else if (const PointerType *PT = ResType->getAsPointerType()) {
+ } else if (ResType->isAnyPointerType()) {
+ QualType PointeeTy = ResType->getPointeeType();
+
// C99 6.5.2.4p2, 6.5.6p2
- if (PT->getPointeeType()->isVoidType()) {
+ if (PointeeTy->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
<< Op->getSourceRange();
@@ -4536,7 +5001,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
// Pointer to void is a GNU extension in C.
Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
- } else if (PT->getPointeeType()->isFunctionType()) {
+ } else if (PointeeTy->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
<< Op->getType() << Op->getSourceRange();
@@ -4545,11 +5010,17 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
<< ResType << Op->getSourceRange();
- } else if (RequireCompleteType(OpLoc, PT->getPointeeType(),
- diag::err_typecheck_arithmetic_incomplete_type,
- Op->getSourceRange(), SourceRange(),
- ResType))
+ } else if (RequireCompleteType(OpLoc, PointeeTy,
+ PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << Op->getSourceRange()
+ << ResType))
return QualType();
+ // 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();
+ }
} else if (ResType->isComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
Diag(OpLoc, diag::ext_integer_increment_complex)
@@ -4672,6 +5143,15 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
Diag(OpLoc, diag::err_typecheck_address_of)
<< "vector element" << op->getSourceRange();
return QualType();
+ } 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();
+ } else if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(op)) {
+ // FIXME: Can LHS ever be null here?
+ if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull())
+ return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc);
} else if (dcl) { // C99 6.5.3.2p1
// We have an lvalue with a decl. Make sure the decl is not declared
// with the register storage-class specifier.
@@ -4681,17 +5161,26 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
<< "register variable" << op->getSourceRange();
return QualType();
}
- } else if (isa<OverloadedFunctionDecl>(dcl)) {
+ } else if (isa<OverloadedFunctionDecl>(dcl) ||
+ isa<FunctionTemplateDecl>(dcl)) {
return Context.OverloadTy;
- } else if (isa<FieldDecl>(dcl)) {
+ } else if (FieldDecl *FD = dyn_cast<FieldDecl>(dcl)) {
// Okay: we can take the address of a field.
// Could be a pointer to member, though, if there is an explicit
// scope qualifier for the class.
if (isa<QualifiedDeclRefExpr>(op)) {
DeclContext *Ctx = dcl->getDeclContext();
- if (Ctx && Ctx->isRecord())
+ if (Ctx && Ctx->isRecord()) {
+ if (FD->getType()->isReferenceType()) {
+ Diag(OpLoc,
+ diag::err_cannot_form_pointer_to_member_of_reference_type)
+ << FD->getDeclName() << FD->getType();
+ return QualType();
+ }
+
return Context.getMemberPointerType(op->getType(),
Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
+ }
}
} else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) {
// Okay: we can take the address of a function.
@@ -4725,9 +5214,12 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) {
// incomplete type or void. It would be possible to warn about dereferencing
// a void pointer, but it's completely well-defined, and such a warning is
// unlikely to catch any mistakes.
- if (const PointerType *PT = Ty->getAsPointerType())
+ if (const PointerType *PT = Ty->getAs<PointerType>())
return PT->getPointeeType();
+ if (const ObjCObjectPointerType *OPT = Ty->getAs<ObjCObjectPointerType>())
+ return OPT->getPointeeType();
+
Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer)
<< Ty << Op->getSourceRange();
return QualType();
@@ -4914,7 +5406,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
if (getLangOptions().CPlusPlus &&
- (lhs->getType()->isOverloadableType() ||
+ (lhs->getType()->isOverloadableType() ||
rhs->getType()->isOverloadableType())) {
// Find all of the overloaded operators visible from this
// point. We perform both an operator-name lookup from the local
@@ -4926,7 +5418,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
Functions);
Expr *Args[2] = { lhs, rhs };
- DeclarationName OpName
+ DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, Args, 2, Functions);
}
@@ -4941,7 +5433,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
}
Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
- unsigned OpcIn,
+ unsigned OpcIn,
ExprArg InputArg) {
UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
@@ -4949,16 +5441,17 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Expr *Input = (Expr *)InputArg.get();
QualType resultType;
switch (Opc) {
- case UnaryOperator::PostInc:
- case UnaryOperator::PostDec:
case UnaryOperator::OffsetOf:
assert(false && "Invalid unary operator");
break;
case UnaryOperator::PreInc:
case UnaryOperator::PreDec:
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
resultType = CheckIncrementDecrementOperand(Input, OpLoc,
- Opc == UnaryOperator::PreInc);
+ Opc == UnaryOperator::PreInc ||
+ Opc == UnaryOperator::PostInc);
break;
case UnaryOperator::AddrOf:
resultType = CheckAddressOfOperand(Input, OpLoc);
@@ -5043,7 +5536,7 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
if (OverOp != OO_None) {
LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
Functions);
- DeclarationName OpName
+ DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, &Input, 1, Functions);
}
@@ -5116,7 +5609,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
SourceLocation RPLoc) {
// FIXME: This function leaks all expressions in the offset components on
// error.
- QualType ArgTy = QualType::getFromOpaquePtr(argty);
+ // FIXME: Preserve type source info.
+ QualType ArgTy = GetTypeFromParser(argty);
assert(!ArgTy.isNull() && "Missing type argument!");
bool Dependent = ArgTy->isDependentType();
@@ -5147,7 +5641,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
if (!Dependent) {
bool DidWarnAboutNonPOD = false;
-
+
// FIXME: Dependent case loses a lot of information here. And probably
// leaks like a sieve.
for (unsigned i = 0; i != NumComponents; ++i) {
@@ -5180,7 +5674,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
continue;
}
- const RecordType *RC = Res->getType()->getAsRecordType();
+ const RecordType *RC = Res->getType()->getAs<RecordType>();
if (!RC) {
Res->Destroy(Context);
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
@@ -5197,15 +5691,16 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
DidWarnAboutNonPOD = true;
}
}
-
+
+ LookupResult R;
+ LookupQualifiedName(R, RD, OC.U.IdentInfo, LookupMemberName);
+
FieldDecl *MemberDecl
- = dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo,
- LookupMemberName)
- .getAsDecl());
+ = dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context));
// FIXME: Leaks Res
if (!MemberDecl)
- return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member)
- << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd));
+ return ExprError(Diag(BuiltinLoc, diag::err_no_member)
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
// FIXME: C++: Verify that MemberDecl isn't a static field.
// FIXME: Verify that MemberDecl isn't a bitfield.
@@ -5229,8 +5724,9 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
TypeTy *arg1,TypeTy *arg2,
SourceLocation RPLoc) {
- QualType argT1 = QualType::getFromOpaquePtr(arg1);
- QualType argT2 = QualType::getFromOpaquePtr(arg2);
+ // FIXME: Preserve type source info.
+ QualType argT1 = GetTypeFromParser(arg1);
+ QualType argT2 = GetTypeFromParser(arg2);
assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)");
@@ -5255,8 +5751,10 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
QualType resType;
+ bool ValueDependent = false;
if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
resType = Context.DependentTy;
+ ValueDependent = true;
} else {
// The conditional expression is required to be a constant expression.
llvm::APSInt condEval(32);
@@ -5268,11 +5766,15 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
// If the condition is > zero, then the AST type is the same as the LSHExpr.
resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType();
+ ValueDependent = condEval.getZExtValue() ? LHSExpr->isValueDependent()
+ : RHSExpr->isValueDependent();
}
cond.release(); expr1.release(); expr2.release();
return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
- resType, RPLoc));
+ resType, RPLoc,
+ resType->isDependentType(),
+ ValueDependent));
}
//===----------------------------------------------------------------------===//
@@ -5291,6 +5793,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
BSI->ReturnType = QualType();
BSI->TheScope = BlockScope;
BSI->hasBlockDeclRefExprs = false;
+ BSI->hasPrototype = false;
BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
CurFunctionNeedsScopeChecking = false;
@@ -5320,12 +5823,12 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
CurBlock->isVariadic = false;
// Check for a valid sentinel attribute on this block.
if (CurBlock->TheDecl->getAttr<SentinelAttr>()) {
- Diag(ParamInfo.getAttributes()->getLoc(),
+ Diag(ParamInfo.getAttributes()->getLoc(),
diag::warn_attribute_sentinel_not_variadic) << 1;
// FIXME: remove the attribute.
}
- QualType RetTy = T.getTypePtr()->getAsFunctionType()->getResultType();
-
+ QualType RetTy = T.getTypePtr()->getAs<FunctionType>()->getResultType();
+
// Do not allow returning a objc interface by-value.
if (RetTy->isObjCInterfaceType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
@@ -5367,17 +5870,17 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
PushOnScopeChains(*AI, CurBlock->TheScope);
// Check for a valid sentinel attribute on this block.
- if (!CurBlock->isVariadic &&
+ if (!CurBlock->isVariadic &&
CurBlock->TheDecl->getAttr<SentinelAttr>()) {
- Diag(ParamInfo.getAttributes()->getLoc(),
+ Diag(ParamInfo.getAttributes()->getLoc(),
diag::warn_attribute_sentinel_not_variadic) << 1;
// FIXME: remove the attribute.
}
-
+
// Analyze the return type.
QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
- QualType RetTy = T->getAsFunctionType()->getResultType();
-
+ QualType RetTy = T->getAs<FunctionType>()->getResultType();
+
// Do not allow returning a objc interface by-value.
if (RetTy->isObjCInterfaceType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
@@ -5407,7 +5910,7 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
Diag(CaretLoc, diag::err_blocks_disable);
-
+
// Ensure that CurBlock is deleted.
llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
@@ -5424,12 +5927,15 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
ArgTypes.push_back(BSI->Params[i]->getType());
+ bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>();
QualType BlockTy;
if (!BSI->hasPrototype)
- BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0);
+ BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
+ NoReturn);
else
BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
- BSI->isVariadic, 0);
+ BSI->isVariadic, 0, false, false, 0, 0,
+ NoReturn);
// FIXME: Check that return/parameter types are complete/non-abstract
DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
@@ -5439,8 +5945,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (CurFunctionNeedsScopeChecking)
DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get()));
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
-
+
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
+ CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody());
return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs));
}
@@ -5448,10 +5955,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
ExprArg expr, TypeTy *type,
SourceLocation RPLoc) {
- QualType T = QualType::getFromOpaquePtr(type);
+ QualType T = GetTypeFromParser(type);
Expr *E = static_cast<Expr*>(expr.get());
Expr *OrigExpr = E;
-
+
InitBuiltinVaListType();
// Get the va_list type
@@ -5466,7 +5973,7 @@ Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
} else {
// Otherwise, the va_list argument must be an l-value because
// it is modified by va_arg.
- if (!E->isTypeDependent() &&
+ if (!E->isTypeDependent() &&
CheckForModifiableLvalue(E, BuiltinLoc, *this))
return ExprError();
}
@@ -5600,17 +6107,17 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
return false;
}
-Sema::ExpressionEvaluationContext
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
+Sema::ExpressionEvaluationContext
+Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
// Introduce a new set of potentially referenced declarations to the stack.
if (NewContext == PotentiallyPotentiallyEvaluated)
PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls());
-
+
std::swap(ExprEvalContext, NewContext);
return NewContext;
}
-void
+void
Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
ExpressionEvaluationContext NewContext) {
ExprEvalContext = NewContext;
@@ -5622,7 +6129,7 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
PotentiallyReferencedDecls RemainingDecls;
RemainingDecls.swap(PotentiallyReferencedDeclStack.back());
PotentiallyReferencedDeclStack.pop_back();
-
+
for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(),
IEnd = RemainingDecls.end();
I != IEnd; ++I)
@@ -5642,30 +6149,33 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
/// \param D the declaration that has been referenced by the source code.
void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
assert(D && "No declaration?");
-
+
if (D->isUsed())
return;
-
- // Mark a parameter declaration "used", regardless of whether we're in a
- // template or not.
- if (isa<ParmVarDecl>(D))
+
+ // 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()))
D->setUsed(true);
-
+
// Do not mark anything as "used" within a dependent context; wait for
// an instantiation.
if (CurContext->isDependentContext())
return;
-
+
switch (ExprEvalContext) {
case Unevaluated:
// We are in an expression that is not potentially evaluated; do nothing.
return;
-
+
case PotentiallyEvaluated:
// We are in a potentially-evaluated expression, so this declaration is
// "used"; handle this below.
break;
-
+
case PotentiallyPotentiallyEvaluated:
// We are in an expression that may be potentially evaluated; queue this
// declaration reference until we know whether the expression is
@@ -5673,23 +6183,22 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D));
return;
}
-
+
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
unsigned TypeQuals;
if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
if (!Constructor->isUsed())
DefineImplicitDefaultConstructor(Loc, Constructor);
- }
- else if (Constructor->isImplicit() &&
- Constructor->isCopyConstructor(Context, TypeQuals)) {
+ } else if (Constructor->isImplicit() &&
+ Constructor->isCopyConstructor(Context, TypeQuals)) {
if (!Constructor->isUsed())
DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
}
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
if (Destructor->isImplicit() && !Destructor->isUsed())
DefineImplicitDestructor(Loc, Destructor);
-
+
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
@@ -5698,28 +6207,125 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- // Implicit instantiation of function templates and member functions of
+ // Implicit instantiation of function templates and member functions of
// class templates.
- if (!Function->getBody()) {
- // FIXME: distinguish between implicit instantiations of function
- // templates and explicit specializations (the latter don't get
- // instantiated, naturally).
- if (Function->getInstantiatedFromMemberFunction() ||
- Function->getPrimaryTemplate())
+ if (!Function->getBody() &&
+ Function->getTemplateSpecializationKind()
+ == TSK_ImplicitInstantiation) {
+ bool AlreadyInstantiated = false;
+ if (FunctionTemplateSpecializationInfo *SpecInfo
+ = Function->getTemplateSpecializationInfo()) {
+ if (SpecInfo->getPointOfInstantiation().isInvalid())
+ SpecInfo->setPointOfInstantiation(Loc);
+ else
+ AlreadyInstantiated = true;
+ } else if (MemberSpecializationInfo *MSInfo
+ = Function->getMemberSpecializationInfo()) {
+ if (MSInfo->getPointOfInstantiation().isInvalid())
+ MSInfo->setPointOfInstantiation(Loc);
+ else
+ AlreadyInstantiated = true;
+ }
+
+ if (!AlreadyInstantiated)
PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc));
}
-
// FIXME: keep track of references to static functions
Function->setUsed(true);
return;
}
-
+
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
- (void)Var;
- // FIXME: implicit template instantiation
+ // Implicit instantiation of static data members of class templates.
+ if (Var->isStaticDataMember() &&
+ 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));
+ }
+ }
+
// FIXME: keep track of references to static data?
+
D->setUsed(true);
+ return;
+ }
+}
+
+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;
+}
+
+// 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;
+
+ if (isa<BinaryOperator>(E)) {
+ BinaryOperator *Op = cast<BinaryOperator>(E);
+ if (Op->getOpcode() != BinaryOperator::Assign)
+ return;
+
+ 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();
+ SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
+
+ Diag(Loc, diag::warn_condition_is_assignment)
+ << 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;
+}