From: Douglas Gregor Date: Fri, 15 May 2009 18:53:42 +0000 (+0000) Subject: Template instantiation for "if" statements. Also: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d06f6ca61062f85926eb9d409eb3d4f8afcf93c7;p=clang Template instantiation for "if" statements. Also: - Skip semantic analysis of the "if" condition if it is type-dependent. - Added the location of the "else" keyword into IfStmt, so that we can provide it for type-checking after template instantiation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71875 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 99e49722af..14afcfcd62 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -540,13 +540,16 @@ class IfStmt : public Stmt { enum { COND, THEN, ELSE, END_EXPR }; Stmt* SubExprs[END_EXPR]; SourceLocation IfLoc; + SourceLocation ElseLoc; public: - IfStmt(SourceLocation IL, Expr *cond, Stmt *then, Stmt *elsev = 0) + IfStmt(SourceLocation IL, Expr *cond, Stmt *then, + SourceLocation EL = SourceLocation(), Stmt *elsev = 0) : Stmt(IfStmtClass) { SubExprs[COND] = reinterpret_cast(cond); SubExprs[THEN] = then; SubExprs[ELSE] = elsev; IfLoc = IL; + ElseLoc = EL; } /// \brief Build an empty if/then/else statement @@ -565,6 +568,8 @@ public: SourceLocation getIfLoc() const { return IfLoc; } void setIfLoc(SourceLocation L) { IfLoc = L; } + SourceLocation getElseLoc() const { return ElseLoc; } + void setElseLoc(SourceLocation L) { ElseLoc = L; } virtual SourceRange getSourceRange() const { if (SubExprs[ELSE]) diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 1c6f3f1da7..eb8dab968b 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -172,6 +172,7 @@ unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) { S->setThen(StmtStack[StmtStack.size() - 2]); S->setElse(StmtStack[StmtStack.size() - 1]); S->setIfLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setElseLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); return 3; } diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index d37df07d07..af5d563587 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -165,6 +165,7 @@ void PCHStmtWriter::VisitIfStmt(IfStmt *S) { Writer.WriteSubStmt(S->getThen()); Writer.WriteSubStmt(S->getElse()); Writer.AddSourceLocation(S->getIfLoc(), Record); + Writer.AddSourceLocation(S->getElseLoc(), Record); Code = pch::STMT_IF; } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index e200c46e4f..a5277a9293 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -184,17 +184,20 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, ExprArg CondVal, assert(condExpr && "ActOnIfStmt(): missing expression"); - DefaultFunctionArrayConversion(condExpr); - // Take ownership again until we're past the error checking. - CondVal = condExpr; - QualType condType = condExpr->getType(); - - if (getLangOptions().CPlusPlus) { - if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4 - return StmtError(); - } else if (!condType->isScalarType()) // C99 6.8.4.1p1 - return StmtError(Diag(IfLoc, diag::err_typecheck_statement_requires_scalar) - << condType << condExpr->getSourceRange()); + if (!condExpr->isTypeDependent()) { + DefaultFunctionArrayConversion(condExpr); + // Take ownership again until we're past the error checking. + CondVal = condExpr; + QualType condType = condExpr->getType(); + + if (getLangOptions().CPlusPlus) { + if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4 + return StmtError(); + } else if (!condType->isScalarType()) // C99 6.8.4.1p1 + return StmtError(Diag(IfLoc, + diag::err_typecheck_statement_requires_scalar) + << condType << condExpr->getSourceRange()); + } Stmt *thenStmt = ThenVal.takeAs(); @@ -209,7 +212,7 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, ExprArg CondVal, CondVal.release(); return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt, - ElseVal.takeAs())); + ElseLoc, ElseVal.takeAs())); } Action::OwningStmtResult diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp index cbe4449efc..957402ac6f 100644 --- a/lib/Sema/SemaTemplateInstantiateStmt.cpp +++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp @@ -39,6 +39,7 @@ namespace { OwningStmtResult VisitDeclStmt(DeclStmt *S); OwningStmtResult VisitNullStmt(NullStmt *S); OwningStmtResult VisitCompoundStmt(CompoundStmt *S); + OwningStmtResult VisitIfStmt(IfStmt *S); OwningStmtResult VisitExpr(Expr *E); OwningStmtResult VisitLabelStmt(LabelStmt *S); OwningStmtResult VisitGotoStmt(GotoStmt *S); @@ -135,6 +136,26 @@ TemplateStmtInstantiator::VisitCompoundStmt(CompoundStmt *S) { S->getRBracLoc())); } +Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) { + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the "then" branch. + OwningStmtResult Then = SemaRef.InstantiateStmt(S->getThen(), TemplateArgs); + if (Then.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the "else" branch. + OwningStmtResult Else = SemaRef.InstantiateStmt(S->getElse(), TemplateArgs); + if (Else.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnIfStmt(S->getIfLoc(), move(Cond), move(Then), + S->getElseLoc(), move(Else)); +} + Sema::OwningStmtResult TemplateStmtInstantiator::VisitExpr(Expr *E) { Sema::OwningExprResult Result = SemaRef.InstantiateExpr(E, TemplateArgs); if (Result.isInvalid()) diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp index 482b466e84..5ded6140a6 100644 --- a/test/SemaTemplate/instantiate-function-1.cpp +++ b/test/SemaTemplate/instantiate-function-1.cpp @@ -58,3 +58,20 @@ template struct X5 { void test_X5(X5 x5); // okay! template struct X5; // expected-note{{instantiation}} + +template struct X6 { + U f(T t, U u, V v) { + // IfStmt + if (t > 0) + return u; + else + return v; // expected-error{{incompatible type}} + } +}; + +struct ConvertibleToInt { + operator int() const; +}; + +template struct X6; +template struct X6; // expected-note{{instantiation}}