diff options
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 735 |
1 files changed, 654 insertions, 81 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 9052278..d22deb2 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -19,6 +19,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtObjC.h" @@ -28,7 +29,21 @@ #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" using namespace clang; using namespace sema; @@ -150,10 +165,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (!E) return; + const Expr *WarnExpr; SourceLocation Loc; SourceRange R1, R2; if (SourceMgr.isInSystemMacro(E->getExprLoc()) || - !E->isUnusedResultAWarning(Loc, R1, R2, Context)) + !E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context)) return; // Okay, we have an unused result. Depending on what the base expression is, @@ -168,7 +184,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (DiagnoseUnusedComparison(*this, E)) return; - E = E->IgnoreParenImpCasts(); + E = WarnExpr; if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { if (E->getType()->isVoidType()) return; @@ -226,6 +242,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } + if (E->isGLValue() && E->getType().isVolatileQualified()) { + Diag(Loc, diag::warn_unused_volatile) << R1 << R2; + return; + } + DiagRuntimeBehavior(Loc, 0, PDiag(DiagID) << R1 << R2); } @@ -361,12 +382,10 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, } StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc, - const AttrVec &Attrs, + ArrayRef<const Attr*> Attrs, Stmt *SubStmt) { - // Fill in the declaration and return it. Variable length will require to - // change this to AttributedStmt::Create(Context, ....); - // and probably using ArrayRef - AttributedStmt *LS = new (Context) AttributedStmt(AttrLoc, Attrs, SubStmt); + // Fill in the declaration and return it. + AttributedStmt *LS = AttributedStmt::Create(Context, AttrLoc, Attrs, SubStmt); return Owned(LS); } @@ -519,16 +538,56 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, if (!Cond) return StmtError(); + class SwitchConvertDiagnoser : public ICEConvertDiagnoser { + Expr *Cond; + + public: + SwitchConvertDiagnoser(Expr *Cond) + : ICEConvertDiagnoser(false, true), Cond(Cond) { } + + virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; + } + + virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_switch_incomplete_class_type) + << T << Cond->getSourceRange(); + } + + virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, + QualType T, + QualType ConvTy) { + return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy; + } + + virtual DiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, + QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_switch_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_switch_multiple_conversions) << T; + } + + virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, + QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_switch_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, + QualType T, + QualType ConvTy) { + return DiagnosticBuilder::getEmpty(); + } + } SwitchDiagnoser(Cond); + CondResult - = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, - PDiag(diag::err_typecheck_statement_requires_integer), - PDiag(diag::err_switch_incomplete_class_type) - << Cond->getSourceRange(), - PDiag(diag::err_switch_explicit_conversion), - PDiag(diag::note_switch_conversion), - PDiag(diag::err_switch_multiple_conversions), - PDiag(diag::note_switch_conversion), - PDiag(0), + = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, SwitchDiagnoser, /*AllowScopedEnumerations*/ true); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); @@ -609,7 +668,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); unsigned CondWidth = HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion); - bool CondIsSigned + bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerOrEnumerationType(); // Accumulate all of the case values in a vector so that we can sort them @@ -726,8 +785,30 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (i != 0 && CaseVals[i].first == CaseVals[i-1].first) { // If we have a duplicate, report it. - Diag(CaseVals[i].second->getLHS()->getLocStart(), - diag::err_duplicate_case) << CaseVals[i].first.toString(10); + // First, determine if either case value has a name + StringRef PrevString, CurrString; + Expr *PrevCase = CaseVals[i-1].second->getLHS()->IgnoreParenCasts(); + Expr *CurrCase = CaseVals[i].second->getLHS()->IgnoreParenCasts(); + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(PrevCase)) { + PrevString = DeclRef->getDecl()->getName(); + } + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(CurrCase)) { + CurrString = DeclRef->getDecl()->getName(); + } + llvm::SmallString<16> CaseValStr; + CaseVals[i-1].first.toString(CaseValStr); + + if (PrevString == CurrString) + Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::err_duplicate_case) << + (PrevString.empty() ? CaseValStr.str() : PrevString); + else + Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::err_duplicate_case_differing_expr) << + (PrevString.empty() ? CaseValStr.str() : PrevString) << + (CurrString.empty() ? CaseValStr.str() : CurrString) << + CaseValStr; + Diag(CaseVals[i-1].second->getLHS()->getLocStart(), diag::note_duplicate_case_prev); // FIXME: We really want to remove the bogus case stmt from the @@ -904,7 +985,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, << CondTypeBeforePromotion; } - llvm::APSInt Hi = + llvm::APSInt Hi = RI->second->getRHS()->EvaluateKnownConstInt(Context); AdjustAPSInt(Hi, CondWidth, CondIsSigned); while (EI != EIend && EI->first < Hi) @@ -952,12 +1033,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, switch (UnhandledNames.size()) { case 0: break; case 1: - Diag(CondExpr->getExprLoc(), TheDefaultStmt + Diag(CondExpr->getExprLoc(), TheDefaultStmt ? diag::warn_def_missing_case1 : diag::warn_missing_case1) << UnhandledNames[0]; break; case 2: - Diag(CondExpr->getExprLoc(), TheDefaultStmt + Diag(CondExpr->getExprLoc(), TheDefaultStmt ? diag::warn_def_missing_case2 : diag::warn_missing_case2) << UnhandledNames[0] << UnhandledNames[1]; break; @@ -990,6 +1071,55 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, return Owned(SS); } +void +Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, + Expr *SrcExpr) { + unsigned DIAG = diag::warn_not_in_enum_assignement; + if (Diags.getDiagnosticLevel(DIAG, SrcExpr->getExprLoc()) + == DiagnosticsEngine::Ignored) + return; + + if (const EnumType *ET = DstType->getAs<EnumType>()) + if (!Context.hasSameType(SrcType, DstType) && + SrcType->isIntegerType()) { + if (!SrcExpr->isTypeDependent() && !SrcExpr->isValueDependent() && + SrcExpr->isIntegerConstantExpr(Context)) { + // Get the bitwidth of the enum value before promotions. + unsigned DstWith = Context.getIntWidth(DstType); + bool DstIsSigned = DstType->isSignedIntegerOrEnumerationType(); + + llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context); + const EnumDecl *ED = ET->getDecl(); + typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> + EnumValsTy; + EnumValsTy EnumVals; + + // Gather all enum values, set their type and sort them, + // allowing easier comparison with rhs constant. + for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); + EDI != ED->enumerator_end(); ++EDI) { + llvm::APSInt Val = EDI->getInitVal(); + AdjustAPSInt(Val, DstWith, DstIsSigned); + EnumVals.push_back(std::make_pair(Val, *EDI)); + } + if (EnumVals.empty()) + return; + std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); + EnumValsTy::iterator EIend = + std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); + + // See which case values aren't in enum. + EnumValsTy::const_iterator EI = EnumVals.begin(); + while (EI != EIend && EI->first < RhsVal) + EI++; + if (EI == EIend || EI->first != RhsVal) { + Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignement) + << DstType; + } + } + } +} + StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, Decl *CondVar, Stmt *Body) { @@ -1037,6 +1167,215 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, return Owned(new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen)); } +namespace { + // This visitor will traverse a conditional statement and store all + // the evaluated decls into a vector. Simple is set to true if none + // of the excluded constructs are used. + class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> { + llvm::SmallPtrSet<VarDecl*, 8> &Decls; + llvm::SmallVector<SourceRange, 10> &Ranges; + bool Simple; +public: + typedef EvaluatedExprVisitor<DeclExtractor> Inherited; + + DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, + llvm::SmallVector<SourceRange, 10> &Ranges) : + Inherited(S.Context), + Decls(Decls), + Ranges(Ranges), + Simple(true) {} + + bool isSimple() { return Simple; } + + // Replaces the method in EvaluatedExprVisitor. + void VisitMemberExpr(MemberExpr* E) { + Simple = false; + } + + // Any Stmt not whitelisted will cause the condition to be marked complex. + void VisitStmt(Stmt *S) { + Simple = false; + } + + void VisitBinaryOperator(BinaryOperator *E) { + Visit(E->getLHS()); + Visit(E->getRHS()); + } + + void VisitCastExpr(CastExpr *E) { + Visit(E->getSubExpr()); + } + + void VisitUnaryOperator(UnaryOperator *E) { + // Skip checking conditionals with derefernces. + if (E->getOpcode() == UO_Deref) + Simple = false; + else + Visit(E->getSubExpr()); + } + + void VisitConditionalOperator(ConditionalOperator *E) { + Visit(E->getCond()); + Visit(E->getTrueExpr()); + Visit(E->getFalseExpr()); + } + + void VisitParenExpr(ParenExpr *E) { + Visit(E->getSubExpr()); + } + + void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { + Visit(E->getOpaqueValue()->getSourceExpr()); + Visit(E->getFalseExpr()); + } + + void VisitIntegerLiteral(IntegerLiteral *E) { } + void VisitFloatingLiteral(FloatingLiteral *E) { } + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { } + void VisitCharacterLiteral(CharacterLiteral *E) { } + void VisitGNUNullExpr(GNUNullExpr *E) { } + void VisitImaginaryLiteral(ImaginaryLiteral *E) { } + + void VisitDeclRefExpr(DeclRefExpr *E) { + VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()); + if (!VD) return; + + Ranges.push_back(E->getSourceRange()); + + Decls.insert(VD); + } + + }; // end class DeclExtractor + + // DeclMatcher checks to see if the decls are used in a non-evauluated + // context. + class DeclMatcher : public EvaluatedExprVisitor<DeclMatcher> { + llvm::SmallPtrSet<VarDecl*, 8> &Decls; + bool FoundDecl; + +public: + typedef EvaluatedExprVisitor<DeclMatcher> Inherited; + + DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, Stmt *Statement) : + Inherited(S.Context), Decls(Decls), FoundDecl(false) { + if (!Statement) return; + + Visit(Statement); + } + + void VisitReturnStmt(ReturnStmt *S) { + FoundDecl = true; + } + + void VisitBreakStmt(BreakStmt *S) { + FoundDecl = true; + } + + void VisitGotoStmt(GotoStmt *S) { + FoundDecl = true; + } + + void VisitCastExpr(CastExpr *E) { + if (E->getCastKind() == CK_LValueToRValue) + CheckLValueToRValueCast(E->getSubExpr()); + else + Visit(E->getSubExpr()); + } + + void CheckLValueToRValueCast(Expr *E) { + E = E->IgnoreParenImpCasts(); + + if (isa<DeclRefExpr>(E)) { + return; + } + + if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + Visit(CO->getCond()); + CheckLValueToRValueCast(CO->getTrueExpr()); + CheckLValueToRValueCast(CO->getFalseExpr()); + return; + } + + if (BinaryConditionalOperator *BCO = + dyn_cast<BinaryConditionalOperator>(E)) { + CheckLValueToRValueCast(BCO->getOpaqueValue()->getSourceExpr()); + CheckLValueToRValueCast(BCO->getFalseExpr()); + return; + } + + Visit(E); + } + + void VisitDeclRefExpr(DeclRefExpr *E) { + if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) + if (Decls.count(VD)) + FoundDecl = true; + } + + bool FoundDeclInUse() { return FoundDecl; } + + }; // end class DeclMatcher + + void CheckForLoopConditionalStatement(Sema &S, Expr *Second, + Expr *Third, Stmt *Body) { + // Condition is empty + if (!Second) return; + + if (S.Diags.getDiagnosticLevel(diag::warn_variables_not_in_loop_body, + Second->getLocStart()) + == DiagnosticsEngine::Ignored) + return; + + PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body); + llvm::SmallPtrSet<VarDecl*, 8> Decls; + llvm::SmallVector<SourceRange, 10> Ranges; + DeclExtractor DE(S, Decls, Ranges); + DE.Visit(Second); + + // Don't analyze complex conditionals. + if (!DE.isSimple()) return; + + // No decls found. + if (Decls.size() == 0) return; + + // Don't warn on volatile, static, or global variables. + for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) + if ((*I)->getType().isVolatileQualified() || + (*I)->hasGlobalStorage()) return; + + if (DeclMatcher(S, Decls, Second).FoundDeclInUse() || + DeclMatcher(S, Decls, Third).FoundDeclInUse() || + DeclMatcher(S, Decls, Body).FoundDeclInUse()) + return; + + // Load decl names into diagnostic. + if (Decls.size() > 4) + PDiag << 0; + else { + PDiag << Decls.size(); + for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) + PDiag << (*I)->getDeclName(); + } + + // Load SourceRanges into diagnostic if there is room. + // Otherwise, load the SourceRange of the conditional expression. + if (Ranges.size() <= PartialDiagnostic::MaxArguments) + for (llvm::SmallVector<SourceRange, 10>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) + PDiag << *I; + else + PDiag << Second->getSourceRange(); + + S.Diag(Ranges.begin()->getBegin(), PDiag); + } + +} // end namespace + StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *First, FullExprArg second, Decl *secondVar, @@ -1059,6 +1398,8 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, } } + CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body); + ExprResult SecondResult(second.release()); VarDecl *ConditionVar = 0; if (secondVar) { @@ -1103,8 +1444,9 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) { } ExprResult -Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { - assert(collection); +Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { + if (!collection) + return ExprError(); // Bail out early if we've got a type-dependent expression. if (collection->isTypeDependent()) return Owned(collection); @@ -1130,12 +1472,12 @@ Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { // If we have a forward-declared type, we can't do this check. // Under ARC, it is an error not to have a forward-declared class. - if (iface && + if (iface && RequireCompleteType(forLoc, QualType(objectType, 0), getLangOpts().ObjCAutoRefCount - ? PDiag(diag::err_arc_collection_forward) - << collection->getSourceRange() - : PDiag(0))) { + ? diag::err_arc_collection_forward + : 0, + collection)) { // Otherwise, if we have any useful type information, check that // the type declares the appropriate method. } else if (iface || !objectType->qual_empty()) { @@ -1151,7 +1493,7 @@ Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { // If there's an interface, look in both the public and private APIs. if (iface) { method = iface->lookupInstanceMethod(selector); - if (!method) method = LookupPrivateInstanceMethod(selector, iface); + if (!method) method = iface->lookupPrivateMethod(selector); } // Also check protocol qualifiers. @@ -1175,8 +1517,12 @@ Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - Stmt *First, Expr *Second, - SourceLocation RParenLoc, Stmt *Body) { + Stmt *First, Expr *collection, + SourceLocation RParenLoc) { + + ExprResult CollectionExprResult = + CheckObjCForCollectionOperand(ForLoc, collection); + if (First) { QualType FirstType; if (DeclStmt *DS = dyn_cast<DeclStmt>(First)) { @@ -1204,11 +1550,15 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, if (!FirstType->isDependentType() && !FirstType->isObjCObjectPointerType() && !FirstType->isBlockPointerType()) - Diag(ForLoc, diag::err_selector_element_type) - << FirstType << First->getSourceRange(); + return StmtError(Diag(ForLoc, diag::err_selector_element_type) + << FirstType << First->getSourceRange()); } - return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body, + if (CollectionExprResult.isInvalid()) + return StmtError(); + + return Owned(new (Context) ObjCForCollectionStmt(First, + CollectionExprResult.take(), 0, ForLoc, RParenLoc)); } @@ -1252,7 +1602,7 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, // In ARC, infer lifetime. // FIXME: ARC may want to turn this into 'const __unsafe_unretained' if // we're doing the equivalent of fast iteration. - if (SemaRef.getLangOpts().ObjCAutoRefCount && + if (SemaRef.getLangOpts().ObjCAutoRefCount && SemaRef.inferObjCARCLifetime(Decl)) Decl->setInvalidDecl(); @@ -1343,6 +1693,11 @@ static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S, } +static bool ObjCEnumerationCollection(Expr *Collection) { + return !Collection->isTypeDependent() + && Collection->getType()->getAs<ObjCObjectPointerType>() != 0; +} + /// ActOnCXXForRangeStmt - Check and build a C++0x for-range statement. /// /// C++0x [stmt.ranged]: @@ -1368,6 +1723,10 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc, if (!First || !Range) return StmtError(); + if (ObjCEnumerationCollection(Range)) + return ActOnObjCForCollectionStmt(ForLoc, LParenLoc, First, Range, + RParenLoc); + DeclStmt *DS = dyn_cast<DeclStmt>(First); assert(DS && "first part of for range not a decl stmt"); @@ -1442,7 +1801,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, QualType RangeType = Range->getType(); if (RequireCompleteType(RangeLoc, RangeType, - PDiag(diag::err_for_range_incomplete_type))) + diag::err_for_range_incomplete_type)) return StmtError(); // Build auto __begin = begin-expr, __end = end-expr. @@ -1618,6 +1977,17 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, ColonLoc, RParenLoc)); } +/// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach +/// statement. +StmtResult Sema::FinishObjCForCollectionStmt(Stmt *S, Stmt *B) { + if (!S || !B) + return StmtError(); + ObjCForCollectionStmt * ForStmt = cast<ObjCForCollectionStmt>(S); + + ForStmt->setBody(B); + return S; +} + /// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement. /// This is a separate step from ActOnCXXForRangeStmt because analysis of the /// body cannot be performed until after the type of the range variable is @@ -1626,6 +1996,9 @@ StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) { if (!S || !B) return StmtError(); + if (isa<ObjCForCollectionStmt>(S)) + return FinishObjCForCollectionStmt(S, B); + CXXForRangeStmt *ForStmt = cast<CXXForRangeStmt>(S); ForStmt->setBody(B); @@ -1723,7 +2096,7 @@ const VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, // ... the expression is the name of a non-volatile automatic object // (other than a function or catch-clause parameter)) ... const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()); - if (!DR) + if (!DR || DR->refersToEnclosingLocal()) return 0; const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) @@ -1776,8 +2149,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, if (AllowNRVO && (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) { ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, - Value->getType(), CK_LValueToRValue, - Value, VK_XValue); + Value->getType(), CK_NoOp, Value, VK_XValue); Expr *InitExpr = &AsRvalue; InitializationKind Kind @@ -1812,8 +2184,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // Promote "AsRvalue" to the heap, since we now need this // expression node to persist. Value = ImplicitCastExpr::Create(Context, Value->getType(), - CK_LValueToRValue, Value, 0, - VK_XValue); + CK_NoOp, Value, 0, VK_XValue); // Complete type-checking the initialization of the return type // using the constructor we found. @@ -1840,8 +2211,12 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // [expr.prim.lambda]p4 in C++11; block literals follow a superset of those // rules which allows multiple return statements. CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); + QualType FnRetType = CurCap->ReturnType; + + // For blocks/lambdas with implicit return types, we check each return + // statement individually, and deduce the common return type when the block + // or lambda is completed. if (CurCap->HasImplicitReturnType) { - QualType ReturnT; if (RetValExp && !isa<InitListExpr>(RetValExp)) { ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp); if (Result.isInvalid()) @@ -1849,10 +2224,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { RetValExp = Result.take(); if (!RetValExp->isTypeDependent()) - ReturnT = RetValExp->getType(); + FnRetType = RetValExp->getType(); else - ReturnT = Context.DependentTy; - } else { + FnRetType = CurCap->ReturnType = Context.DependentTy; + } else { if (RetValExp) { // C++11 [expr.lambda.prim]p4 bans inferring the result from an // initializer list, because it is not an expression (even @@ -1861,21 +2236,14 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { << RetValExp->getSourceRange(); } - ReturnT = Context.VoidTy; - } - // We require the return types to strictly match here. - if (!CurCap->ReturnType.isNull() && - !CurCap->ReturnType->isDependentType() && - !ReturnT->isDependentType() && - !Context.hasSameType(ReturnT, CurCap->ReturnType)) { - Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << ReturnT << CurCap->ReturnType - << (getCurLambda() != 0); - return StmtError(); + FnRetType = Context.VoidTy; } - CurCap->ReturnType = ReturnT; + + // Although we'll properly infer the type of the block once it's completed, + // make sure we provide a return type now for better error recovery. + if (CurCap->ReturnType.isNull()) + CurCap->ReturnType = FnRetType; } - QualType FnRetType = CurCap->ReturnType; assert(!FnRetType.isNull()); if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) { @@ -1943,10 +2311,12 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); - // If we need to check for the named return value optimization, save the - // return statement in our scope for later processing. - if (getLangOpts().CPlusPlus && FnRetType->isRecordType() && - !CurContext->isDependentContext()) + // If we need to check for the named return value optimization, + // or if we need to infer the return type, + // save the return statement in our scope for later processing. + if (CurCap->HasImplicitReturnType || + (getLangOpts().CPlusPlus && FnRetType->isRecordType() && + !CurContext->isDependentContext())) FunctionScopes.back()->Returns.push_back(Result); return Owned(Result); @@ -1957,7 +2327,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Check for unexpanded parameter packs. if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); - + if (isa<CapturingScopeInfo>(getCurFunction())) return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); @@ -1973,7 +2343,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { FnRetType = MD->getResultType(); if (MD->hasRelatedResultType() && MD->getClassInterface()) { // In the implementation of a method with a related return type, the - // type used to type-check the validity of return statements within the + // type used to type-check the validity of return statements within the // method body is a pointer to the type of the class being implemented. RelatedRetType = Context.getObjCInterfaceType(MD->getClassInterface()); RelatedRetType = Context.getObjCObjectPointerType(RelatedRetType); @@ -2064,7 +2434,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // FIXME: The diagnostics here don't really describe what is happening. InitializedEntity Entity = InitializedEntity::InitializeTemporary(RelatedRetType); - + ExprResult Res = PerformCopyInitialization(Entity, SourceLocation(), RetValExp); if (Res.isInvalid()) { @@ -2108,7 +2478,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (getLangOpts().CPlusPlus && FnRetType->isRecordType() && !CurContext->isDependentContext()) FunctionScopes.back()->Returns.push_back(Result); - + return Owned(Result); } @@ -2147,18 +2517,17 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) { /// isOperandMentioned - Return true if the specified operand # is mentioned /// anywhere in the decomposed asm string. -static bool isOperandMentioned(unsigned OpNo, +static bool isOperandMentioned(unsigned OpNo, ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) { for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) { const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p]; if (!Piece.isOperand()) continue; - + // If this is a reference to the input and if the input was the smaller // one, then we have to reject this asm. if (Piece.getOperandNo() == OpNo) return true; } - return false; } @@ -2343,7 +2712,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, // then we can promote the smaller one to a larger input and the asm string // won't notice. bool SmallerValueMentioned = false; - + // If this is a reference to the input and if the input was the smaller // one, then we have to reject this asm. if (isOperandMentioned(InputOpNo, Pieces)) { @@ -2364,7 +2733,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, if (!SmallerValueMentioned && InputDomain != AD_Other && OutputConstraintInfos[TiedTo].allowsRegister()) continue; - + // Either both of the operands were mentioned or the smaller one was // mentioned. One more special case that we'll allow: if the tied input is // integer, unmentioned, and is a constant, then we'll allow truncating it @@ -2379,7 +2748,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, NS->setInputExpr(i, InputExpr); continue; } - + Diag(InputExpr->getLocStart(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() @@ -2390,6 +2759,213 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, return Owned(NS); } +// needSpaceAsmToken - This function handles whitespace around asm punctuation. +// Returns true if a space should be emitted. +static inline bool needSpaceAsmToken(Token currTok) { + static Token prevTok; + + // No need for space after prevToken. + switch(prevTok.getKind()) { + default: + break; + case tok::l_square: + case tok::r_square: + case tok::l_brace: + case tok::r_brace: + case tok::colon: + prevTok = currTok; + return false; + } + + // No need for a space before currToken. + switch(currTok.getKind()) { + default: + break; + case tok::l_square: + case tok::r_square: + case tok::l_brace: + case tok::r_brace: + case tok::comma: + case tok::colon: + prevTok = currTok; + return false; + } + prevTok = currTok; + return true; +} + +static void patchMSAsmStrings(Sema &SemaRef, bool &IsSimple, + SourceLocation AsmLoc, + ArrayRef<Token> AsmToks, + ArrayRef<unsigned> LineEnds, + const TargetInfo &TI, + std::vector<std::string> &AsmStrings) { + assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); + + // Assume simple asm stmt until we parse a non-register identifer. + IsSimple = true; + + for (unsigned i = 0, e = LineEnds.size(); i != e; ++i) { + SmallString<512> Asm; + + // Check the operands. + for (unsigned j = (i == 0) ? 0 : LineEnds[i-1], e = LineEnds[i]; j != e; ++j) { + + IdentifierInfo *II; + if (j == 0 || (i > 0 && j == LineEnds[i-1])) { + II = AsmToks[j].getIdentifierInfo(); + Asm = II->getName().str(); + continue; + } + + if (needSpaceAsmToken(AsmToks[j])) + Asm += " "; + + switch (AsmToks[j].getKind()) { + default: + //llvm_unreachable("Unknown token."); + break; + case tok::comma: Asm += ","; break; + case tok::colon: Asm += ":"; break; + case tok::l_square: Asm += "["; break; + case tok::r_square: Asm += "]"; break; + case tok::l_brace: Asm += "{"; break; + case tok::r_brace: Asm += "}"; break; + case tok::numeric_constant: { + SmallString<32> TokenBuf; + TokenBuf.resize(32); + bool StringInvalid = false; + Asm += SemaRef.PP.getSpelling(AsmToks[j], TokenBuf, &StringInvalid); + assert (!StringInvalid && "Expected valid string!"); + break; + } + case tok::identifier: { + II = AsmToks[j].getIdentifierInfo(); + StringRef Name = II->getName(); + + // Valid registers don't need modification. + if (TI.isValidGCCRegisterName(Name)) { + Asm += Name; + break; + } + + // TODO: Lookup the identifier. + IsSimple = false; + } + } // AsmToks[i].getKind() + } + AsmStrings[i] = Asm.c_str(); + } +} + +// Build the unmodified MSAsmString. +static std::string buildMSAsmString(Sema &SemaRef, + ArrayRef<Token> AsmToks, + ArrayRef<unsigned> LineEnds) { + assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); + SmallString<512> Asm; + SmallString<512> TokenBuf; + TokenBuf.resize(512); + unsigned AsmLineNum = 0; + for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { + const char *ThisTokBuf = &TokenBuf[0]; + bool StringInvalid = false; + unsigned ThisTokLen = + Lexer::getSpelling(AsmToks[i], ThisTokBuf, SemaRef.getSourceManager(), + SemaRef.getLangOpts(), &StringInvalid); + if (i && (!AsmLineNum || i != LineEnds[AsmLineNum-1]) && + needSpaceAsmToken(AsmToks[i])) + Asm += ' '; + Asm += StringRef(ThisTokBuf, ThisTokLen); + if (i + 1 == LineEnds[AsmLineNum] && i + 1 != AsmToks.size()) { + Asm += '\n'; + ++AsmLineNum; + } + } + return Asm.c_str(); +} + +StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, + ArrayRef<Token> AsmToks, + ArrayRef<unsigned> LineEnds, + SourceLocation EndLoc) { + // MS-style inline assembly is not fully supported, so emit a warning. + Diag(AsmLoc, diag::warn_unsupported_msasm); + SmallVector<StringRef,4> Clobbers; + + // Empty asm statements don't need to instantiate the AsmParser, etc. + if (AsmToks.empty()) { + StringRef AsmString; + MSAsmStmt *NS = + new (Context) MSAsmStmt(Context, AsmLoc, /* IsSimple */ true, + /* IsVolatile */ true, AsmToks, LineEnds, + AsmString, Clobbers, EndLoc); + return Owned(NS); + } + + std::string AsmString = buildMSAsmString(*this, AsmToks, LineEnds); + + bool IsSimple; + std::vector<std::string> PatchedAsmStrings; + PatchedAsmStrings.resize(LineEnds.size()); + + // Rewrite operands to appease the AsmParser. + patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks, LineEnds, + Context.getTargetInfo(), PatchedAsmStrings); + + // patchMSAsmStrings doesn't correctly patch non-simple asm statements. + if (!IsSimple) { + MSAsmStmt *NS = + new (Context) MSAsmStmt(Context, AsmLoc, /* IsSimple */ true, + /* IsVolatile */ true, AsmToks, LineEnds, + AsmString, Clobbers, EndLoc); + return Owned(NS); + } + + // Initialize targets and assembly printers/parsers. + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + + // Get the target specific parser. + std::string Error; + const std::string &TT = Context.getTargetInfo().getTriple().getTriple(); + const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error)); + + OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); + OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); + OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); + OwningPtr<llvm::MCSubtargetInfo> + STI(TheTarget->createMCSubtargetInfo(TT, "", "")); + + for (unsigned i = 0, e = PatchedAsmStrings.size(); i != e; ++i) { + llvm::SourceMgr SrcMgr; + llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); + llvm::MemoryBuffer *Buffer = + llvm::MemoryBuffer::getMemBuffer(PatchedAsmStrings[i], "<inline asm>"); + + // Tell SrcMgr about this buffer, which is what the parser will pick up. + SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); + + OwningPtr<llvm::MCStreamer> Str; + OwningPtr<llvm::MCAsmParser> + Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); + OwningPtr<llvm::MCTargetAsmParser> + TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); + // Change to the Intel dialect. + Parser->setAssemblerDialect(1); + Parser->setTargetParser(*TargetParser.get()); + + // TODO: Start parsing. + } + + MSAsmStmt *NS = + new (Context) MSAsmStmt(Context, AsmLoc, IsSimple, /* IsVolatile */ true, + AsmToks, LineEnds, AsmString, Clobbers, EndLoc); + + return Owned(NS); +} + StmtResult Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, Decl *Parm, @@ -2420,15 +2996,13 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, Finally)); } -StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, - Expr *Throw) { +StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) { if (Throw) { - Throw = MaybeCreateExprWithCleanups(Throw); ExprResult Result = DefaultLvalueConversion(Throw); if (Result.isInvalid()) return StmtError(); - Throw = Result.take(); + Throw = MaybeCreateExprWithCleanups(Result.take()); QualType ThrowType = Throw->getType(); // Make sure the expression type is an ObjC pointer or "void *". if (!ThrowType->isDependentType() && @@ -2458,7 +3032,6 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, if (!AtCatchParent) return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); } - return BuildObjCAtThrowStmt(AtLoc, Throw); } @@ -2646,17 +3219,17 @@ StmtResult Sema::BuildMSDependentExistsStmt(SourceLocation KeywordLoc, Stmt *Nested) { return new (Context) MSDependentExistsStmt(KeywordLoc, IsIfExists, - QualifierLoc, NameInfo, + QualifierLoc, NameInfo, cast<CompoundStmt>(Nested)); } -StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, +StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, - CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, Stmt *Nested) { - return BuildMSDependentExistsStmt(KeywordLoc, IsIfExists, + return BuildMSDependentExistsStmt(KeywordLoc, IsIfExists, SS.getWithLocInContext(Context), GetNameFromUnqualifiedId(Name), Nested); |