aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r--lib/Sema/SemaExpr.cpp2769
1 files changed, 777 insertions, 1992 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0549e9499560..5efc36559d97 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -87,7 +87,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
Diag(Loc, diag::err_deleted_function_use);
- Diag(D->getLocation(), diag::note_unavailable_here) << true;
+ Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true;
return true;
}
}
@@ -104,17 +104,20 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
break;
case AR_Unavailable:
- if (Message.empty()) {
- if (!UnknownObjCClass)
- Diag(Loc, diag::err_unavailable) << D->getDeclName();
- else
- Diag(Loc, diag::warn_unavailable_fwdclass_message)
- << D->getDeclName();
+ if (cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) {
+ if (Message.empty()) {
+ if (!UnknownObjCClass)
+ Diag(Loc, diag::err_unavailable) << D->getDeclName();
+ else
+ Diag(Loc, diag::warn_unavailable_fwdclass_message)
+ << D->getDeclName();
+ }
+ else
+ Diag(Loc, diag::err_unavailable_message)
+ << D->getDeclName() << Message;
+ Diag(D->getLocation(), diag::note_unavailable_here)
+ << isa<FunctionDecl>(D) << false;
}
- else
- Diag(Loc, diag::err_unavailable_message)
- << D->getDeclName() << Message;
- Diag(D->getLocation(), diag::note_unavailable_here) << 0;
break;
}
@@ -437,8 +440,12 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
/// will warn if the resulting type is not a POD type, and rejects ObjC
/// interfaces passed by value.
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
- FunctionDecl *FDecl) {
- ExprResult ExprRes = DefaultArgumentPromotion(E);
+ FunctionDecl *FDecl) {
+ ExprResult ExprRes = CheckPlaceholderExpr(E);
+ if (ExprRes.isInvalid())
+ return ExprError();
+
+ ExprRes = DefaultArgumentPromotion(E);
if (ExprRes.isInvalid())
return ExprError();
E = ExprRes.take();
@@ -456,7 +463,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
<< E->getType() << CT))
return ExprError();
- if (!E->getType()->isPODType()) {
+ if (!E->getType().isPODType(Context)) {
// C++0x [expr.call]p7:
// Passing a potentially-evaluated argument of class type (Clause 9)
// having a non-trivial copy constructor, a non-trivial move constructor,
@@ -471,6 +478,11 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
TrivialEnough = true;
}
}
+
+ if (!TrivialEnough &&
+ getLangOptions().ObjCAutoRefCount &&
+ E->getType()->isObjCLifetimeType())
+ TrivialEnough = true;
if (TrivialEnough) {
// Nothing to diagnose. This is okay.
@@ -1004,7 +1016,6 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
return Owned(StringLiteral::Create(Context, Literal.GetString(),
- Literal.GetStringLength(),
Literal.AnyWide, Literal.Pascal, StrTy,
&StringTokLocs[0],
StringTokLocs.size()));
@@ -1271,125 +1282,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
return Owned(E);
}
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo);
-
-ExprResult
-Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
- SourceLocation loc,
- IndirectFieldDecl *indirectField,
- Expr *baseObjectExpr,
- SourceLocation opLoc) {
- // First, build the expression that refers to the base object.
-
- bool baseObjectIsPointer = false;
- Qualifiers baseQuals;
-
- // Case 1: the base of the indirect field is not a field.
- VarDecl *baseVariable = indirectField->getVarDecl();
- CXXScopeSpec EmptySS;
- if (baseVariable) {
- assert(baseVariable->getType()->isRecordType());
-
- // In principle we could have a member access expression that
- // accesses an anonymous struct/union that's a static member of
- // the base object's class. However, under the current standard,
- // static data members cannot be anonymous structs or unions.
- // Supporting this is as easy as building a MemberExpr here.
- assert(!baseObjectExpr && "anonymous struct/union is static data member?");
-
- DeclarationNameInfo baseNameInfo(DeclarationName(), loc);
-
- ExprResult result =
- BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
- if (result.isInvalid()) return ExprError();
-
- baseObjectExpr = result.take();
- baseObjectIsPointer = false;
- baseQuals = baseObjectExpr->getType().getQualifiers();
-
- // Case 2: the base of the indirect field is a field and the user
- // wrote a member expression.
- } 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 *ptr = objectType->getAs<PointerType>()) {
- baseObjectIsPointer = true;
- objectType = ptr->getPointeeType();
- } else {
- baseObjectIsPointer = false;
- }
- baseQuals = objectType.getQualifiers();
-
- // Case 3: the base of the indirect field is a field and we should
- // build an implicit member access.
- } 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".
- QualType ThisTy = getAndCaptureCurrentThisType();
- if (ThisTy.isNull()) {
- Diag(loc, diag::err_invalid_member_use_in_static_method)
- << indirectField->getDeclName();
- return ExprError();
- }
-
- // Our base object expression is "this".
- baseObjectExpr =
- new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
- baseObjectIsPointer = true;
- baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
- }
-
- // Build the implicit member references to the field of the
- // anonymous struct/union.
- Expr *result = baseObjectExpr;
- IndirectFieldDecl::chain_iterator
- FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
-
- // Build the first member access in the chain with full information.
- if (!baseVariable) {
- FieldDecl *field = cast<FieldDecl>(*FI);
-
- // FIXME: use the real found-decl info!
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
- // Make a nameInfo that properly uses the anonymous name.
- DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
-
- result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
- EmptySS, field, foundDecl,
- memberNameInfo).take();
- baseObjectIsPointer = false;
-
- // FIXME: check qualified member access
- }
-
- // In all cases, we should now skip the first declaration in the chain.
- ++FI;
-
- while (FI != FEnd) {
- FieldDecl *field = cast<FieldDecl>(*FI++);
-
- // FIXME: these are somewhat meaningless
- DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
- DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess());
-
- result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
- (FI == FEnd? SS : EmptySS), field,
- foundDecl, memberNameInfo)
- .take();
- }
-
- return Owned(result);
-}
-
/// Decomposes the given name into a DeclarationNameInfo, its location, and
/// possibly a list of template arguments.
///
@@ -1399,215 +1291,30 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
/// This actually loses a lot of source location information for
/// non-standard name kinds; we should consider preserving that in
/// some way.
-static void DecomposeUnqualifiedId(Sema &SemaRef,
- const UnqualifiedId &Id,
- TemplateArgumentListInfo &Buffer,
- DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *&TemplateArgs) {
+void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
+ TemplateArgumentListInfo &Buffer,
+ DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *&TemplateArgs) {
if (Id.getKind() == UnqualifiedId::IK_TemplateId) {
Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(SemaRef,
+ ASTTemplateArgsPtr TemplateArgsPtr(*this,
Id.TemplateId->getTemplateArgs(),
Id.TemplateId->NumArgs);
- SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer);
+ translateTemplateArguments(TemplateArgsPtr, Buffer);
TemplateArgsPtr.release();
TemplateName TName = Id.TemplateId->Template.get();
SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc;
- NameInfo = SemaRef.Context.getNameForTemplate(TName, TNameLoc);
+ NameInfo = Context.getNameForTemplate(TName, TNameLoc);
TemplateArgs = &Buffer;
} else {
- NameInfo = SemaRef.GetNameFromUnqualifiedId(Id);
+ NameInfo = GetNameFromUnqualifiedId(Id);
TemplateArgs = 0;
}
}
-/// Determines if the given class is provably not derived from all of
-/// the prospective base classes.
-static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
- CXXRecordDecl *Record,
- const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
- if (Bases.count(Record->getCanonicalDecl()))
- return false;
-
- RecordDecl *RD = Record->getDefinition();
- if (!RD) return false;
- Record = cast<CXXRecordDecl>(RD);
-
- for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
- E = Record->bases_end(); I != E; ++I) {
- CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
- CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
- if (!BaseRT) return false;
-
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
- return false;
- }
-
- return true;
-}
-
-enum IMAKind {
- /// The reference is definitely not an instance member access.
- IMA_Static,
-
- /// The reference may be an implicit instance member access.
- IMA_Mixed,
-
- /// The reference may be to an instance member, but it is invalid if
- /// so, because the context is not an instance method.
- IMA_Mixed_StaticContext,
-
- /// The reference may be to an instance member, but it is invalid if
- /// so, because the context is from an unrelated class.
- IMA_Mixed_Unrelated,
-
- /// The reference is definitely an implicit instance member access.
- IMA_Instance,
-
- /// The reference may be to an unresolved using declaration.
- IMA_Unresolved,
-
- /// The reference may be to an unresolved using declaration and the
- /// context is not an instance method.
- IMA_Unresolved_StaticContext,
-
- /// All possible referrents are instance members and the current
- /// context is not an instance method.
- IMA_Error_StaticContext,
-
- /// All possible referrents are instance members of an unrelated
- /// class.
- IMA_Error_Unrelated
-};
-
-/// The given lookup names class member(s) and is not being used for
-/// an address-of-member expression. Classify the type of access
-/// according to whether it's possible that this reference names an
-/// instance member. This is best-effort; it is okay to
-/// conservatively answer "yes", in which case some errors will simply
-/// not be caught until template-instantiation.
-static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
- Scope *CurScope,
- const LookupResult &R) {
- assert(!R.empty() && (*R.begin())->isCXXClassMember());
-
- DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
-
- bool isStaticContext =
- (!isa<CXXMethodDecl>(DC) ||
- cast<CXXMethodDecl>(DC)->isStatic());
-
- // C++0x [expr.prim]p4:
- // Otherwise, if a member-declarator declares a non-static data member
- // of a class X, the expression this is a prvalue of type "pointer to X"
- // within the optional brace-or-equal-initializer.
- if (CurScope->getFlags() & Scope::ThisScope)
- isStaticContext = false;
-
- if (R.isUnresolvableResult())
- return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
-
- // Collect all the declaring classes of instance members we find.
- bool hasNonInstance = false;
- bool hasField = false;
- llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = *I;
-
- if (D->isCXXInstanceMember()) {
- if (dyn_cast<FieldDecl>(D))
- hasField = true;
-
- CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
- Classes.insert(R->getCanonicalDecl());
- }
- else
- hasNonInstance = true;
- }
-
- // If we didn't find any instance members, it can't be an implicit
- // member reference.
- if (Classes.empty())
- return IMA_Static;
-
- // If the current context is not an instance method, it can't be
- // an implicit member reference.
- if (isStaticContext) {
- if (hasNonInstance)
- return IMA_Mixed_StaticContext;
-
- if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
- // C++0x [expr.prim.general]p10:
- // An id-expression that denotes a non-static data member or non-static
- // member function of a class can only be used:
- // (...)
- // - if that id-expression denotes a non-static data member and it appears in an unevaluated operand.
- const Sema::ExpressionEvaluationContextRecord& record = SemaRef.ExprEvalContexts.back();
- bool isUnevaluatedExpression = record.Context == Sema::Unevaluated;
- if (isUnevaluatedExpression)
- return IMA_Mixed_StaticContext;
- }
-
- return IMA_Error_StaticContext;
- }
-
- CXXRecordDecl *contextClass;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
- contextClass = MD->getParent()->getCanonicalDecl();
- else
- contextClass = cast<CXXRecordDecl>(DC);
-
- // [class.mfct.non-static]p3:
- // ...is used in the body of a non-static member function of class X,
- // if name lookup (3.4.1) resolves the name in the id-expression to a
- // non-static non-type member of some class C [...]
- // ...if C is not X or a base class of X, the class member access expression
- // is ill-formed.
- if (R.getNamingClass() &&
- contextClass != R.getNamingClass()->getCanonicalDecl() &&
- contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
-
- // If we can prove that the current context is unrelated to all the
- // declaring classes, it can't be an implicit member reference (in
- // which case it's an error if any of those members are selected).
- if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
-
- return (hasNonInstance ? IMA_Mixed : IMA_Instance);
-}
-
-/// Diagnose a reference to a field with no object available.
-static void DiagnoseInstanceReference(Sema &SemaRef,
- const CXXScopeSpec &SS,
- NamedDecl *rep,
- const DeclarationNameInfo &nameInfo) {
- SourceLocation Loc = nameInfo.getLoc();
- SourceRange Range(Loc);
- if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
-
- if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
- if (MD->isStatic()) {
- // "invalid use of member 'x' in static member function"
- SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
- << Range << nameInfo.getName();
- return;
- }
- }
-
- SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
- << nameInfo.getName() << Range;
- return;
- }
-
- SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
-}
-
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
@@ -1690,39 +1397,43 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
}
// We didn't find anything, so try to correct for a typo.
- DeclarationName Corrected;
- if (S && (Corrected = CorrectTypo(R, S, &SS, 0, false, CTC))) {
- if (!R.empty()) {
- if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
+ TypoCorrection Corrected;
+ if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
+ S, &SS, NULL, false, CTC))) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ R.setLookupName(Corrected.getCorrection());
+
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ R.addDecl(ND);
+ if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ if (ND)
Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
+ << CorrectedQuotedStr;
// Tell the callee to try to recover.
return false;
}
- if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
+ if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) {
// FIXME: If we ended up with a typo for a type name or
// Objective-C class name, we're in trouble because the parser
// is in the wrong place to recover. Suggest the typo
// correction, but don't make it a fix-it since we're not going
// to recover well anyway.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange();
// Don't try to recover; it won't work.
@@ -1732,15 +1443,15 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// FIXME: We found a keyword. Suggest it, but don't provide a fix-it
// because we aren't able to recover.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected;
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << Corrected
+ << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange();
return true;
}
- R.clear();
}
+ R.clear();
// Emit a special diagnostic for failed member lookups.
// FIXME: computing the declaration context might fail here (?)
@@ -1856,7 +1567,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// Decompose the UnqualifiedId into the following data.
DeclarationNameInfo NameInfo;
const TemplateArgumentListInfo *TemplateArgs;
- DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, NameInfo, TemplateArgs);
+ DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs);
DeclarationName Name = NameInfo.getName();
IdentifierInfo *II = Name.getAsIdentifierInfo();
@@ -1892,7 +1603,9 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
bool IvarLookupFollowUp = false;
// Perform the required lookup.
- LookupResult R(*this, NameInfo, LookupOrdinaryName);
+ LookupResult R(*this, NameInfo,
+ (Id.getKind() == UnqualifiedId::IK_ImplicitSelfParam)
+ ? LookupObjCImplicitSelfParam : LookupOrdinaryName);
if (TemplateArgs) {
// Lookup the template name again to correctly establish the context in
// which it was found. This is really unfortunate as we already did the
@@ -2032,38 +1745,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
return BuildDeclarationNameExpr(SS, R, ADL);
}
-/// Builds an expression which might be an implicit member expression.
-ExprResult
-Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
- switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
- case IMA_Instance:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
-
- case IMA_Mixed:
- case IMA_Mixed_Unrelated:
- case IMA_Unresolved:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
-
- case IMA_Static:
- case IMA_Mixed_StaticContext:
- case IMA_Unresolved_StaticContext:
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
- return BuildDeclarationNameExpr(SS, R, false);
-
- case IMA_Error_StaticContext:
- case IMA_Error_Unrelated:
- DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
- R.getLookupNameInfo());
- return ExprError();
- }
-
- llvm_unreachable("unexpected instance member access kind");
- return ExprError();
-}
-
/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified
/// declaration name, generally during template instantiation.
/// There's a large number of things which don't need to be done along
@@ -2155,6 +1836,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
IdentifierInfo &II = Context.Idents.get("self");
UnqualifiedId SelfName;
SelfName.setIdentifier(&II, SourceLocation());
+ SelfName.setKind(UnqualifiedId::IK_ImplicitSelfParam);
CXXScopeSpec SelfScopeSpec;
ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
SelfName, false, false);
@@ -2166,27 +1848,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
return ExprError();
MarkDeclarationReferenced(Loc, IV);
- Expr *base = SelfExpr.take();
- base = base->IgnoreParenImpCasts();
- if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(base)) {
- const NamedDecl *ND = DE->getDecl();
- if (!isa<ImplicitParamDecl>(ND)) {
- // relax the rule such that it is allowed to have a shadow 'self'
- // where stand-alone ivar can be found in this 'self' object.
- // This is to match gcc's behavior.
- ObjCInterfaceDecl *selfIFace = 0;
- if (const ObjCObjectPointerType *OPT =
- base->getType()->getAsObjCInterfacePointerType())
- selfIFace = OPT->getInterfaceDecl();
- if (!selfIFace ||
- !selfIFace->lookupInstanceVariable(IV->getIdentifier())) {
- Diag(Loc, diag::error_implicit_ivar_access)
- << IV->getDeclName();
- Diag(ND->getLocation(), diag::note_declared_at);
- return ExprError();
- }
- }
- }
return Owned(new (Context)
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.take(), true, true));
@@ -2385,120 +2046,6 @@ Sema::PerformObjectMemberConversion(Expr *From,
VK, &BasePath);
}
-/// \brief Build a MemberExpr AST node.
-static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
- const CXXScopeSpec &SS, ValueDecl *Member,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo,
- QualType Ty,
- ExprValueKind VK, ExprObjectKind OK,
- const TemplateArgumentListInfo *TemplateArgs = 0) {
- return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
- Member, FoundDecl, MemberNameInfo,
- TemplateArgs, Ty, VK, OK);
-}
-
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- const CXXScopeSpec &SS, FieldDecl *Field,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo) {
- // x.a is an l-value if 'a' has a reference type. Otherwise:
- // x.a is an l-value/x-value/pr-value if the base is (and note
- // that *x is always an l-value), except that if the base isn't
- // an ordinary object then we must have an rvalue.
- ExprValueKind VK = VK_LValue;
- ExprObjectKind OK = OK_Ordinary;
- if (!IsArrow) {
- if (BaseExpr->getObjectKind() == OK_Ordinary)
- VK = BaseExpr->getValueKind();
- else
- VK = VK_RValue;
- }
- if (VK != VK_RValue && Field->isBitField())
- OK = OK_BitField;
-
- // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
- QualType MemberType = Field->getType();
- if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
- MemberType = Ref->getPointeeType();
- VK = VK_LValue;
- } else {
- QualType BaseType = BaseExpr->getType();
- if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
-
- Qualifiers BaseQuals = BaseType.getQualifiers();
-
- // GC attributes are never picked up by members.
- BaseQuals.removeObjCGCAttr();
-
- // CVR attributes from the base are picked up by members,
- // except that 'mutable' members don't pick up 'const'.
- if (Field->isMutable()) BaseQuals.removeConst();
-
- Qualifiers MemberQuals
- = S.Context.getCanonicalType(MemberType).getQualifiers();
-
- // TR 18037 does not allow fields to be declared with address spaces.
- assert(!MemberQuals.hasAddressSpace());
-
- Qualifiers Combined = BaseQuals + MemberQuals;
- if (Combined != MemberQuals)
- MemberType = S.Context.getQualifiedType(MemberType, Combined);
- }
-
- S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
- ExprResult Base =
- S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
- FoundDecl, Field);
- if (Base.isInvalid())
- return ExprError();
- return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
- Field, FoundDecl, MemberNameInfo,
- MemberType, VK, OK));
-}
-
-/// Builds an implicit member access expression. The current context
-/// is known to be an instance method, and the given unqualified lookup
-/// set is known to contain only instance members, at least one of which
-/// is from an appropriate type.
-ExprResult
-Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool IsKnownInstance) {
- assert(!R.empty() && !R.isAmbiguous());
-
- SourceLocation loc = R.getNameLoc();
-
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- // FIXME: template-ids inside anonymous structs?
- if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>())
- return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD);
-
- // If this is known to be an instance access, go ahead and build an
- // implicit 'this' expression now.
- // 'this' expression now.
- QualType ThisTy = getAndCaptureCurrentThisType();
- assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
-
- Expr *baseExpr = 0; // null signifies implicit access
- if (IsKnownInstance) {
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
- }
-
- return BuildMemberReferenceExpr(baseExpr, ThisTy,
- /*OpLoc*/ SourceLocation(),
- /*IsArrow*/ true,
- SS,
- /*FirstQualifierInScope*/ 0,
- R, TemplateArgs);
-}
-
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
const LookupResult &R,
bool HasTrailingLParen) {
@@ -3160,6 +2707,20 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
Op->getSourceRange(), ExprKind))
return true;
+ if (ExprKind == UETT_SizeOf) {
+ if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(Op->IgnoreParens())) {
+ if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) {
+ QualType OType = PVD->getOriginalType();
+ QualType Type = PVD->getType();
+ if (Type->isPointerType() && OType->isArrayType()) {
+ Diag(Op->getExprLoc(), diag::warn_sizeof_array_param)
+ << Type << OType;
+ Diag(PVD->getLocation(), diag::note_declared_at);
+ }
+ }
+ }
+ }
+
return false;
}
@@ -3274,6 +2835,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind) {
+ ExprResult PE = CheckPlaceholderExpr(E);
+ if (PE.isInvalid())
+ return ExprError();
+
+ E = PE.get();
+
// Verify that the operand is valid.
bool isInvalid = false;
if (E->isTypeDependent()) {
@@ -3285,10 +2852,6 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
} else if (E->getBitField()) { // C99 6.5.3.4p1.
Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0;
isInvalid = true;
- } else if (E->getType()->isPlaceholderType()) {
- ExprResult PE = CheckPlaceholderExpr(E);
- if (PE.isInvalid()) return ExprError();
- return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind);
} else {
isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf);
}
@@ -3372,19 +2935,6 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
-/// Expressions of certain arbitrary types are forbidden by C from
-/// having l-value type. These are:
-/// - 'void', but not qualified void
-/// - function types
-///
-/// The exact rule here is C99 6.3.2.1:
-/// An lvalue is an expression with an object type or an incomplete
-/// type other than void.
-static bool IsCForbiddenLValueType(ASTContext &C, QualType T) {
- return ((T->isVoidType() && !T.hasQualifiers()) ||
- T->isFunctionType());
-}
-
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@@ -3528,7 +3078,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) {
// GNU extension: subscripting on pointer to void
- Diag(LLoc, diag::ext_gnu_void_ptr)
+ Diag(LLoc, diag::ext_gnu_subscript_void_type)
<< BaseExpr->getSourceRange();
// C forbids expressions of unqualified void type from being l-values.
@@ -3548,1109 +3098,12 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
}
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
- !IsCForbiddenLValueType(Context, ResultType));
+ !ResultType.isCForbiddenLValueType());
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
ResultType, VK, OK, RLoc));
}
-/// Check an ext-vector component access expression.
-///
-/// VK should be set in advance to the value kind of the base
-/// expression.
-static QualType
-CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
- SourceLocation OpLoc, const IdentifierInfo *CompName,
- SourceLocation CompLoc) {
- // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements,
- // see FIXME there.
- //
- // FIXME: This logic can be greatly simplified by splitting it along
- // halving/not halving and reworking the component checking.
- const ExtVectorType *vecType = baseType->getAs<ExtVectorType>();
-
- // The vector accessor can't exceed the number of elements.
- const char *compStr = CompName->getNameStart();
-
- // 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
- // to be selected.
- bool HalvingSwizzle = false;
-
- // This flag determines whether or not CompName has an 's' char prefix,
- // indicating that it is a string of hex values to be used as vector indices.
- bool HexSwizzle = *compStr == 's' || *compStr == 'S';
-
- bool HasRepeated = false;
- bool HasIndex[16] = {};
-
- int Idx;
-
- // Check that we've found one of the special components, or that the component
- // names must come from the same set.
- if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") ||
- !strcmp(compStr, "even") || !strcmp(compStr, "odd")) {
- HalvingSwizzle = true;
- } else if (!HexSwizzle &&
- (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) {
- do {
- if (HasIndex[Idx]) HasRepeated = true;
- HasIndex[Idx] = true;
- compStr++;
- } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1);
- } else {
- if (HexSwizzle) compStr++;
- while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) {
- if (HasIndex[Idx]) HasRepeated = true;
- HasIndex[Idx] = true;
- compStr++;
- }
- }
-
- if (!HalvingSwizzle && *compStr) {
- // We didn't get to the end of the string. This means the component names
- // didn't come from the same set *or* we encountered an illegal name.
- S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal)
- << llvm::StringRef(compStr, 1) << SourceRange(CompLoc);
- return QualType();
- }
-
- // Ensure no component accessor exceeds the width of the vector type it
- // operates on.
- if (!HalvingSwizzle) {
- compStr = CompName->getNameStart();
-
- if (HexSwizzle)
- compStr++;
-
- while (*compStr) {
- if (!vecType->isAccessorWithinNumElements(*compStr++)) {
- S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length)
- << baseType << SourceRange(CompLoc);
- return QualType();
- }
- }
- }
-
- // The component accessor looks fine - now we need to compute the actual type.
- // The vector type is implied by the component accessor. For example,
- // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
- // 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() + 1) / 2
- : CompName->getLength();
- if (HexSwizzle)
- CompSize--;
-
- if (CompSize == 1)
- return vecType->getElementType();
-
- if (HasRepeated) VK = VK_RValue;
-
- QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize);
- // Now look up the TypeDefDecl from the vector type. Without this,
- // diagostics look bad. We want extended vector types to appear built-in.
- for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) {
- if (S.ExtVectorDecls[i]->getUnderlyingType() == VT)
- return S.Context.getTypedefType(S.ExtVectorDecls[i]);
- }
- return VT; // should never get here (a typedef type should always be found).
-}
-
-static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl,
- IdentifierInfo *Member,
- const Selector &Sel,
- ASTContext &Context) {
- if (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 = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context))
- return D;
- }
- return 0;
-}
-
-static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
- 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 (Member)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
- GDecl = PD;
- break;
- }
- // Also must look for a getter or setter name which uses property syntax.
- if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
- GDecl = OMD;
- break;
- }
- }
- if (!GDecl) {
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- // Search in the protocol-qualifier list of current protocol.
- GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context);
- if (GDecl)
- return GDecl;
- }
- }
- return GDecl;
-}
-
-ExprResult
-Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
- bool IsArrow, SourceLocation OpLoc,
- const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
- // Even in dependent contexts, try to diagnose base expressions with
- // obviously wrong types, e.g.:
- //
- // 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.
- if (!IsArrow) {
- const PointerType *PT = BaseType->getAs<PointerType>();
- if (PT && (!getLangOptions().ObjC1 ||
- PT->getPointeeType()->isRecordType())) {
- assert(BaseExpr && "cannot happen with implicit member accesses");
- Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr->getSourceRange();
- return ExprError();
- }
- }
-
- assert(BaseType->isDependentType() ||
- NameInfo.getName().isDependentName() ||
- isDependentScopeSpecifier(SS));
-
- // 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.
- return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- FirstQualifierInScope,
- NameInfo, TemplateArgs));
-}
-
-/// We know that the given qualified member reference points only to
-/// declarations which do not belong to the static type of the base
-/// expression. Diagnose the problem.
-static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
- Expr *BaseExpr,
- QualType BaseType,
- const CXXScopeSpec &SS,
- NamedDecl *rep,
- const DeclarationNameInfo &nameInfo) {
- // If this is an implicit member access, use a different set of
- // diagnostics.
- if (!BaseExpr)
- return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
-
- SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
- << SS.getRange() << rep << BaseType;
-}
-
-// Check whether the declarations we found through a nested-name
-// specifier in a member expression are actually members of the base
-// type. The restriction here is:
-//
-// C++ [expr.ref]p2:
-// ... In these cases, the id-expression shall name a
-// member of the class or of one of its base classes.
-//
-// So it's perfectly legitimate for the nested-name specifier to name
-// an unrelated class, and for us to find an overload set including
-// decls from classes which are not superclasses, as long as the decl
-// we actually pick through overload resolution is from a superclass.
-bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
- QualType BaseType,
- const CXXScopeSpec &SS,
- const LookupResult &R) {
- const RecordType *BaseRT = BaseType->getAs<RecordType>();
- if (!BaseRT) {
- // We can't check this yet because the base type is still
- // dependent.
- assert(BaseType->isDependentType());
- return false;
- }
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
-
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- // If this is an implicit member reference and we find a
- // non-instance member, it's not an error.
- if (!BaseExpr && !(*I)->isCXXInstanceMember())
- return false;
-
- // Note that we use the DC of the decl, not the underlying decl.
- DeclContext *DC = (*I)->getDeclContext();
- while (DC->isTransparentContext())
- DC = DC->getParent();
-
- if (!DC->isRecord())
- continue;
-
- llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
- MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
-
- if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
- return false;
- }
-
- DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS,
- R.getRepresentativeDecl(),
- R.getLookupNameInfo());
- return true;
-}
-
-static bool
-LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
- SourceRange BaseRange, const RecordType *RTy,
- SourceLocation OpLoc, CXXScopeSpec &SS,
- bool HasTemplateArgs) {
- RecordDecl *RDecl = RTy->getDecl();
- if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
- SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
- << BaseRange))
- return true;
-
- if (HasTemplateArgs) {
- // LookupTemplateName doesn't expect these both to exist simultaneously.
- QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
-
- bool MOUS;
- SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS);
- return false;
- }
-
- DeclContext *DC = RDecl;
- if (SS.isSet()) {
- // If the member name was a qualified-id, look into the
- // nested-name-specifier.
- DC = SemaRef.computeDeclContext(SS, false);
-
- if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
- SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
- << SS.getRange() << DC;
- return true;
- }
-
- assert(DC && "Cannot handle non-computable dependent contexts in lookup");
-
- if (!isa<TypeDecl>(DC)) {
- SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
- << DC << SS.getRange();
- return true;
- }
- }
-
- // The record definition is complete, now look up the member.
- SemaRef.LookupQualifiedName(R, DC);
-
- if (!R.empty())
- return false;
-
- // We didn't find anything with the given name, so try to correct
- // for typos.
- DeclarationName Name = R.getLookupName();
- if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) &&
- !R.empty() &&
- (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
- SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << DC << R.getLookupName() << SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
- SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
- return false;
- } else {
- R.clear();
- R.setLookupName(Name);
- }
-
- return false;
-}
-
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
- SourceLocation OpLoc, bool IsArrow,
- CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
- if (BaseType->isDependentType() ||
- (SS.isSet() && isDependentScopeSpecifier(SS)))
- return ActOnDependentMemberExpr(Base, BaseType,
- IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- NameInfo, TemplateArgs);
-
- LookupResult R(*this, NameInfo, LookupMemberName);
-
- // Implicit member accesses.
- if (!Base) {
- QualType RecordTy = BaseType;
- if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
- if (LookupMemberExprInRecord(*this, R, SourceRange(),
- RecordTy->getAs<RecordType>(),
- OpLoc, SS, TemplateArgs != 0))
- return ExprError();
-
- // Explicit member accesses.
- } else {
- ExprResult BaseResult = Owned(Base);
- ExprResult Result =
- LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
-
- if (BaseResult.isInvalid())
- return ExprError();
- Base = BaseResult.take();
-
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
-
- if (Result.get())
- return move(Result);
-
- // LookupMemberExpr can modify Base, and thus change BaseType
- BaseType = Base->getType();
- }
-
- return BuildMemberReferenceExpr(Base, BaseType,
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
-}
-
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
- SourceLocation OpLoc, bool IsArrow,
- const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs,
- bool SuppressQualifierCheck) {
- QualType BaseType = BaseExprType;
- if (IsArrow) {
- assert(BaseType->isPointerType());
- BaseType = BaseType->getAs<PointerType>()->getPointeeType();
- }
- R.setBaseObjectType(BaseType);
-
- const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
- DeclarationName MemberName = MemberNameInfo.getName();
- SourceLocation MemberLoc = MemberNameInfo.getLoc();
-
- if (R.isAmbiguous())
- return ExprError();
-
- if (R.empty()) {
- // Rederive where we looked up.
- DeclContext *DC = (SS.isSet()
- ? computeDeclContext(SS, false)
- : BaseType->getAs<RecordType>()->getDecl());
-
- Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC
- << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
- return ExprError();
- }
-
- // Diagnose lookups that find only declarations from a non-base
- // type. This is possible for either qualified lookups (which may
- // have been qualified with an unrelated type) or implicit member
- // expressions (which were found with unqualified lookup and thus
- // may have come from an enclosing scope). Note that it's okay for
- // lookup to find declarations from a non-base type as long as those
- // aren't the ones picked by overload resolution.
- if ((SS.isSet() || !BaseExpr ||
- (isa<CXXThisExpr>(BaseExpr) &&
- cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
- !SuppressQualifierCheck &&
- CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
- return ExprError();
-
- // Construct an unresolved result if we in fact got an unresolved
- // result.
- if (R.isOverloadedResult() || R.isUnresolvableResult()) {
- // Suppress any lookup-related diagnostics; we'll do these when we
- // pick a member.
- R.suppressDiagnostics();
-
- UnresolvedMemberExpr *MemExpr
- = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
- BaseExpr, BaseExprType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- MemberNameInfo,
- TemplateArgs, R.begin(), R.end());
-
- return Owned(MemExpr);
- }
-
- assert(R.isSingleResult());
- DeclAccessPair FoundDecl = R.begin().getPair();
- NamedDecl *MemberDecl = R.getFoundDecl();
-
- // FIXME: diagnose the presence of template arguments now.
-
- // If the decl being referenced had an error, return an error for this
- // sub-expr without emitting another error, in order to avoid cascading
- // error cases.
- if (MemberDecl->isInvalidDecl())
- return ExprError();
-
- // Handle the implicit-member-access case.
- if (!BaseExpr) {
- // If this is not an instance member, convert to a non-member access.
- if (!MemberDecl->isCXXInstanceMember())
- return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl);
-
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
- }
-
- 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.isSet())
- ShouldCheckUse = false;
- }
-
- // Check the use of this member.
- if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
- Owned(BaseExpr);
- return ExprError();
- }
-
- // Perform a property load on the base regardless of whether we
- // actually need it for the declaration.
- if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(BaseExpr);
- if (Result.isInvalid())
- return ExprError();
- BaseExpr = Result.take();
- }
-
- if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
- return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
- SS, FD, FoundDecl, MemberNameInfo);
-
- if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
- BaseExpr, OpLoc);
-
- if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, Var);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Var, FoundDecl, MemberNameInfo,
- Var->getType().getNonReferenceType(),
- VK_LValue, OK_Ordinary));
- }
-
- if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
- ExprValueKind valueKind;
- QualType type;
- if (MemberFn->isInstance()) {
- valueKind = VK_RValue;
- type = Context.BoundMemberTy;
- } else {
- valueKind = VK_LValue;
- type = MemberFn->getType();
- }
-
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- MemberFn, FoundDecl, MemberNameInfo,
- type, valueKind, OK_Ordinary));
- }
- assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
-
- if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Enum, FoundDecl, MemberNameInfo,
- Enum->getType(), VK_RValue, OK_Ordinary));
- }
-
- Owned(BaseExpr);
-
- // We found something that we didn't expect. Complain.
- if (isa<TypeDecl>(MemberDecl))
- Diag(MemberLoc, diag::err_typecheck_member_reference_type)
- << MemberName << BaseType << int(IsArrow);
- else
- Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
- << MemberName << BaseType << int(IsArrow);
-
- Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
- << MemberName;
- R.suppressDiagnostics();
- return ExprError();
-}
-
-/// Given that normal member access failed on the given expression,
-/// and given that the expression's type involves builtin-id or
-/// builtin-Class, decide whether substituting in the redefinition
-/// types would be profitable. The redefinition type is whatever
-/// this translation unit tried to typedef to id/Class; we store
-/// it to the side and then re-use it in places like this.
-static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
- const ObjCObjectPointerType *opty
- = base.get()->getType()->getAs<ObjCObjectPointerType>();
- if (!opty) return false;
-
- const ObjCObjectType *ty = opty->getObjectType();
-
- QualType redef;
- if (ty->isObjCId()) {
- redef = S.Context.ObjCIdRedefinitionType;
- } else if (ty->isObjCClass()) {
- redef = S.Context.ObjCClassRedefinitionType;
- } else {
- return false;
- }
-
- // Do the substitution as long as the redefinition type isn't just a
- // possibly-qualified pointer to builtin-id or builtin-Class again.
- opty = redef->getAs<ObjCObjectPointerType>();
- if (opty && !opty->getObjectType()->getInterface() != 0)
- return false;
-
- base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
- return true;
-}
-
-/// Look up the given member of the given non-type-dependent
-/// expression. This can return in one of two ways:
-/// * If it returns a sentinel null-but-valid result, the caller will
-/// assume that lookup was performed and the results written into
-/// the provided structure. It will take over from there.
-/// * Otherwise, the returned expression will be produced in place of
-/// an ordinary member expression.
-///
-/// The ObjCImpDecl bit is a gross hack that will need to be properly
-/// fixed for ObjC++.
-ExprResult
-Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
- bool &IsArrow, SourceLocation OpLoc,
- CXXScopeSpec &SS,
- Decl *ObjCImpDecl, bool HasTemplateArgs) {
- assert(BaseExpr.get() && "no base expression");
-
- // Perform default conversions.
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
-
- if (IsArrow) {
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
- }
-
- QualType BaseType = BaseExpr.get()->getType();
- assert(!BaseType->isDependentType());
-
- DeclarationName MemberName = R.getLookupName();
- SourceLocation MemberLoc = R.getNameLoc();
-
- // For later type-checking purposes, turn arrow accesses into dot
- // accesses. The only access type we support that doesn't follow
- // the C equivalence "a->b === (*a).b" is ObjC property accesses,
- // and those never use arrows, so this is unaffected.
- if (IsArrow) {
- if (const PointerType *Ptr = BaseType->getAs<PointerType>())
- BaseType = Ptr->getPointeeType();
- else if (const ObjCObjectPointerType *Ptr
- = BaseType->getAs<ObjCObjectPointerType>())
- BaseType = Ptr->getPointeeType();
- else if (BaseType->isRecordType()) {
- // Recover from arrow accesses to records, e.g.:
- // struct MyRecord foo;
- // foo->bar
- // This is actually well-formed in C++ if MyRecord has an
- // overloaded operator->, but that should have been dealt with
- // by now.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, ".");
- IsArrow = false;
- } else if (BaseType == Context.BoundMemberTy) {
- goto fail;
- } else {
- Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr.get()->getSourceRange();
- return ExprError();
- }
- }
-
- // Handle field access to simple records.
- if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
- RTy, OpLoc, SS, HasTemplateArgs))
- return ExprError();
-
- // Returning valid-but-null is how we indicate to the caller that
- // the lookup result was filled in.
- return Owned((Expr*) 0);
- }
-
- // Handle ivar access to Objective-C objects.
- if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- // There are three cases for the base type:
- // - builtin id (qualified or unqualified)
- // - builtin Class (qualified or unqualified)
- // - an interface
- ObjCInterfaceDecl *IDecl = OTy->getInterface();
- if (!IDecl) {
- // There's an implicit 'isa' ivar on all objects.
- // But we only actually find it this way on objects of type 'id',
- // apparently.
- if (OTy->isObjCId() && Member->isStr("isa"))
- return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
- Context.getObjCClassType()));
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- goto fail;
- }
-
- ObjCInterfaceDecl *ClassDeclared;
- ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
-
- if (!IV) {
- // Attempt to correct for typos in ivar names.
- LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
- LookupMemberName);
- if (CorrectTypo(Res, 0, 0, IDecl, false,
- IsArrow ? CTC_ObjCIvarLookup
- : CTC_ObjCPropertyLookup) &&
- (IV = Res.getAsSingle<ObjCIvarDecl>())) {
- Diag(R.getNameLoc(),
- diag::err_typecheck_member_reference_ivar_suggest)
- << IDecl->getDeclName() << MemberName << IV->getDeclName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- IV->getNameAsString());
- Diag(IV->getLocation(), diag::note_previous_decl)
- << IV->getDeclName();
- } else {
- Res.clear();
- Res.setLookupName(Member);
-
- Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
- << IDecl->getDeclName() << MemberName
- << BaseExpr.get()->getSourceRange();
- return ExprError();
- }
- }
-
- // 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.
- if (ObjCImplementationDecl *IMPD =
- dyn_cast<ObjCImplementationDecl>(ObjCImpDecl))
- ClassOfMethodDecl = IMPD->getClassInterface();
- else if (ObjCCategoryImplDecl* CatImplClass =
- dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
- 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();
- }
-
- return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr.take(),
- IsArrow));
- }
-
- // Objective-C property access.
- const ObjCObjectPointerType *OPT;
- if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
- // This actually uses the base as an r-value.
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
-
- assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
-
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- const ObjCObjectType *OT = OPT->getObjectType();
-
- // id, with and without qualifiers.
- if (OT->isObjCId()) {
- // Check protocols on qualified interfaces.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) {
- if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
- // Check the use of this declaration
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
-
- QualType T = PD->getType();
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- T = getMessageSendResultType(BaseType, Getter, false, false);
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
- VK_LValue,
- OK_ObjCProperty,
- MemberLoc,
- BaseExpr.take()));
- }
-
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(OMD, MemberLoc))
- return ExprError();
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *SMD = 0;
- if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
- SetterSel, Context))
- SMD = dyn_cast<ObjCMethodDecl>(SDecl);
- QualType PType = getMessageSendResultType(BaseType, OMD, false,
- false);
-
- ExprValueKind VK = VK_LValue;
- if (!getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(Context, PType))
- VK = VK_RValue;
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
- VK, OK,
- MemberLoc, BaseExpr.take()));
- }
- }
- // Use of id.member can only be for a property reference. Do not
- // use the 'id' redefinition in this case.
- if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
- }
-
- // 'Class', unqualified only.
- if (OT->isObjCClass()) {
- // Only works in a method declaration (??!).
- ObjCMethodDecl *MD = getCurMethodDecl();
- if (!MD) {
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- goto fail;
- }
-
- // Also must look for a getter name which uses property syntax.
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCInterfaceDecl *IFace = MD->getClassInterface();
- ObjCMethodDecl *Getter;
- if ((Getter = IFace->lookupClassMethod(Sel))) {
- // Check the use of this method.
- if (DiagnoseUseOfDecl(Getter, MemberLoc))
- return ExprError();
- } else
- Getter = IFace->lookupPrivateMethod(Sel, false);
- // 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->lookupPrivateMethod(SetterSel, false);
- }
- // 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;
-
- ExprValueKind VK = VK_LValue;
- if (Getter) {
- PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
- false);
- if (!getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(Context, PType))
- VK = VK_RValue;
- } else {
- // Get the expression type from Setter's incoming parameter.
- PType = (*(Setter->param_end() -1))->getType();
- }
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- // FIXME: we must check that the setter has property type.
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
- MemberLoc, BaseExpr.take()));
- }
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
-
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType);
- }
-
- // Normal property access.
- return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc,
- SourceLocation(), QualType(), false);
- }
-
- // Handle 'field access' to vectors, such as 'V.xx'.
- if (BaseType->isExtVectorType()) {
- // FIXME: this expr should store IsArrow.
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
- QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc,
- Member, MemberLoc);
- if (ret.isNull())
- return ExprError();
-
- return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
- *Member, MemberLoc));
- }
-
- // Adjust builtin-sel to the appropriate redefinition type if that's
- // not just a pointer to builtin-sel again.
- if (IsArrow &&
- BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
- !Context.ObjCSelRedefinitionType->isObjCSelType()) {
- BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
- CK_BitCast);
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
-
- // Failure cases.
- fail:
-
- // Recover from dot accesses to pointers, e.g.:
- // type *foo;
- // foo.bar
- // This is actually well-formed in two cases:
- // - 'type' is an Objective C type
- // - 'bar' is a pseudo-destructor name which happens to refer to
- // the appropriate pointer type
- if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
- MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, "->");
-
- // Recurse as an -> access.
- IsArrow = true;
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
- }
-
- // If the user is trying to apply -> or . to a function name, it's probably
- // because they forgot parentheses to call that function.
- QualType ZeroArgCallTy;
- UnresolvedSet<4> Overloads;
- if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
- if (ZeroArgCallTy.isNull()) {
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
- UnresolvedSet<2> PlausibleOverloads;
- for (OverloadExpr::decls_iterator It = Overloads.begin(),
- DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
- const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
- QualType OverloadResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && OverloadResultTy->isRecordType()) ||
- (IsArrow && OverloadResultTy->isPointerType() &&
- OverloadResultTy->getPointeeType()->isRecordType()))
- PlausibleOverloads.addDecl(It.getDecl());
- }
- NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
- return ExprError();
- }
- if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
- (IsArrow && ZeroArgCallTy->isPointerType() &&
- ZeroArgCallTy->getPointeeType()->isRecordType())) {
- // At this point, we know BaseExpr looks like it's potentially callable
- // with 0 arguments, and that it returns something of a reasonable type,
- // so we can emit a fixit and carry on pretending that BaseExpr was
- // actually a CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- // FIXME: Try this before emitting the fixit, and suppress diagnostics
- // while doing so.
- ExprResult NewBase =
- ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc.getFileLocWithOffset(1));
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase;
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
- }
-
- Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr.get()->getSourceRange();
-
- return ExprError();
-}
-
-/// The main callback when the parser finds something like
-/// expression . [nested-name-specifier] identifier
-/// expression -> [nested-name-specifier] identifier
-/// where 'identifier' encompasses a fairly broad spectrum of
-/// possibilities, including destructor and operator references.
-///
-/// \param OpKind either tok::arrow or tok::period
-/// \param HasTrailingLParen whether the next token is '(', which
-/// is used to diagnose mis-uses of special members that can
-/// only be called
-/// \param ObjCImpDecl the current ObjC @implementation decl;
-/// this is an ugly hack around the fact that ObjC @implementations
-/// aren't properly put in the context chain
-ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
- SourceLocation OpLoc,
- tok::TokenKind OpKind,
- CXXScopeSpec &SS,
- UnqualifiedId &Id,
- Decl *ObjCImpDecl,
- bool HasTrailingLParen) {
- if (SS.isSet() && SS.isInvalid())
- return ExprError();
-
- // Warn about the explicit constructor calls Microsoft extension.
- if (getLangOptions().Microsoft &&
- Id.getKind() == UnqualifiedId::IK_ConstructorName)
- Diag(Id.getSourceRange().getBegin(),
- diag::ext_ms_explicit_constructor_call);
-
- TemplateArgumentListInfo TemplateArgsBuffer;
-
- // Decompose the name into its component parts.
- DeclarationNameInfo NameInfo;
- const TemplateArgumentListInfo *TemplateArgs;
- DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer,
- NameInfo, TemplateArgs);
-
- DeclarationName Name = NameInfo.getName();
- bool IsArrow = (OpKind == tok::arrow);
-
- NamedDecl *FirstQualifierInScope
- = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
- static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
-
- // This is a postfix expression, so get rid of ParenListExprs.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
- if (Result.isInvalid()) return ExprError();
- Base = Result.take();
-
- if (Base->getType()->isDependentType() || Name.isDependentName() ||
- isDependentScopeSpecifier(SS)) {
- Result = ActOnDependentMemberExpr(Base, Base->getType(),
- IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- NameInfo, TemplateArgs);
- } else {
- LookupResult R(*this, NameInfo, LookupMemberName);
- ExprResult BaseResult = Owned(Base);
- Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, ObjCImpDecl, TemplateArgs != 0);
- if (BaseResult.isInvalid())
- return ExprError();
- Base = BaseResult.take();
-
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
-
- if (Result.get()) {
- // The only way a reference to a destructor can be used is to
- // immediately call it, which falls into this case. If the
- // next token is not a '(', produce a diagnostic and build the
- // call now.
- if (!HasTrailingLParen &&
- Id.getKind() == UnqualifiedId::IK_DestructorName)
- return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
-
- return move(Result);
- }
-
- Result = BuildMemberReferenceExpr(Base, Base->getType(),
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
- }
-
- return move(Result);
-}
-
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
FunctionDecl *FD,
ParmVarDecl *Param) {
@@ -4716,6 +3169,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(),
const_cast<CXXDestructorDecl*>(Temporary->getDestructor()));
ExprTemporaries.push_back(Temporary);
+ ExprNeedsCleanups = true;
}
// We already type-checked the argument, so we know it works.
@@ -4834,7 +3288,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
InitializedEntity Entity =
Param? InitializedEntity::InitializeParameter(Context, Param)
- : InitializedEntity::InitializeParameter(Context, ProtoArgType);
+ : InitializedEntity::InitializeParameter(Context, ProtoArgType,
+ Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg));
@@ -5157,7 +3612,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (Proto && i < Proto->getNumArgs()) {
InitializedEntity Entity
= InitializedEntity::InitializeParameter(Context,
- Proto->getArgType(i));
+ Proto->getArgType(i),
+ Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg));
@@ -5248,8 +3704,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
InitializedEntity Entity
= InitializedEntity::InitializeTemporary(literalType);
InitializationKind Kind
- = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc),
- /*IsCStyleCast=*/true);
+ = InitializationKind::CreateCStyleCast(LParenLoc,
+ SourceRange(LParenLoc, RParenLoc));
InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
MultiExprArg(*this, &literalExpr, 1),
@@ -5267,8 +3723,9 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
// In C, compound literals are l-values for some reason.
ExprValueKind VK = getLangOptions().CPlusPlus ? VK_RValue : VK_LValue;
- return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
- VK, literalExpr, isFileScope));
+ return MaybeBindToTemporary(
+ new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
+ VK, literalExpr, isFileScope));
}
ExprResult
@@ -5426,14 +3883,15 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
}
/// CheckCastTypes - Check type constraints for casting between types.
-ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
- Expr *castExpr, CastKind& Kind, ExprValueKind &VK,
+ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR,
+ QualType castType, Expr *castExpr,
+ CastKind& Kind, ExprValueKind &VK,
CXXCastPath &BasePath, bool FunctionalStyle) {
if (castExpr->getType() == Context.UnknownAnyTy)
return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath);
if (getLangOptions().CPlusPlus)
- return CXXCheckCStyleCast(SourceRange(TyR.getBegin(),
+ return CXXCheckCStyleCast(SourceRange(CastStartLoc,
castExpr->getLocEnd()),
castType, VK, castExpr, Kind, BasePath,
FunctionalStyle);
@@ -5551,8 +4009,8 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
// If either type is a pointer, the other type has to be either an
// integer or a pointer.
+ QualType castExprType = castExpr->getType();
if (!castType->isArithmeticType()) {
- QualType castExprType = castExpr->getType();
if (!castExprType->isIntegralType(Context) &&
castExprType->isArithmeticType()) {
Diag(castExpr->getLocStart(),
@@ -5568,6 +4026,36 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
}
}
+ if (getLangOptions().ObjCAutoRefCount) {
+ // Diagnose problems with Objective-C casts involving lifetime qualifiers.
+ CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()),
+ castType, castExpr, CCK_CStyleCast);
+
+ if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
+ if (const PointerType *ExprPtr = castExprType->getAs<PointerType>()) {
+ Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
+ Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
+ if (CastPtr->getPointeeType()->isObjCLifetimeType() &&
+ ExprPtr->getPointeeType()->isObjCLifetimeType() &&
+ !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) {
+ Diag(castExpr->getLocStart(),
+ diag::err_typecheck_incompatible_ownership)
+ << castExprType << castType << AA_Casting
+ << castExpr->getSourceRange();
+
+ return ExprError();
+ }
+ }
+ }
+ else if (!CheckObjCARCUnavailableWeakConversion(castType, castExprType)) {
+ Diag(castExpr->getLocStart(),
+ diag::err_arc_convesion_of_weak_unavailable) << 1
+ << castExprType << castType
+ << castExpr->getSourceRange();
+ return ExprError();
+ }
+ }
+
castExprRes = Owned(castExpr);
Kind = PrepareScalarCast(*this, castExprRes, castType);
if (castExprRes.isInvalid())
@@ -5638,20 +4126,57 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
}
ExprResult
-Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty,
+Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
+ Declarator &D, ParsedType &Ty,
SourceLocation RParenLoc, Expr *castExpr) {
- assert((Ty != 0) && (castExpr != 0) &&
+ assert(!D.isInvalidType() && (castExpr != 0) &&
"ActOnCastExpr(): missing type or expr");
- TypeSourceInfo *castTInfo;
- QualType castType = GetTypeFromParser(Ty, &castTInfo);
- if (!castTInfo)
- castTInfo = Context.getTrivialTypeSourceInfo(castType);
+ TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType());
+ if (D.isInvalidType())
+ return ExprError();
+
+ if (getLangOptions().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+ }
+
+ QualType castType = castTInfo->getType();
+ Ty = CreateParsedType(castType, castTInfo);
+
+ bool isVectorLiteral = false;
+
+ // Check for an altivec or OpenCL literal,
+ // i.e. all the elements are integer constants.
+ ParenExpr *PE = dyn_cast<ParenExpr>(castExpr);
+ ParenListExpr *PLE = dyn_cast<ParenListExpr>(castExpr);
+ if (getLangOptions().AltiVec && castType->isVectorType() && (PE || PLE)) {
+ if (PLE && PLE->getNumExprs() == 0) {
+ Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer);
+ return ExprError();
+ }
+ if (PE || PLE->getNumExprs() == 1) {
+ Expr *E = (PE ? PE->getSubExpr() : PLE->getExpr(0));
+ if (!E->getType()->isVectorType())
+ isVectorLiteral = true;
+ }
+ else
+ isVectorLiteral = true;
+ }
+
+ // If this is a vector initializer, '(' type ')' '(' init, ..., init ')'
+ // then handle it as such.
+ if (isVectorLiteral)
+ return BuildVectorLiteral(LParenLoc, RParenLoc, castExpr, castTInfo);
// If the Expr being casted is a ParenListExpr, handle it specially.
- if (isa<ParenListExpr>(castExpr))
- return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, castExpr,
- castTInfo);
+ // This is not an AltiVec-style cast, so turn the ParenListExpr into a
+ // sequence of BinOp comma operators.
+ if (isa<ParenListExpr>(castExpr)) {
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, castExpr);
+ if (Result.isInvalid()) return ExprError();
+ castExpr = Result.take();
+ }
return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr);
}
@@ -5663,8 +4188,8 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
ExprResult CastResult =
- CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
- Kind, VK, BasePath);
+ CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(),
+ castExpr, Kind, VK, BasePath);
if (CastResult.isInvalid())
return ExprError();
castExpr = CastResult.take();
@@ -5675,6 +4200,80 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
LParenLoc, RParenLoc));
}
+ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
+ SourceLocation RParenLoc, Expr *E,
+ TypeSourceInfo *TInfo) {
+ assert((isa<ParenListExpr>(E) || isa<ParenExpr>(E)) &&
+ "Expected paren or paren list expression");
+
+ Expr **exprs;
+ unsigned numExprs;
+ Expr *subExpr;
+ if (ParenListExpr *PE = dyn_cast<ParenListExpr>(E)) {
+ exprs = PE->getExprs();
+ numExprs = PE->getNumExprs();
+ } else {
+ subExpr = cast<ParenExpr>(E)->getSubExpr();
+ exprs = &subExpr;
+ numExprs = 1;
+ }
+
+ QualType Ty = TInfo->getType();
+ assert(Ty->isVectorType() && "Expected vector type");
+
+ llvm::SmallVector<Expr *, 8> initExprs;
+ const VectorType *VTy = Ty->getAs<VectorType>();
+ unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
+
+ // '(...)' form of vector initialization in AltiVec: the number of
+ // initializers must be one or must match the size of the vector.
+ // If a single value is specified in the initializer then it will be
+ // replicated to all the components of the vector
+ if (VTy->getVectorKind() == VectorType::AltiVecVector) {
+ // The number of initializers must be one or must match the size of the
+ // vector. If a single value is specified in the initializer then it will
+ // be replicated to all the components of the vector
+ if (numExprs == 1) {
+ QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ ExprResult Literal = Owned(exprs[0]);
+ Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ PrepareScalarCast(*this, Literal, ElemTy));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ }
+ else if (numExprs < numElems) {
+ Diag(E->getExprLoc(),
+ diag::err_incorrect_number_of_vector_initializers);
+ return ExprError();
+ }
+ else
+ for (unsigned i = 0, e = numExprs; i != e; ++i)
+ initExprs.push_back(exprs[i]);
+ }
+ else {
+ // For OpenCL, when the number of initializers is a single value,
+ // it will be replicated to all components of the vector.
+ if (getLangOptions().OpenCL &&
+ VTy->getVectorKind() == VectorType::GenericVector &&
+ numExprs == 1) {
+ QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ ExprResult Literal = Owned(exprs[0]);
+ Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ PrepareScalarCast(*this, Literal, ElemTy));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ }
+
+ for (unsigned i = 0, e = numExprs; i != e; ++i)
+ initExprs.push_back(exprs[i]);
+ }
+ // FIXME: This means that pretty-printing the final AST will produce curly
+ // braces instead of the original commas.
+ InitListExpr *initE = new (Context) InitListExpr(Context, LParenLoc,
+ &initExprs[0],
+ initExprs.size(), RParenLoc);
+ initE->setType(Ty);
+ return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE);
+}
+
/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence
/// of comma binary operators.
ExprResult
@@ -5694,91 +4293,18 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) {
return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get());
}
-ExprResult
-Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
- SourceLocation RParenLoc, Expr *Op,
- TypeSourceInfo *TInfo) {
- ParenListExpr *PE = cast<ParenListExpr>(Op);
- QualType Ty = TInfo->getType();
- bool isVectorLiteral = false;
-
- // Check for an altivec or OpenCL literal,
- // i.e. all the elements are integer constants.
- if (getLangOptions().AltiVec && Ty->isVectorType()) {
- if (PE->getNumExprs() == 0) {
- Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer);
- return ExprError();
- }
- if (PE->getNumExprs() == 1) {
- if (!PE->getExpr(0)->getType()->isVectorType())
- isVectorLiteral = true;
- }
- else
- isVectorLiteral = true;
- }
-
- // If this is a vector initializer, '(' type ')' '(' init, ..., init ')'
- // then handle it as such.
- if (isVectorLiteral) {
- llvm::SmallVector<Expr *, 8> initExprs;
- // '(...)' form of vector initialization in AltiVec: the number of
- // initializers must be one or must match the size of the vector.
- // If a single value is specified in the initializer then it will be
- // replicated to all the components of the vector
- if (Ty->getAs<VectorType>()->getVectorKind() ==
- VectorType::AltiVecVector) {
- unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
- // The number of initializers must be one or must match the size of the
- // vector. If a single value is specified in the initializer then it will
- // be replicated to all the components of the vector
- if (PE->getNumExprs() == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
- ExprResult Literal = Owned(PE->getExpr(0));
- Literal = ImpCastExprToType(Literal.take(), ElemTy,
- PrepareScalarCast(*this, Literal, ElemTy));
- return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
- }
- else if (PE->getNumExprs() < numElems) {
- Diag(PE->getExprLoc(),
- diag::err_incorrect_number_of_vector_initializers);
- return ExprError();
- }
- else
- for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
- initExprs.push_back(PE->getExpr(i));
- }
- else
- 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.
- InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc,
- &initExprs[0],
- initExprs.size(), RParenLoc);
- E->setType(Ty);
- return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, E);
- } else {
- // This is not an AltiVec-style cast, so turn the ParenListExpr into a
- // sequence of BinOp comma operators.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Op);
- if (Result.isInvalid()) return ExprError();
- return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Result.take());
- }
-}
-
ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
SourceLocation R,
- MultiExprArg Val,
- ParsedType TypeOfCast) {
+ MultiExprArg Val) {
unsigned nexprs = Val.size();
Expr **exprs = reinterpret_cast<Expr**>(Val.release());
assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list");
Expr *expr;
- if (nexprs == 1 && TypeOfCast && !TypeIsVectorType(TypeOfCast))
+ if (nexprs == 1)
expr = new (Context) ParenExpr(L, R, exprs[0]);
else
- expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
+ expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R,
+ exprs[nexprs-1]->getType());
return Owned(expr);
}
@@ -5876,7 +4402,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR
// Now check the two expressions.
if (LHSTy->isVectorType() || RHSTy->isVectorType())
- return CheckVectorOperands(QuestionLoc, LHS, RHS);
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
// OpenCL: If the condition is a vector, and both operands are scalar,
// attempt to implicity convert them to the vector type to act like the
@@ -6203,43 +4729,21 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
-/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps
+/// SuggestParentheses - Emit a note with a fixit hint that wraps
/// ParenRange in parentheses.
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
- const PartialDiagnostic &PD,
- const PartialDiagnostic &FirstNote,
- SourceRange FirstParenRange,
- const PartialDiagnostic &SecondNote,
- SourceRange SecondParenRange) {
- Self.Diag(Loc, PD);
-
- if (!FirstNote.getDiagID())
- return;
-
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
- if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just return.
- return;
- }
-
- Self.Diag(Loc, FirstNote)
- << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
-
- if (!SecondNote.getDiagID())
- return;
-
- EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
- if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just dig the
- // warning/error and return.
- Self.Diag(Loc, SecondNote);
- return;
+ const PartialDiagnostic &Note,
+ SourceRange ParenRange) {
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
+ if (ParenRange.getBegin().isFileID() && ParenRange.getEnd().isFileID() &&
+ EndLoc.isValid()) {
+ Self.Diag(Loc, Note)
+ << FixItHint::CreateInsertion(ParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ } else {
+ // We can't display the parentheses, so just show the bare note.
+ Self.Diag(Loc, Note) << ParenRange;
}
-
- Self.Diag(Loc, SecondNote)
- << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
}
static bool IsArithmeticOp(BinaryOperatorKind Opc) {
@@ -6312,13 +4816,13 @@ static bool ExprLooksBoolean(Expr *E) {
/// "int x = a + someBinaryCondition ? 1 : 2".
static void DiagnoseConditionalPrecedence(Sema &Self,
SourceLocation OpLoc,
- Expr *cond,
- Expr *lhs,
- Expr *rhs) {
+ Expr *Condition,
+ Expr *LHS,
+ Expr *RHS) {
BinaryOperatorKind CondOpcode;
Expr *CondRHS;
- if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS))
+ if (!IsArithmeticBinaryExpr(Condition, &CondOpcode, &CondRHS))
return;
if (!ExprLooksBoolean(CondRHS))
return;
@@ -6326,25 +4830,18 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
// The condition is an arithmetic binary expression, with a right-
// hand side that looks boolean, so warn.
- PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional)
- << cond->getSourceRange()
- << BinaryOperator::getOpcodeStr(CondOpcode);
-
- PartialDiagnostic FirstNote =
- Self.PDiag(diag::note_precedence_conditional_silence)
+ Self.Diag(OpLoc, diag::warn_precedence_conditional)
+ << Condition->getSourceRange()
<< BinaryOperator::getOpcodeStr(CondOpcode);
- SourceRange FirstParenRange(cond->getLocStart(),
- cond->getLocEnd());
-
- PartialDiagnostic SecondNote =
- Self.PDiag(diag::note_precedence_conditional_first);
-
- SourceRange SecondParenRange(CondRHS->getLocStart(),
- rhs->getLocEnd());
+ SuggestParentheses(Self, OpLoc,
+ Self.PDiag(diag::note_precedence_conditional_silence)
+ << BinaryOperator::getOpcodeStr(CondOpcode),
+ SourceRange(Condition->getLocStart(), Condition->getLocEnd()));
- SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange,
- SecondNote, SecondParenRange);
+ SuggestParentheses(Self, OpLoc,
+ Self.PDiag(diag::note_precedence_conditional_first),
+ SourceRange(CondRHS->getLocStart(), RHS->getLocEnd()));
}
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
@@ -6427,17 +4924,31 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) {
// qualifiers of the type *pointed to* by the right;
Qualifiers lq;
+ // As a special case, 'non-__weak A *' -> 'non-__weak const *' is okay.
+ if (lhq.getObjCLifetime() != rhq.getObjCLifetime() &&
+ lhq.compatiblyIncludesObjCLifetime(rhq)) {
+ // Ignore lifetime for further calculation.
+ lhq.removeObjCLifetime();
+ rhq.removeObjCLifetime();
+ }
+
if (!lhq.compatiblyIncludes(rhq)) {
// Treat address-space mismatches as fatal. TODO: address subspaces
if (lhq.getAddressSpace() != rhq.getAddressSpace())
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
- // It's okay to add or remove GC qualifiers when converting to
+ // It's okay to add or remove GC or lifetime qualifiers when converting to
// and from void*.
- else if (lhq.withoutObjCGCAttr().compatiblyIncludes(rhq.withoutObjCGCAttr())
+ else if (lhq.withoutObjCGCAttr().withoutObjCGLifetime()
+ .compatiblyIncludes(
+ rhq.withoutObjCGCAttr().withoutObjCGLifetime())
&& (lhptee->isVoidType() || rhptee->isVoidType()))
; // keep old
+ // Treat lifetime mismatches as fatal.
+ else if (lhq.getObjCLifetime() != rhq.getObjCLifetime())
+ ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
+
// For GCC compatibility, other qualifier mismatches are treated
// as still compatible in C.
else ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
@@ -6614,6 +5125,7 @@ Sema::AssignConvertType
Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
CastKind &Kind) {
QualType rhsType = rhs.get()->getType();
+ QualType origLhsType = lhsType;
// Get canonical types. We're not formatting these types, just comparing
// them.
@@ -6768,7 +5280,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
// A* -> B*
if (rhsType->isObjCObjectPointerType()) {
Kind = CK_BitCast;
- return checkObjCPointerTypesForAssignment(*this, lhsType, rhsType);
+ Sema::AssignConvertType result =
+ checkObjCPointerTypesForAssignment(*this, lhsType, rhsType);
+ if (getLangOptions().ObjCAutoRefCount &&
+ result == Compatible &&
+ !CheckObjCARCUnavailableWeakConversion(origLhsType, rhsType))
+ result = IncompatibleObjCWeakRef;
+ return result;
}
// int or null -> A*
@@ -6936,8 +5454,12 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) {
AA_Assigning);
if (Res.isInvalid())
return Incompatible;
+ Sema::AssignConvertType result = Compatible;
+ if (getLangOptions().ObjCAutoRefCount &&
+ !CheckObjCARCUnavailableWeakConversion(lhsType, rExpr.get()->getType()))
+ result = IncompatibleObjCWeakRef;
rExpr = move(Res);
- return Compatible;
+ return result;
}
// FIXME: Currently, we fall through and treat C++ classes like C
@@ -6989,7 +5511,8 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult &
return QualType();
}
-QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) {
+QualType Sema::CheckVectorOperands(ExprResult &lex, ExprResult &rex,
+ SourceLocation Loc, bool isCompAssign) {
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhsType =
@@ -7001,42 +5524,33 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
if (lhsType == rhsType)
return lhsType;
- // Handle the case of a vector & extvector type of the same size and element
- // type. It would be nice if we only had one vector type someday.
- if (getLangOptions().LaxVectorConversions) {
- if (const VectorType *LV = lhsType->getAs<VectorType>()) {
- if (const VectorType *RV = rhsType->getAs<VectorType>()) {
- if (LV->getElementType() == RV->getElementType() &&
- LV->getNumElements() == RV->getNumElements()) {
- if (lhsType->isExtVectorType()) {
- rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
- return lhsType;
- }
-
- lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
- return rhsType;
- } else if (Context.getTypeSize(lhsType) ==Context.getTypeSize(rhsType)){
- // 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; no bits are changed but the result type is different.
- rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
- return lhsType;
- }
- }
- }
- }
-
// Handle the case of equivalent AltiVec and GCC vector types
if (lhsType->isVectorType() && rhsType->isVectorType() &&
Context.areCompatibleVectorTypes(lhsType, rhsType)) {
- lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
+ if (lhsType->isExtVectorType()) {
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
+ return lhsType;
+ }
+
+ if (!isCompAssign)
+ lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
return rhsType;
}
+ if (getLangOptions().LaxVectorConversions &&
+ Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) {
+ // 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; no bits are changed but the result type is different.
+ // FIXME: Should we really be allowing this?
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
+ return lhsType;
+ }
+
// Canonicalize the ExtVector to the LHS, remember if we swapped so we can
// swap back (so that we don't reverse the inputs to a subtract, for instance.
bool swapped = false;
- if (rhsType->isExtVectorType()) {
+ if (rhsType->isExtVectorType() && !isCompAssign) {
swapped = true;
std::swap(rex, lex);
std::swap(rhsType, lhsType);
@@ -7069,6 +5583,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
}
// Vectors of different size or scalar and non-ext-vector are errors.
+ if (swapped) std::swap(rex, lex);
Diag(Loc, diag::err_typecheck_vector_not_convertable)
<< lex.get()->getType() << rex.get()->getType()
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
@@ -7078,7 +5593,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu
QualType Sema::CheckMultiplyDivideOperands(
ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
if (lex.isInvalid() || rex.isInvalid())
@@ -7102,7 +5617,7 @@ QualType Sema::CheckRemainderOperands(
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
if (lex.get()->getType()->hasIntegerRepresentation() &&
rex.get()->getType()->hasIntegerRepresentation())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
return InvalidOperands(Loc, lex, rex);
}
@@ -7121,10 +5636,149 @@ QualType Sema::CheckRemainderOperands(
return compType;
}
+/// \brief Diagnose invalid arithmetic on two void pointers.
+static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_void_type
+ : diag::ext_gnu_void_ptr)
+ << 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on a void pointer.
+static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
+ Expr *Pointer) {
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_void_type
+ : diag::ext_gnu_void_ptr)
+ << 0 /* one pointer */ << Pointer->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on two function pointers.
+static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ assert(LHS->getType()->isAnyPointerType());
+ assert(RHS->getType()->isAnyPointerType());
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_function_type
+ : diag::ext_gnu_ptr_func_arith)
+ << 1 /* two pointers */ << LHS->getType()->getPointeeType()
+ // We only show the second type if it differs from the first.
+ << (unsigned)!S.Context.hasSameUnqualifiedType(LHS->getType(),
+ RHS->getType())
+ << RHS->getType()->getPointeeType()
+ << LHS->getSourceRange() << RHS->getSourceRange();
+}
+
+/// \brief Diagnose invalid arithmetic on a function pointer.
+static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
+ Expr *Pointer) {
+ assert(Pointer->getType()->isAnyPointerType());
+ S.Diag(Loc, S.getLangOptions().CPlusPlus
+ ? diag::err_typecheck_pointer_arith_function_type
+ : diag::ext_gnu_ptr_func_arith)
+ << 0 /* one pointer */ << Pointer->getType()->getPointeeType()
+ << 0 /* one pointer, so only one type */
+ << Pointer->getSourceRange();
+}
+
+/// \brief Check the validity of an arithmetic pointer operand.
+///
+/// If the operand has pointer type, this code will check for pointer types
+/// which are invalid in arithmetic operations. These will be diagnosed
+/// appropriately, including whether or not the use is supported as an
+/// extension.
+///
+/// \returns True when the operand is valid to use (even if as an extension).
+static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
+ Expr *Operand) {
+ if (!Operand->getType()->isAnyPointerType()) return true;
+
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (PointeeTy->isVoidType()) {
+ diagnoseArithmeticOnVoidPointer(S, Loc, Operand);
+ return !S.getLangOptions().CPlusPlus;
+ }
+ if (PointeeTy->isFunctionType()) {
+ diagnoseArithmeticOnFunctionPointer(S, Loc, Operand);
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ if ((Operand->getType()->isPointerType() &&
+ !Operand->getType()->isDependentType()) ||
+ Operand->getType()->isObjCObjectPointerType()) {
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (S.RequireCompleteType(
+ Loc, PointeeTy,
+ S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PointeeTy << Operand->getSourceRange()))
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer
+/// operands.
+///
+/// This routine will diagnose any invalid arithmetic on pointer operands much
+/// like \see checkArithmeticOpPointerOperand. However, it has special logic
+/// for emitting a single diagnostic even for operations where both LHS and RHS
+/// are (potentially problematic) pointers.
+///
+/// \returns True when the operand is valid to use (even if as an extension).
+static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ bool isLHSPointer = LHS->getType()->isAnyPointerType();
+ bool isRHSPointer = RHS->getType()->isAnyPointerType();
+ if (!isLHSPointer && !isRHSPointer) return true;
+
+ QualType LHSPointeeTy, RHSPointeeTy;
+ if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType();
+ if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType();
+
+ // Check for arithmetic on pointers to incomplete types.
+ bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType();
+ bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType();
+ if (isLHSVoidPtr || isRHSVoidPtr) {
+ if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS);
+ else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS);
+ else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS);
+
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType();
+ bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType();
+ if (isLHSFuncPtr || isRHSFuncPtr) {
+ if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS);
+ else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS);
+ else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS);
+
+ return !S.getLangOptions().CPlusPlus;
+ }
+
+ Expr *Operands[] = { LHS, RHS };
+ for (unsigned i = 0; i < 2; ++i) {
+ Expr *Operand = Operands[i];
+ if ((Operand->getType()->isPointerType() &&
+ !Operand->getType()->isDependentType()) ||
+ Operand->getType()->isObjCObjectPointerType()) {
+ QualType PointeeTy = Operand->getType()->getPointeeType();
+ if (S.RequireCompleteType(
+ Loc, PointeeTy,
+ S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
+ << PointeeTy << Operand->getSourceRange()))
+ return false;
+ }
+ }
+ return true;
+}
+
QualType Sema::CheckAdditionOperands( // C99 6.5.6
ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(Loc, lex, rex);
+ QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
@@ -7146,42 +5800,12 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
std::swap(PExp, IExp);
if (PExp->getType()->isAnyPointerType()) {
-
if (IExp->getType()->isIntegerType()) {
- QualType PointeeTy = PExp->getType()->getPointeeType();
-
- // Check for arithmetic on pointers to incomplete types.
- if (PointeeTy->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
+ if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
+ return QualType();
- // GNU extension: arithmetic on pointer to void
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- } else if (PointeeTy->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << lex.get()->getType() << lex.get()->getSourceRange();
- return QualType();
- }
+ QualType PointeeTy = PExp->getType()->getPointeeType();
- // GNU extension: arithmetic on pointer to function
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << lex.get()->getType() << lex.get()->getSourceRange();
- } 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->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
@@ -7209,7 +5833,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
SourceLocation Loc, QualType* CompLHSTy) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(Loc, lex, rex);
+ QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
@@ -7231,35 +5855,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
if (lex.get()->getType()->isAnyPointerType()) {
QualType lpointee = lex.get()->getType()->getPointeeType();
- // The LHS must be an completely-defined object type.
-
- bool ComplainAboutVoid = false;
- Expr *ComplainAboutFunc = 0;
- if (lpointee->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU C extension: arithmetic on pointer to void
- ComplainAboutVoid = true;
- } else if (lpointee->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << lex.get()->getType() << lex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU C extension: arithmetic on pointer to function
- ComplainAboutFunc = lex.get();
- } else if (!lpointee->isDependentType() &&
- RequireCompleteType(Loc, lpointee,
- PDiag(diag::err_typecheck_sub_ptr_object)
- << lex.get()->getSourceRange()
- << lex.get()->getType()))
- return QualType();
-
// Diagnose bad cases where we step over interface counts.
if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
@@ -7269,13 +5864,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
// The result type of a pointer-int computation is the pointer type.
if (rex.get()->getType()->isIntegerType()) {
- if (ComplainAboutVoid)
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- if (ComplainAboutFunc)
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
- << ComplainAboutFunc->getSourceRange();
+ if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get()))
+ return QualType();
if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return lex.get()->getType();
@@ -7285,33 +5875,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
- // RHS must be a completely-type object type.
- // Handle the GNU void* extension.
- if (rpointee->isVoidType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- return QualType();
- }
-
- ComplainAboutVoid = true;
- } else if (rpointee->isFunctionType()) {
- if (getLangOptions().CPlusPlus) {
- Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << rex.get()->getType() << rex.get()->getSourceRange();
- return QualType();
- }
-
- // GNU extension: arithmetic on pointer to function
- if (!ComplainAboutFunc)
- ComplainAboutFunc = rex.get();
- } else if (!rpointee->isDependentType() &&
- RequireCompleteType(Loc, rpointee,
- PDiag(diag::err_typecheck_sub_ptr_object)
- << rex.get()->getSourceRange()
- << rex.get()->getType()))
- return QualType();
-
if (getLangOptions().CPlusPlus) {
// Pointee types must be the same: C++ [expr.add]
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
@@ -7332,13 +5895,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
}
}
- if (ComplainAboutVoid)
- Diag(Loc, diag::ext_gnu_void_ptr)
- << lex.get()->getSourceRange() << rex.get()->getSourceRange();
- if (ComplainAboutFunc)
- Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << ComplainAboutFunc->getType()
- << ComplainAboutFunc->getSourceRange();
+ if (!checkArithmeticBinOpPointerOperands(*this, Loc,
+ lex.get(), rex.get()))
+ return QualType();
if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return Context.getPointerDiffType();
@@ -7394,19 +5953,24 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex,
llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue());
Result = Result.shl(Right);
+ // Print the bit representation of the signed integer as an unsigned
+ // hexadecimal number.
+ llvm::SmallString<40> HexResult;
+ Result.toString(HexResult, 16, /*Signed =*/false, /*Literal =*/true);
+
// If we are only missing a sign bit, this is less likely to result in actual
// bugs -- if the result is cast back to an unsigned type, it will have the
// expected value. Thus we place this behind a different warning that can be
// turned off separately if needed.
if (LeftBits == ResultBits - 1) {
- S.Diag(Loc, diag::warn_shift_result_overrides_sign_bit)
- << Result.toString(10) << LHSTy
+ S.Diag(Loc, diag::warn_shift_result_sets_sign_bit)
+ << HexResult.str() << LHSTy
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
return;
}
S.Diag(Loc, diag::warn_shift_result_gt_typewidth)
- << Result.toString(10) << Result.getMinSignedBits() << LHSTy
+ << HexResult.str() << Result.getMinSignedBits() << LHSTy
<< Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
@@ -7427,7 +5991,7 @@ QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocati
// Vector shifts promote their scalar inputs to vector type.
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
@@ -7720,7 +6284,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
// comparisons of member pointers to null pointer constants.
if (RHSIsNull &&
((lType->isAnyPointerType() || lType->isNullPtrType()) ||
- (!isRelational && lType->isMemberPointerType()))) {
+ (!isRelational &&
+ (lType->isMemberPointerType() || lType->isBlockPointerType())))) {
rex = ImpCastExprToType(rex.take(), lType,
lType->isMemberPointerType()
? CK_NullToMemberPointer
@@ -7729,7 +6294,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
}
if (LHSIsNull &&
((rType->isAnyPointerType() || rType->isNullPtrType()) ||
- (!isRelational && rType->isMemberPointerType()))) {
+ (!isRelational &&
+ (rType->isMemberPointerType() || rType->isBlockPointerType())))) {
lex = ImpCastExprToType(lex.take(), rType,
rType->isMemberPointerType()
? CK_NullToMemberPointer
@@ -7894,7 +6460,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex,
bool isRelational) {
// Check to make sure we're operating on vectors of the same type and width,
// Allowing one side to be a scalar of element type.
- QualType vType = CheckVectorOperands(Loc, lex, rex);
+ QualType vType = CheckVectorOperands(lex, rex, Loc, /*isCompAssign*/false);
if (vType.isNull())
return vType;
@@ -7949,7 +6515,7 @@ inline QualType Sema::CheckBitwiseOperands(
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
if (lex.get()->getType()->hasIntegerRepresentation() &&
rex.get()->getType()->hasIntegerRepresentation())
- return CheckVectorOperands(Loc, lex, rex);
+ return CheckVectorOperands(lex, rex, Loc, isCompAssign);
return InvalidOperands(Loc, lex, rex);
}
@@ -7975,8 +6541,8 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// is a constant.
if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() &&
rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() &&
- // Don't warn in macros.
- !Loc.isMacroID()) {
+ // Don't warn in macros or template instantiations.
+ !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) {
// If the RHS can be constant folded, and if it constant folds to something
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
@@ -8099,7 +6665,43 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
unsigned Diag = 0;
bool NeedType = false;
switch (IsLV) { // C99 6.5.16p2
- case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break;
+ case Expr::MLV_ConstQualified:
+ Diag = diag::err_typecheck_assign_const;
+
+ // In ARC, use some specialized diagnostics for occasions where we
+ // infer 'const'. These are always pseudo-strong variables.
+ if (S.getLangOptions().ObjCAutoRefCount) {
+ DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
+ if (declRef && isa<VarDecl>(declRef->getDecl())) {
+ VarDecl *var = cast<VarDecl>(declRef->getDecl());
+
+ // Use the normal diagnostic if it's pseudo-__strong but the
+ // user actually wrote 'const'.
+ if (var->isARCPseudoStrong() &&
+ (!var->getTypeSourceInfo() ||
+ !var->getTypeSourceInfo()->getType().isConstQualified())) {
+ // There are two pseudo-strong cases:
+ // - self
+ ObjCMethodDecl *method = S.getCurMethodDecl();
+ if (method && var == method->getSelfDecl())
+ Diag = diag::err_typecheck_arr_assign_self;
+
+ // - fast enumeration variables
+ else
+ Diag = diag::err_typecheck_arr_assign_enumeration;
+
+ SourceRange Assign;
+ if (Loc != OrigLoc)
+ Assign = SourceRange(OrigLoc, OrigLoc);
+ S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+ // We need to preserve the AST regardless, so migration tool
+ // can do its job.
+ return false;
+ }
+ }
+ }
+
+ break;
case Expr::MLV_ArrayType:
Diag = diag::err_typecheck_array_not_modifiable_lvalue;
NeedType = true;
@@ -8214,6 +6816,13 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
<< SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc());
}
}
+
+ if (ConvTy == Compatible) {
+ if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
+ checkRetainCycles(LHS, RHS.get());
+ else if (getLangOptions().ObjCAutoRefCount)
+ checkUnsafeExprAssigns(Loc, LHS, RHS.get());
+ }
} else {
// Compound assignment "x += y"
ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType);
@@ -8295,29 +6904,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
QualType PointeeTy = ResType->getPointeeType();
// C99 6.5.2.4p2, 6.5.6p2
- if (PointeeTy->isVoidType()) {
- if (S.getLangOptions().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
- << Op->getSourceRange();
- return QualType();
- }
-
- // Pointer to void is a GNU extension in C.
- S.Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
- } else if (PointeeTy->isFunctionType()) {
- if (S.getLangOptions().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
- << Op->getType() << Op->getSourceRange();
- return QualType();
- }
-
- S.Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
- << ResType << Op->getSourceRange();
- } else if (S.RequireCompleteType(OpLoc, PointeeTy,
- S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
- << Op->getSourceRange()
- << ResType))
+ if (!checkArithmeticOpPointerOperand(S, OpLoc, Op))
return QualType();
+
// Diagnose bad cases where we step over interface counts.
else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) {
S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
@@ -8400,6 +6989,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
LHS.get()->getObjectKind() == OK_ObjCProperty);
const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
+ bool Consumed = false;
+
if (PropRef->isImplicitProperty()) {
// If using property-dot syntax notation for assignment, and there is a
// setter, RHS expression is being passed to the setter argument. So,
@@ -8407,6 +6998,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
ObjCMethodDecl::param_iterator P = SetterMD->param_begin();
LHSTy = (*P)->getType();
+ Consumed = (getLangOptions().ObjCAutoRefCount &&
+ (*P)->hasAttr<NSConsumedAttr>());
// Otherwise, if the getter returns an l-value, just call that.
} else {
@@ -8418,14 +7011,26 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &
return;
}
}
+ } else if (getLangOptions().ObjCAutoRefCount) {
+ const ObjCMethodDecl *setter
+ = PropRef->getExplicitProperty()->getSetterMethodDecl();
+ if (setter) {
+ ObjCMethodDecl::param_iterator P = setter->param_begin();
+ LHSTy = (*P)->getType();
+ Consumed = (*P)->hasAttr<NSConsumedAttr>();
+ }
}
- if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) {
+ if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) ||
+ getLangOptions().ObjCAutoRefCount) {
InitializedEntity Entity =
- InitializedEntity::InitializeParameter(Context, LHSTy);
+ InitializedEntity::InitializeParameter(Context, LHSTy, Consumed);
ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS);
- if (!ArgE.isInvalid())
+ if (!ArgE.isInvalid()) {
RHS = ArgE;
+ if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver())
+ checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get());
+ }
}
}
@@ -8682,8 +7287,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
VK = VK_LValue;
// ...except that certain expressions are never l-values in C.
- if (!S.getLangOptions().CPlusPlus &&
- IsCForbiddenLValueType(S.Context, Result))
+ if (!S.getLangOptions().CPlusPlus && Result.isCForbiddenLValueType())
VK = VK_RValue;
return Result;
@@ -8815,6 +7419,53 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
rhs = move(resolvedRHS);
}
+ // The canonical way to check for a GNU null is with isNullPointerConstant,
+ // but we use a bit of a hack here for speed; this is a relatively
+ // hot path, and isNullPointerConstant is slow.
+ bool LeftNull = isa<GNUNullExpr>(lhs.get()->IgnoreParenImpCasts());
+ bool RightNull = isa<GNUNullExpr>(rhs.get()->IgnoreParenImpCasts());
+
+ // Detect when a NULL constant is used improperly in an expression. These
+ // are mainly cases where the null pointer is used as an integer instead
+ // of a pointer.
+ if (LeftNull || RightNull) {
+ // Avoid analyzing cases where the result will either be invalid (and
+ // diagnosed as such) or entirely valid and not something to warn about.
+ QualType LeftType = lhs.get()->getType();
+ QualType RightType = rhs.get()->getType();
+ if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() &&
+ !LeftType->isFunctionType() &&
+ !RightType->isBlockPointerType() &&
+ !RightType->isMemberPointerType() &&
+ !RightType->isFunctionType()) {
+ if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add ||
+ Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And ||
+ Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign ||
+ Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign ||
+ Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign ||
+ Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) {
+ // These are the operations that would not make sense with a null pointer
+ // no matter what the other expression is.
+ Diag(OpLoc, diag::warn_null_in_arithmetic_operation)
+ << (LeftNull ? lhs.get()->getSourceRange() : SourceRange())
+ << (RightNull ? rhs.get()->getSourceRange() : SourceRange());
+ } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT ||
+ Opc == BO_EQ || Opc == BO_NE) {
+ // These are the operations that would not make sense with a null pointer
+ // if the other expression the other expression is not a pointer.
+ if (LeftNull != RightNull &&
+ !LeftType->isAnyPointerType() &&
+ !LeftType->canDecayToPointerType() &&
+ !RightType->isAnyPointerType() &&
+ !RightType->canDecayToPointerType()) {
+ Diag(OpLoc, diag::warn_null_in_arithmetic_operation)
+ << (LeftNull ? lhs.get()->getSourceRange()
+ : rhs.get()->getSourceRange());
+ }
+ }
+ }
+ }
+
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType());
@@ -8953,28 +7604,46 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
(BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc)))
return;
- if (BinOp::isComparisonOp(lhsopc))
+ if (BinOp::isComparisonOp(lhsopc)) {
+ Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
+ << SourceRange(lhs->getLocStart(), OpLoc)
+ << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc);
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::warn_precedence_bitwise_rel)
- << SourceRange(lhs->getLocStart(), OpLoc)
- << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
Self.PDiag(diag::note_precedence_bitwise_silence)
<< BinOp::getOpcodeStr(lhsopc),
- lhs->getSourceRange(),
+ lhs->getSourceRange());
+ SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
- else if (BinOp::isComparisonOp(rhsopc))
+ } else if (BinOp::isComparisonOp(rhsopc)) {
+ Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
+ << SourceRange(OpLoc, rhs->getLocEnd())
+ << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc);
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::warn_precedence_bitwise_rel)
- << SourceRange(OpLoc, rhs->getLocEnd())
- << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
Self.PDiag(diag::note_precedence_bitwise_silence)
<< BinOp::getOpcodeStr(rhsopc),
- rhs->getSourceRange(),
+ rhs->getSourceRange());
+ SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
- SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
+ SourceRange(lhs->getLocStart(),
+ cast<BinOp>(rhs)->getLHS()->getLocStart()));
+ }
+}
+
+/// \brief It accepts a '&' expr that is inside a '|' one.
+/// Emit a diagnostic together with a fixit hint that wraps the '&' expression
+/// in parentheses.
+static void
+EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc,
+ BinaryOperator *Bop) {
+ assert(Bop->getOpcode() == BO_And);
+ Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or)
+ << Bop->getSourceRange() << OpLoc;
+ SuggestParentheses(Self, Bop->getOperatorLoc(),
+ Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence),
+ Bop->getSourceRange());
}
/// \brief It accepts a '&&' expr that is inside a '||' one.
@@ -8984,12 +7653,11 @@ static void
EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
BinaryOperator *Bop) {
assert(Bop->getOpcode() == BO_LAnd);
+ Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or)
+ << Bop->getSourceRange() << OpLoc;
SuggestParentheses(Self, Bop->getOperatorLoc(),
- Self.PDiag(diag::warn_logical_and_in_logical_or)
- << Bop->getSourceRange() << OpLoc,
Self.PDiag(diag::note_logical_and_in_logical_or_silence),
- Bop->getSourceRange(),
- Self.PDiag(0), SourceRange());
+ Bop->getSourceRange());
}
/// \brief Returns true if the given expression can be evaluated as a constant
@@ -9043,13 +7711,28 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc,
}
}
+/// \brief Look for '&' in the left or right hand of a '|' expr.
+static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc,
+ Expr *OrArg) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrArg)) {
+ if (Bop->getOpcode() == BO_And)
+ return EmitDiagnosticForBitwiseAndInBitwiseOr(S, OpLoc, Bop);
+ }
+}
+
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
/// precedence.
static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
SourceLocation OpLoc, Expr *lhs, Expr *rhs){
// Diagnose "arg1 'bitwise' arg2 'eq' arg3".
if (BinaryOperator::isBitwiseOp(Opc))
- return DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs);
+ DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs);
+
+ // Diagnose "arg1 & arg2 | arg3"
+ if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) {
+ DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs);
+ DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs);
+ }
// Warn about arg1 || arg2 && arg3, as GCC 4.3+ does.
// We don't warn for 'assert(a || b && "bad")' since this is safe.
@@ -9274,6 +7957,29 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
Context.getPointerType(Context.VoidTy)));
}
+/// Given the last statement in a statement-expression, check whether
+/// the result is a producing expression (like a call to an
+/// ns_returns_retained function) and, if so, rebuild it to hoist the
+/// release out of the full-expression. Otherwise, return null.
+/// Cannot fail.
+static Expr *maybeRebuildARCConsumingStmt(Stmt *s) {
+ // Should always be wrapped with one of these.
+ ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(s);
+ if (!cleanups) return 0;
+
+ ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr());
+ if (!cast || cast->getCastKind() != CK_ObjCConsumeObject)
+ return 0;
+
+ // Splice out the cast. This shouldn't modify any interesting
+ // features of the statement.
+ Expr *producer = cast->getSubExpr();
+ assert(producer->getType() == cast->getType());
+ assert(producer->getValueKind() == cast->getValueKind());
+ cleanups->setSubExpr(producer);
+ return cleanups;
+}
+
ExprResult
Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc) { // "({..})"
@@ -9301,6 +8007,7 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
LastLabelStmt = Label;
LastStmt = Label->getSubStmt();
}
+
if (Expr *LastE = dyn_cast<Expr>(LastStmt)) {
// Do function/array conversion on the last expression, but not
// lvalue-to-rvalue. However, initialize an unqualified type.
@@ -9310,12 +8017,24 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
Ty = LastExpr.get()->getType().getUnqualifiedType();
if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) {
- LastExpr = PerformCopyInitialization(
+ // In ARC, if the final expression ends in a consume, splice
+ // the consume out and bind it later. In the alternate case
+ // (when dealing with a retainable type), the result
+ // initialization will create a produce. In both cases the
+ // result will be +1, and we'll need to balance that out with
+ // a bind.
+ if (Expr *rebuiltLastStmt
+ = maybeRebuildARCConsumingStmt(LastExpr.get())) {
+ LastExpr = rebuiltLastStmt;
+ } else {
+ LastExpr = PerformCopyInitialization(
InitializedEntity::InitializeResult(LPLoc,
Ty,
false),
SourceLocation(),
- LastExpr);
+ LastExpr);
+ }
+
if (LastExpr.isInvalid())
return ExprError();
if (LastExpr.get() != 0) {
@@ -9757,7 +8476,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If we don't have a function type, just build one from nothing.
} else {
FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default);
+ EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
}
@@ -9766,15 +8485,25 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BlockTy = Context.getBlockPointerType(BlockTy);
// If needed, diagnose invalid gotos and switches in the block.
- if (getCurFunction()->NeedsScopeChecking() && !hasAnyErrorsInThisFunction())
+ if (getCurFunction()->NeedsScopeChecking() &&
+ !hasAnyUnrecoverableErrorsInThisFunction())
DiagnoseInvalidJumps(cast<CompoundStmt>(Body));
BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
- BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
+ for (BlockDecl::capture_const_iterator ci = BSI->TheDecl->capture_begin(),
+ ce = BSI->TheDecl->capture_end(); ci != ce; ++ci) {
+ const VarDecl *variable = ci->getVariable();
+ QualType T = variable->getType();
+ QualType::DestructionKind destructKind = T.isDestructedType();
+ if (destructKind != QualType::DK_none)
+ getCurFunction()->setHasBranchProtectedScope();
+ }
+ BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
+
return Owned(Result);
}
@@ -9818,8 +8547,41 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
<< OrigExpr->getType() << E->getSourceRange());
}
- // FIXME: Check that type is complete/non-abstract
- // FIXME: Warn if a non-POD type is passed in.
+ if (!TInfo->getType()->isDependentType()) {
+ if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(),
+ PDiag(diag::err_second_parameter_to_va_arg_incomplete)
+ << TInfo->getTypeLoc().getSourceRange()))
+ return ExprError();
+
+ if (RequireNonAbstractType(TInfo->getTypeLoc().getBeginLoc(),
+ TInfo->getType(),
+ PDiag(diag::err_second_parameter_to_va_arg_abstract)
+ << TInfo->getTypeLoc().getSourceRange()))
+ return ExprError();
+
+ if (!TInfo->getType().isPODType(Context))
+ Diag(TInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_second_parameter_to_va_arg_not_pod)
+ << TInfo->getType()
+ << TInfo->getTypeLoc().getSourceRange();
+
+ // Check for va_arg where arguments of the given type will be promoted
+ // (i.e. this va_arg is guaranteed to have undefined behavior).
+ QualType PromoteType;
+ if (TInfo->getType()->isPromotableIntegerType()) {
+ PromoteType = Context.getPromotedIntegerType(TInfo->getType());
+ if (Context.typesAreCompatible(PromoteType, TInfo->getType()))
+ PromoteType = QualType();
+ }
+ if (TInfo->getType()->isSpecificBuiltinType(BuiltinType::Float))
+ PromoteType = Context.DoubleTy;
+ if (!PromoteType.isNull())
+ Diag(TInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_second_parameter_to_va_arg_never_compatible)
+ << TInfo->getType()
+ << PromoteType
+ << TInfo->getTypeLoc().getSourceRange();
+ }
QualType T = TInfo->getType().getNonLValueExprType(Context);
return Owned(new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T));
@@ -9913,6 +8675,11 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (lhq.getAddressSpace() != rhq.getAddressSpace()) {
DiagKind = diag::err_typecheck_incompatible_address_space;
break;
+
+
+ } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) {
+ DiagKind = diag::err_typecheck_incompatible_ownership;
+ break;
}
llvm_unreachable("unknown error case for discarding qualifiers!");
@@ -9950,6 +8717,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatibleVectors:
DiagKind = diag::warn_incompatible_vectors;
break;
+ case IncompatibleObjCWeakRef:
+ DiagKind = diag::err_arc_weak_unavailable_assign;
+ break;
case Incompatible:
DiagKind = diag::err_typecheck_convert_incompatible;
isInvalid = true;
@@ -10027,7 +8797,10 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
void
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
ExprEvalContexts.push_back(
- ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size()));
+ ExpressionEvaluationContextRecord(NewContext,
+ ExprTemporaries.size(),
+ ExprNeedsCleanups));
+ ExprNeedsCleanups = false;
}
void
@@ -10062,15 +8835,27 @@ Sema::PopExpressionEvaluationContext() {
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
// will never be constructed.
- if (Rec.Context == Unevaluated &&
- ExprTemporaries.size() > Rec.NumTemporaries)
+ if (Rec.Context == Unevaluated) {
ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries,
ExprTemporaries.end());
+ ExprNeedsCleanups = Rec.ParentNeedsCleanups;
+
+ // Otherwise, merge the contexts together.
+ } else {
+ ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
+ }
// Destroy the popped expression evaluation record.
Rec.Destroy();
}
+void Sema::DiscardCleanupsInEvaluationContext() {
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
+ ExprNeedsCleanups = false;
+}
+
/// \brief Note that the given declaration was referenced in the source code.
///
/// This routine should be invoke whenever a given declaration is referenced
@@ -10364,7 +9149,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) {
/// during overload resolution or within sizeof/alignof/typeof/typeid.
bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt,
const PartialDiagnostic &PD) {
- switch (ExprEvalContexts.back().Context ) {
+ switch (ExprEvalContexts.back().Context) {
case Unevaluated:
// The argument will never be evaluated, so don't complain.
break;
@@ -10780,9 +9565,6 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) {
}
ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
- ObjCMethodDecl *method = msg->getMethodDecl();
- assert(method && "__unknown_anytype message without result type?");
-
// Verify that this is a legal result type of a call.
if (DestType->isArrayType() || DestType->isFunctionType()) {
S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function)
@@ -10790,8 +9572,11 @@ ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
return ExprError();
}
- assert(method->getResultType() == S.Context.UnknownAnyTy);
- method->setResultType(DestType);
+ // Rewrite the method result type if available.
+ if (ObjCMethodDecl *method = msg->getMethodDecl()) {
+ assert(method->getResultType() == S.Context.UnknownAnyTy);
+ method->setResultType(DestType);
+ }
// Change the type of the message.
msg->setType(DestType.getNonReferenceType());