diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-05-15 23:57:33 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-05-15 23:57:33 +0000 |
commit | dbb26db1d426fb6caaaf1b4fa47b46d1947c12c9 (patch) | |
tree | 7f9391cb5b808d440b7acd28628112a616cae5fc | |
parent | c13b7ca5f5c81d0a526bda179d3cd700882e713e (diff) |
Template instantiation for switch statements
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71916 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Stmt.h | 20 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderStmt.cpp | 3 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterStmt.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 257 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateStmt.cpp | 69 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-function-1.cpp | 30 |
6 files changed, 263 insertions, 119 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 1159ef3ffa..698da72abd 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -417,14 +417,20 @@ class CaseStmt : public SwitchCase { Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for // GNU "case 1 ... 4" extension SourceLocation CaseLoc; + SourceLocation EllipsisLoc; + SourceLocation ColonLoc; + virtual Stmt* v_getSubStmt() { return getSubStmt(); } public: - CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc) + CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, + SourceLocation ellipsisLoc, SourceLocation colonLoc) : SwitchCase(CaseStmtClass) { SubExprs[SUBSTMT] = 0; SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs); SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs); CaseLoc = caseLoc; + EllipsisLoc = ellipsisLoc; + ColonLoc = colonLoc; } /// \brief Build an empty switch case statement. @@ -432,6 +438,10 @@ public: SourceLocation getCaseLoc() const { return CaseLoc; } void setCaseLoc(SourceLocation L) { CaseLoc = L; } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); } Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); } @@ -471,10 +481,12 @@ public: class DefaultStmt : public SwitchCase { Stmt* SubStmt; SourceLocation DefaultLoc; + SourceLocation ColonLoc; virtual Stmt* v_getSubStmt() { return getSubStmt(); } public: - DefaultStmt(SourceLocation DL, Stmt *substmt) : - SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL) {} + DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : + SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL), + ColonLoc(CL) {} /// \brief Build an empty default statement. explicit DefaultStmt(EmptyShell) : SwitchCase(DefaultStmtClass) { } @@ -485,6 +497,8 @@ public: SourceLocation getDefaultLoc() const { return DefaultLoc; } void setDefaultLoc(SourceLocation L) { DefaultLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } virtual SourceRange getSourceRange() const { return SourceRange(DefaultLoc, SubStmt->getLocEnd()); diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 2daedbf0c3..a729003a99 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -147,6 +147,8 @@ unsigned PCHStmtReader::VisitCaseStmt(CaseStmt *S) { S->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2])); S->setSubStmt(StmtStack.back()); S->setCaseLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setEllipsisLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); return 3; } @@ -154,6 +156,7 @@ unsigned PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) { VisitSwitchCase(S); S->setSubStmt(StmtStack.back()); S->setDefaultLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); return 1; } diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 783cd568b6..575e8430ce 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -140,6 +140,8 @@ void PCHStmtWriter::VisitCaseStmt(CaseStmt *S) { Writer.WriteSubStmt(S->getRHS()); Writer.WriteSubStmt(S->getSubStmt()); Writer.AddSourceLocation(S->getCaseLoc(), Record); + Writer.AddSourceLocation(S->getEllipsisLoc(), Record); + Writer.AddSourceLocation(S->getColonLoc(), Record); Code = pch::STMT_CASE; } @@ -147,6 +149,7 @@ void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) { VisitSwitchCase(S); Writer.WriteSubStmt(S->getSubStmt()); Writer.AddSourceLocation(S->getDefaultLoc(), Record); + Writer.AddSourceLocation(S->getColonLoc(), Record); Code = pch::STMT_DEFAULT; } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 2e5baee72d..b877da2a0c 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -102,13 +102,15 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval, // C99 6.8.4.2p3: The expression shall be an integer constant. // However, GCC allows any evaluatable integer expression. Expr *LHSVal = static_cast<Expr*>(lhsval.get()); - if (VerifyIntegerConstantExpression(LHSVal)) + if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() && + VerifyIntegerConstantExpression(LHSVal)) return StmtError(); // GCC extension: The expression shall be an integer constant. Expr *RHSVal = static_cast<Expr*>(rhsval.get()); - if (RHSVal && VerifyIntegerConstantExpression(RHSVal)) { + if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() && + VerifyIntegerConstantExpression(RHSVal)) { RHSVal = 0; // Recover by just forgetting about it. rhsval = 0; } @@ -121,7 +123,8 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval, // Only now release the smart pointers. lhsval.release(); rhsval.release(); - CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc); + CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc, + ColonLoc); getSwitchStack().back()->addSwitchCase(CS); return Owned(CS); } @@ -143,7 +146,7 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, return Owned(SubStmt); } - DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, SubStmt); + DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt); getSwitchStack().back()->addSwitchCase(DS); return Owned(DS); } @@ -227,17 +230,18 @@ Sema::ActOnStartOfSwitchStmt(ExprArg cond) { // converted by calling that conversion function, and the result of the // conversion is used in place of the original condition for the remainder // of this section. Integral promotions are performed. - - QualType Ty = Cond->getType(); - - // FIXME: Handle class types. - - // If the type is wrong a diagnostic will be emitted later at - // ActOnFinishSwitchStmt. - if (Ty->isIntegralType() || Ty->isEnumeralType()) { - // Integral promotions are performed. - // FIXME: Integral promotions for C++ are not complete. - UsualUnaryConversions(Cond); + if (!Cond->isTypeDependent()) { + QualType Ty = Cond->getType(); + + // FIXME: Handle class types. + + // If the type is wrong a diagnostic will be emitted later at + // ActOnFinishSwitchStmt. + if (Ty->isIntegralType() || Ty->isEnumeralType()) { + // Integral promotions are performed. + // FIXME: Integral promotions for C++ are not complete. + UsualUnaryConversions(Cond); + } } } else { // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. @@ -338,7 +342,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, Expr *CondExpr = SS->getCond(); QualType CondType = CondExpr->getType(); - if (!CondType->isIntegerType()) { // C99 6.8.4.2p1 + if (!CondExpr->isTypeDependent() && + !CondType->isIntegerType()) { // C99 6.8.4.2p1 Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) << CondType << CondExpr->getSourceRange(); return StmtError(); @@ -346,7 +351,11 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // Get the bitwidth of the switched-on value before promotions. We must // convert the integer case values to this width before comparison. - unsigned CondWidth = static_cast<unsigned>(Context.getTypeSize(CondType)); + bool HasDependentValue + = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); + unsigned CondWidth + = HasDependentValue? 0 + : static_cast<unsigned>(Context.getTypeSize(CondType)); bool CondIsSigned = CondType->isSignedIntegerType(); // Accumulate all of the case values in a vector so that we can sort them @@ -362,7 +371,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, bool CaseListIsErroneous = false; - for (SwitchCase *SC = SS->getSwitchCaseList(); SC; + for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue; SC = SC->getNextSwitchCase()) { if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) { @@ -384,6 +393,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // We already verified that the expression has a i-c-e value (C99 // 6.8.4.2p3) - get that value now. Expr *Lo = CS->getLHS(); + + if (Lo->isTypeDependent() || Lo->isValueDependent()) { + HasDependentValue = true; + break; + } + llvm::APSInt LoVal = Lo->EvaluateAsInt(Context); // Convert the value to the same width/sign as the condition. @@ -397,117 +412,127 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, CS->setLHS(Lo); // If this is a case range, remember it in CaseRanges, otherwise CaseVals. - if (CS->getRHS()) + if (CS->getRHS()) { + if (CS->getRHS()->isTypeDependent() || + CS->getRHS()->isValueDependent()) { + HasDependentValue = true; + break; + } CaseRanges.push_back(std::make_pair(LoVal, CS)); - else + } else CaseVals.push_back(std::make_pair(LoVal, CS)); } } - - // Sort all the scalar case values so we can easily detect duplicates. - std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); - - if (!CaseVals.empty()) { - for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) { - if (CaseVals[i].first == CaseVals[i+1].first) { - // If we have a duplicate, report it. - Diag(CaseVals[i+1].second->getLHS()->getLocStart(), - diag::err_duplicate_case) << CaseVals[i].first.toString(10); - Diag(CaseVals[i].second->getLHS()->getLocStart(), - diag::note_duplicate_case_prev); - // FIXME: We really want to remove the bogus case stmt from the substmt, - // but we have no way to do this right now. - CaseListIsErroneous = true; - } - } - } - - // Detect duplicate case ranges, which usually don't exist at all in the first - // place. - if (!CaseRanges.empty()) { - // Sort all the case ranges by their low value so we can easily detect - // overlaps between ranges. - std::stable_sort(CaseRanges.begin(), CaseRanges.end()); - - // Scan the ranges, computing the high values and removing empty ranges. - std::vector<llvm::APSInt> HiVals; - for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { - CaseStmt *CR = CaseRanges[i].second; - Expr *Hi = CR->getRHS(); - llvm::APSInt HiVal = Hi->EvaluateAsInt(Context); - // Convert the value to the same width/sign as the condition. - ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, - CR->getRHS()->getLocStart(), - diag::warn_case_value_overflow); - - // If the LHS is not the same type as the condition, insert an implicit - // cast. - ImpCastExprToType(Hi, CondType); - CR->setRHS(Hi); - - // If the low value is bigger than the high value, the case is empty. - if (CaseRanges[i].first > HiVal) { - Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range) - << SourceRange(CR->getLHS()->getLocStart(), - CR->getRHS()->getLocEnd()); - CaseRanges.erase(CaseRanges.begin()+i); - --i, --e; - continue; + if (!HasDependentValue) { + // Sort all the scalar case values so we can easily detect duplicates. + std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); + + if (!CaseVals.empty()) { + for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) { + if (CaseVals[i].first == CaseVals[i+1].first) { + // If we have a duplicate, report it. + Diag(CaseVals[i+1].second->getLHS()->getLocStart(), + diag::err_duplicate_case) << CaseVals[i].first.toString(10); + Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::note_duplicate_case_prev); + // FIXME: We really want to remove the bogus case stmt from + // the substmt, but we have no way to do this right now. + CaseListIsErroneous = true; + } } - HiVals.push_back(HiVal); } - - // Rescan the ranges, looking for overlap with singleton values and other - // ranges. Since the range list is sorted, we only need to compare case - // ranges with their neighbors. - for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { - llvm::APSInt &CRLo = CaseRanges[i].first; - llvm::APSInt &CRHi = HiVals[i]; - CaseStmt *CR = CaseRanges[i].second; - - // Check to see whether the case range overlaps with any singleton cases. - CaseStmt *OverlapStmt = 0; - llvm::APSInt OverlapVal(32); + + // Detect duplicate case ranges, which usually don't exist at all in + // the first place. + if (!CaseRanges.empty()) { + // Sort all the case ranges by their low value so we can easily detect + // overlaps between ranges. + std::stable_sort(CaseRanges.begin(), CaseRanges.end()); - // Find the smallest value >= the lower bound. If I is in the case range, - // then we have overlap. - CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(), - CaseVals.end(), CRLo, - CaseCompareFunctor()); - if (I != CaseVals.end() && I->first < CRHi) { - OverlapVal = I->first; // Found overlap with scalar. - OverlapStmt = I->second; - } - - // Find the smallest value bigger than the upper bound. - I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor()); - if (I != CaseVals.begin() && (I-1)->first >= CRLo) { - OverlapVal = (I-1)->first; // Found overlap with scalar. - OverlapStmt = (I-1)->second; - } - - // Check to see if this case stmt overlaps with the subsequent case range. - if (i && CRLo <= HiVals[i-1]) { - OverlapVal = HiVals[i-1]; // Found overlap with range. - OverlapStmt = CaseRanges[i-1].second; + // Scan the ranges, computing the high values and removing empty ranges. + std::vector<llvm::APSInt> HiVals; + for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { + CaseStmt *CR = CaseRanges[i].second; + Expr *Hi = CR->getRHS(); + llvm::APSInt HiVal = Hi->EvaluateAsInt(Context); + + // Convert the value to the same width/sign as the condition. + ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, + CR->getRHS()->getLocStart(), + diag::warn_case_value_overflow); + + // If the LHS is not the same type as the condition, insert an implicit + // cast. + ImpCastExprToType(Hi, CondType); + CR->setRHS(Hi); + + // If the low value is bigger than the high value, the case is empty. + if (CaseRanges[i].first > HiVal) { + Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range) + << SourceRange(CR->getLHS()->getLocStart(), + CR->getRHS()->getLocEnd()); + CaseRanges.erase(CaseRanges.begin()+i); + --i, --e; + continue; + } + HiVals.push_back(HiVal); } - if (OverlapStmt) { - // If we have a duplicate, report it. - Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case) - << OverlapVal.toString(10); - Diag(OverlapStmt->getLHS()->getLocStart(), - diag::note_duplicate_case_prev); - // FIXME: We really want to remove the bogus case stmt from the substmt, - // but we have no way to do this right now. - CaseListIsErroneous = true; + // Rescan the ranges, looking for overlap with singleton values and other + // ranges. Since the range list is sorted, we only need to compare case + // ranges with their neighbors. + for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { + llvm::APSInt &CRLo = CaseRanges[i].first; + llvm::APSInt &CRHi = HiVals[i]; + CaseStmt *CR = CaseRanges[i].second; + + // Check to see whether the case range overlaps with any + // singleton cases. + CaseStmt *OverlapStmt = 0; + llvm::APSInt OverlapVal(32); + + // Find the smallest value >= the lower bound. If I is in the + // case range, then we have overlap. + CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(), + CaseVals.end(), CRLo, + CaseCompareFunctor()); + if (I != CaseVals.end() && I->first < CRHi) { + OverlapVal = I->first; // Found overlap with scalar. + OverlapStmt = I->second; + } + + // Find the smallest value bigger than the upper bound. + I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor()); + if (I != CaseVals.begin() && (I-1)->first >= CRLo) { + OverlapVal = (I-1)->first; // Found overlap with scalar. + OverlapStmt = (I-1)->second; + } + + // Check to see if this case stmt overlaps with the subsequent + // case range. + if (i && CRLo <= HiVals[i-1]) { + OverlapVal = HiVals[i-1]; // Found overlap with range. + OverlapStmt = CaseRanges[i-1].second; + } + + if (OverlapStmt) { + // If we have a duplicate, report it. + Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case) + << OverlapVal.toString(10); + Diag(OverlapStmt->getLHS()->getLocStart(), + diag::note_duplicate_case_prev); + // FIXME: We really want to remove the bogus case stmt from + // the substmt, but we have no way to do this right now. + CaseListIsErroneous = true; + } } } } - - // FIXME: If the case list was broken is some way, we don't have a good system - // to patch it up. Instead, just return the whole substmt as broken. + + // FIXME: If the case list was broken is some way, we don't have a + // good system to patch it up. Instead, just return the whole + // substmt as broken. if (CaseListIsErroneous) return StmtError(); diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp index d59f85953f..9252677025 100644 --- a/lib/Sema/SemaTemplateInstantiateStmt.cpp +++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp @@ -39,7 +39,10 @@ namespace { OwningStmtResult VisitDeclStmt(DeclStmt *S); OwningStmtResult VisitNullStmt(NullStmt *S); OwningStmtResult VisitCompoundStmt(CompoundStmt *S); + OwningStmtResult VisitCaseStmt(CaseStmt *S); + OwningStmtResult VisitDefaultStmt(DefaultStmt *S); OwningStmtResult VisitIfStmt(IfStmt *S); + OwningStmtResult VisitSwitchStmt(SwitchStmt *S); OwningStmtResult VisitWhileStmt(WhileStmt *S); OwningStmtResult VisitDoStmt(DoStmt *S); OwningStmtResult VisitForStmt(ForStmt *S); @@ -150,6 +153,50 @@ TemplateStmtInstantiator::VisitCompoundStmt(CompoundStmt *S) { S->getRBracLoc())); } +Sema::OwningStmtResult TemplateStmtInstantiator::VisitCaseStmt(CaseStmt *S) { + // Instantiate left-hand case value. + OwningExprResult LHS = SemaRef.InstantiateExpr(S->getLHS(), TemplateArgs); + if (LHS.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate right-hand case value (for the GNU case-range extension). + OwningExprResult RHS = SemaRef.InstantiateExpr(S->getRHS(), TemplateArgs); + if (RHS.isInvalid()) + return SemaRef.StmtError(); + + // Build the case statement. + OwningStmtResult Case = SemaRef.ActOnCaseStmt(S->getCaseLoc(), + move(LHS), + S->getEllipsisLoc(), + move(RHS), + S->getColonLoc()); + if (Case.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the statement following the case + OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(), + TemplateArgs); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + SemaRef.ActOnCaseStmtBody(Case.get(), move(SubStmt)); + return move(Case); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitDefaultStmt(DefaultStmt *S) { + // Instantiate the statement following the default case + OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(), + TemplateArgs); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnDefaultStmt(S->getDefaultLoc(), + S->getColonLoc(), + move(SubStmt), + /*CurScope=*/0); +} + Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) { // Instantiate the condition OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); @@ -170,6 +217,28 @@ Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) { S->getElseLoc(), move(Else)); } +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitSwitchStmt(SwitchStmt *S) { + // Instantiate the condition. + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Start the switch statement itself. + OwningStmtResult Switch = SemaRef.ActOnStartOfSwitchStmt(move(Cond)); + if (Switch.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body of the switch statement. + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // Complete the switch statement. + return SemaRef.ActOnFinishSwitchStmt(S->getSwitchLoc(), move(Switch), + move(Body)); +} + Sema::OwningStmtResult TemplateStmtInstantiator::VisitWhileStmt(WhileStmt *S) { // Instantiate the condition OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp index 1dfe9e2da6..abd0d1c0fb 100644 --- a/test/SemaTemplate/instantiate-function-1.cpp +++ b/test/SemaTemplate/instantiate-function-1.cpp @@ -140,3 +140,33 @@ template<typename T> struct Member0 { this.f; // expected-error{{member reference base type 'struct Member0 *const' is not a structure or union}} } }; + +template<typename T, typename U> struct Switch0 { + U f(T value, U v0, U v1, U v2) { + switch (value) { + case 0: return v0; + + case 1: return v1; + + case 2: // fall through + + default: + return v2; + } + } +}; + +template struct Switch0<int, float>; + +template<typename T, int I1, int I2> struct Switch1 { + T f(T x, T y, T z) { + switch (x) { + case I1: return y; // expected-note{{previous}} + case I2: return z; // expected-error{{duplicate}} + default: return x; + } + } +}; + +template struct Switch1<int, 1, 2>; +template struct Switch1<int, 2, 2>; // expected-note{{instantiation}} |