2006-11-10 13:07:45 +08:00
|
|
|
//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-11-10 13:07:45 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements semantic analysis for statements.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-08-26 06:03:47 +08:00
|
|
|
#include "clang/Sema/SemaInternal.h"
|
2007-08-23 13:46:52 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2013-01-10 07:04:56 +08:00
|
|
|
#include "clang/AST/ASTDiagnostic.h"
|
2011-11-11 11:57:31 +08:00
|
|
|
#include "clang/AST/CharUnits.h"
|
2015-04-08 08:05:29 +08:00
|
|
|
#include "clang/AST/CXXInheritance.h"
|
2008-08-11 13:35:13 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2012-05-01 02:01:30 +08:00
|
|
|
#include "clang/AST/EvaluatedExprVisitor.h"
|
2009-11-23 21:46:08 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2009-08-17 00:57:27 +08:00
|
|
|
#include "clang/AST/ExprObjC.h"
|
Add -Wunused-local-typedef, a warning that finds unused local typedefs.
The warning warns on TypedefNameDecls -- typedefs and C++11 using aliases --
that are !isReferenced(). Since the isReferenced() bit on TypedefNameDecls
wasn't used for anything before this warning it wasn't always set correctly,
so this patch also adds a few missing MarkAnyDeclReferenced() calls in
various places for TypedefNameDecls.
This is made a bit complicated due to local typedefs possibly being used only
after their local scope has closed. Consider:
template <class T>
void template_fun(T t) {
typename T::Foo s3foo; // YYY
(void)s3foo;
}
void template_fun_user() {
struct Local {
typedef int Foo; // XXX
} p;
template_fun(p);
}
Here the typedef in XXX is only used at end-of-translation unit, when YYY in
template_fun() gets instantiated. To handle this, typedefs that are unused when
their scope exits are added to a set of potentially unused typedefs, and that
set gets checked at end-of-TU. Typedefs that are still unused at that point then
get warned on. There's also serialization code for this set, so that the
warning works with precompiled headers and modules. For modules, the warning
is emitted when the module is built, for precompiled headers each time the
header gets used.
Finally, consider a function using C++14 auto return types to return a local
type defined in a header:
auto f() {
struct S { typedef int a; };
return S();
}
Here, the typedef escapes its local scope and could be used by only some
translation units including the header. To not warn on this, add a
RecursiveASTVisitor that marks all delcs on local types returned from auto
functions as referenced. (Except if it's a function with internal linkage, or
the decls are private and the local type has no friends -- in these cases, it
_is_ safe to warn.)
Several of the included testcases (most of the interesting ones) were provided
by Richard Smith.
(gcc's spelling -Wunused-local-typedefs is supported as an alias for this
warning.)
llvm-svn: 217298
2014-09-06 09:25:55 +08:00
|
|
|
#include "clang/AST/RecursiveASTVisitor.h"
|
2009-04-26 09:32:48 +08:00
|
|
|
#include "clang/AST/StmtCXX.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/AST/StmtObjC.h"
|
2010-04-07 06:24:14 +08:00
|
|
|
#include "clang/AST/TypeLoc.h"
|
2015-04-08 08:05:29 +08:00
|
|
|
#include "clang/AST/TypeOrdering.h"
|
2015-07-07 08:36:30 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
|
|
|
#include "clang/Sema/Initialization.h"
|
|
|
|
#include "clang/Sema/Lookup.h"
|
|
|
|
#include "clang/Sema/Scope.h"
|
|
|
|
#include "clang/Sema/ScopeInfo.h"
|
2011-02-22 05:40:33 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2015-04-08 08:05:29 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2009-07-30 01:15:45 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2012-05-01 02:01:30 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
2012-05-17 00:11:17 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2009-07-30 01:15:45 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2016-04-27 04:55:48 +08:00
|
|
|
|
2006-11-10 13:07:45 +08:00
|
|
|
using namespace clang;
|
2010-08-25 16:40:02 +08:00
|
|
|
using namespace sema;
|
2006-11-10 13:07:45 +08:00
|
|
|
|
2013-01-15 06:39:08 +08:00
|
|
|
StmtResult Sema::ActOnExprStmt(ExprResult FE) {
|
|
|
|
if (FE.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
FE = ActOnFinishFullExpr(FE.get(), FE.get()->getExprLoc(),
|
|
|
|
/*DiscardedValue*/ true);
|
|
|
|
if (FE.isInvalid())
|
2010-12-15 09:34:56 +08:00
|
|
|
return StmtError();
|
|
|
|
|
2008-07-26 07:18:17 +08:00
|
|
|
// C99 6.8.3p2: The expression in an expression statement is evaluated as a
|
|
|
|
// void expression for its side effects. Conversion to void allows any
|
|
|
|
// operand, even incomplete types.
|
2008-12-21 20:04:03 +08:00
|
|
|
|
2008-07-26 07:18:17 +08:00
|
|
|
// Same thing in for stmt first clause (when expr) and third clause.
|
2014-05-29 22:05:12 +08:00
|
|
|
return StmtResult(FE.getAs<Stmt>());
|
2007-06-27 13:38:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-22 10:10:40 +08:00
|
|
|
StmtResult Sema::ActOnExprStmtError() {
|
|
|
|
DiscardCleanupsInEvaluationContext();
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2011-04-27 13:04:02 +08:00
|
|
|
StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc,
|
2011-09-02 05:53:45 +08:00
|
|
|
bool HasLeadingEmptyMacro) {
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro);
|
2007-05-28 09:45:28 +08:00
|
|
|
}
|
|
|
|
|
2011-02-18 09:27:55 +08:00
|
|
|
StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc,
|
|
|
|
SourceLocation EndLoc) {
|
2013-08-27 21:15:56 +08:00
|
|
|
DeclGroupRef DG = dg.get();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
// If we have an invalid decl, just return an error.
|
2009-04-13 04:13:14 +08:00
|
|
|
if (DG.isNull()) return StmtError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) DeclStmt(DG, StartLoc, EndLoc);
|
2007-05-30 06:59:26 +08:00
|
|
|
}
|
2006-11-10 13:07:45 +08:00
|
|
|
|
2009-11-20 06:12:37 +08:00
|
|
|
void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
|
2013-08-27 21:15:56 +08:00
|
|
|
DeclGroupRef DG = dg.get();
|
2013-05-04 05:07:45 +08:00
|
|
|
|
2013-04-09 04:52:24 +08:00
|
|
|
// If we don't have a declaration, or we have an invalid declaration,
|
|
|
|
// just return.
|
|
|
|
if (DG.isNull() || !DG.isSingleDecl())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Decl *decl = DG.getSingleDecl();
|
|
|
|
if (!decl || decl->isInvalidDecl())
|
|
|
|
return;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2013-04-09 04:52:24 +08:00
|
|
|
// Only variable declarations are permitted.
|
|
|
|
VarDecl *var = dyn_cast<VarDecl>(decl);
|
|
|
|
if (!var) {
|
|
|
|
Diag(decl->getLocation(), diag::err_non_variable_decl_in_for);
|
|
|
|
decl->setInvalidDecl();
|
|
|
|
return;
|
|
|
|
}
|
2011-06-16 07:02:42 +08:00
|
|
|
|
2011-06-17 14:42:21 +08:00
|
|
|
// foreach variables are never actually initialized in the way that
|
|
|
|
// the parser came up with.
|
2014-05-26 14:22:03 +08:00
|
|
|
var->setInit(nullptr);
|
2011-06-17 14:42:21 +08:00
|
|
|
|
|
|
|
// In ARC, we don't need to retain the iteration variable of a fast
|
|
|
|
// enumeration loop. Rather than actually trying to catch that
|
|
|
|
// during declaration processing, we remove the consequences here.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().ObjCAutoRefCount) {
|
2011-06-17 14:42:21 +08:00
|
|
|
QualType type = var->getType();
|
|
|
|
|
|
|
|
// Only do this if we inferred the lifetime. Inferred lifetime
|
|
|
|
// will show up as a local qualifier because explicit lifetime
|
|
|
|
// should have shown up as an AttributedType instead.
|
|
|
|
if (type.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong) {
|
|
|
|
// Add 'const' and mark the variable as pseudo-strong.
|
|
|
|
var->setType(type.withConst());
|
|
|
|
var->setARCPseudoStrong(true);
|
2011-06-16 07:02:42 +08:00
|
|
|
}
|
|
|
|
}
|
2009-11-20 06:12:37 +08:00
|
|
|
}
|
|
|
|
|
2014-03-11 11:11:08 +08:00
|
|
|
/// \brief Diagnose unused comparisons, both builtin and overloaded operators.
|
|
|
|
/// For '==' and '!=', suggest fixits for '=' or '|='.
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
///
|
|
|
|
/// Adding a cast to void (or other expression wrappers) will prevent the
|
|
|
|
/// warning from firing.
|
2011-08-17 17:34:37 +08:00
|
|
|
static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
SourceLocation Loc;
|
2014-03-11 11:11:08 +08:00
|
|
|
bool IsNotEqual, CanAssign, IsRelational;
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
|
|
|
|
if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
|
2014-03-11 11:11:08 +08:00
|
|
|
if (!Op->isComparisonOp())
|
2011-08-17 17:34:37 +08:00
|
|
|
return false;
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
|
2014-03-11 11:11:08 +08:00
|
|
|
IsRelational = Op->isRelationalOp();
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
Loc = Op->getOperatorLoc();
|
2011-08-17 16:38:11 +08:00
|
|
|
IsNotEqual = Op->getOpcode() == BO_NE;
|
|
|
|
CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue();
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
} else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) {
|
2014-03-11 11:11:08 +08:00
|
|
|
switch (Op->getOperator()) {
|
|
|
|
default:
|
2011-08-17 17:34:37 +08:00
|
|
|
return false;
|
2014-03-11 11:11:08 +08:00
|
|
|
case OO_EqualEqual:
|
|
|
|
case OO_ExclaimEqual:
|
|
|
|
IsRelational = false;
|
|
|
|
break;
|
|
|
|
case OO_Less:
|
|
|
|
case OO_Greater:
|
|
|
|
case OO_GreaterEqual:
|
|
|
|
case OO_LessEqual:
|
|
|
|
IsRelational = true;
|
|
|
|
break;
|
|
|
|
}
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
|
|
|
|
Loc = Op->getOperatorLoc();
|
2011-08-17 16:38:11 +08:00
|
|
|
IsNotEqual = Op->getOperator() == OO_ExclaimEqual;
|
|
|
|
CanAssign = Op->getArg(0)->IgnoreParenImpCasts()->isLValue();
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
} else {
|
|
|
|
// Not a typo-prone comparison.
|
2011-08-17 17:34:37 +08:00
|
|
|
return false;
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Suppress warnings when the operator, suspicious as it may be, comes from
|
|
|
|
// a macro expansion.
|
2013-01-12 08:54:16 +08:00
|
|
|
if (S.SourceMgr.isMacroBodyExpansion(Loc))
|
2011-08-17 17:34:37 +08:00
|
|
|
return false;
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
|
2011-08-17 17:34:37 +08:00
|
|
|
S.Diag(Loc, diag::warn_unused_comparison)
|
2014-03-11 11:11:08 +08:00
|
|
|
<< (unsigned)IsRelational << (unsigned)IsNotEqual << E->getSourceRange();
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
|
2011-08-17 16:38:11 +08:00
|
|
|
// If the LHS is a plausible entity to assign to, provide a fixit hint to
|
|
|
|
// correct common typos.
|
2014-03-11 11:11:08 +08:00
|
|
|
if (!IsRelational && CanAssign) {
|
2011-08-17 16:38:11 +08:00
|
|
|
if (IsNotEqual)
|
|
|
|
S.Diag(Loc, diag::note_inequality_comparison_to_or_assign)
|
|
|
|
<< FixItHint::CreateReplacement(Loc, "|=");
|
|
|
|
else
|
|
|
|
S.Diag(Loc, diag::note_equality_comparison_to_assign)
|
|
|
|
<< FixItHint::CreateReplacement(Loc, "=");
|
|
|
|
}
|
2011-08-17 17:34:37 +08:00
|
|
|
|
|
|
|
return true;
|
Introduce a new warning, -Wtop-level-comparison. This warning is
a complement to the warnings we provide in condition expressions. Much
like we warn on conditions such as:
int x, y;
...
if (x = y) ... // Almost always a typo of '=='
This warning applies the complementary logic to "top-level" statements,
or statements whose value is not consumed or used in some way:
int x, y;
...
x == y; // Almost always a type for '='
We also mirror the '!=' vs. '|=' logic.
The warning is designed to fire even for overloaded operators for two reasons:
1) Especially in the presence of widespread templates that assume
operator== and operator!= perform the expected comparison operations,
it seems unreasonable to suppress warnings on the offchance that
a user has written a class that abuses these operators, embedding
side-effects or other magic within them.
2) There is a trivial source modification to silence the warning for
truly exceptional cases:
(void)(x == y); // No warning
A (greatly reduced) form of this warning has already caught a number of
bugs in our codebase, so there is precedent for it actually firing. That
said, its currently off by default, but enabled under -Wall.
There are several fixmes left here that I'm working on in follow-up
patches, including de-duplicating warnings from -Wunused, sharing code
with -Wunused's implementation (and creating a nice place to hook
diagnostics on "top-level" statements), and handling cases where a proxy
object with a bool conversion is returned, hiding the operation in the
cleanup AST nodes.
Suggestions for any of this code more than welcome. Also, I'd really
love suggestions for better naming than "top-level".
llvm-svn: 137819
2011-08-17 16:38:04 +08:00
|
|
|
}
|
|
|
|
|
2009-07-31 06:17:18 +08:00
|
|
|
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
|
2010-09-20 05:21:10 +08:00
|
|
|
if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
|
|
|
|
return DiagnoseUnusedExprResult(Label->getSubStmt());
|
|
|
|
|
2009-07-31 06:39:03 +08:00
|
|
|
const Expr *E = dyn_cast_or_null<Expr>(S);
|
2009-07-31 06:17:18 +08:00
|
|
|
if (!E)
|
|
|
|
return;
|
2014-10-17 04:13:28 +08:00
|
|
|
|
|
|
|
// If we are in an unevaluated expression context, then there can be no unused
|
|
|
|
// results because the results aren't expected to be used in the first place.
|
|
|
|
if (isUnevaluatedContext())
|
|
|
|
return;
|
|
|
|
|
Tweak how -Wunused-value interacts with macros
1. Make the warning more strict in C mode. r172696 added code to suppress
warnings from macro expansions in system headers, which checks
`SourceMgr.isMacroBodyExpansion(E->IgnoreParens()->getExprLoc())`. Consider
this snippet:
#define FOO(x) (x)
void f(int a) {
FOO(a);
}
In C, the line `FOO(a)` is an `ImplicitCastExpr(ParenExpr(DeclRefExpr))`,
while it's just a `ParenExpr(DeclRefExpr)` in C++. So in C++,
`E->IgnoreParens()` returns the `DeclRefExpr` and the check tests the
SourceLoc of `a`. In C, the `ImplicitCastExpr` has the effect of checking the
SourceLoc of `FOO`, which is a macro body expansion, which causes the
diagnostic to be skipped. It looks unintentional that clang does different
things for C and C++ here, so use `IgnoreParenImpCasts` instead of
`IgnoreParens` here. This has the effect of the warning firing more often
than previously in C code – it now fires as often as it fires in C++ code.
2. Suppress the warning if it would warn on `UNREFERENCED_PARAMETER`.
`UNREFERENCED_PARAMETER` is a commonly used macro on Windows and it happens
to uselessly trigger -Wunused-value. As discussed in the thread
"rfc: winnt.h's UNREFERENCED_PARAMETER() vs clang's -Wunused-value" on
cfe-dev, fix this by special-casing this specific macro. (This costs a string
comparison and some fast-path lexing per warning, but the warning is emitted
rarely. It fires once in Windows.h itself, so this code runs at least once
per TU including Windows.h, but it doesn't run hundreds of times.)
http://reviews.llvm.org/D13969
llvm-svn: 251441
2015-10-28 03:47:40 +08:00
|
|
|
SourceLocation ExprLoc = E->IgnoreParenImpCasts()->getExprLoc();
|
2013-02-27 03:34:08 +08:00
|
|
|
// In most cases, we don't want to warn if the expression is written in a
|
|
|
|
// macro body, or if the macro comes from a system header. If the offending
|
|
|
|
// expression is a call to a function with the warn_unused_result attribute,
|
|
|
|
// we warn no matter the location. Because of the order in which the various
|
|
|
|
// checks need to happen, we factor out the macro-related test here.
|
|
|
|
bool ShouldSuppress =
|
|
|
|
SourceMgr.isMacroBodyExpansion(ExprLoc) ||
|
|
|
|
SourceMgr.isInSystemMacro(ExprLoc);
|
2009-07-31 06:17:18 +08:00
|
|
|
|
2012-05-24 08:47:05 +08:00
|
|
|
const Expr *WarnExpr;
|
2009-07-31 06:17:18 +08:00
|
|
|
SourceLocation Loc;
|
|
|
|
SourceRange R1, R2;
|
2013-01-17 10:06:08 +08:00
|
|
|
if (!E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context))
|
2009-07-31 06:17:18 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-09-01 06:39:21 +08:00
|
|
|
// If this is a GNU statement expression expanded from a macro, it is probably
|
|
|
|
// unused because it is a function-like macro that can be used as either an
|
|
|
|
// expression or statement. Don't warn, because it is almost certainly a
|
|
|
|
// false positive.
|
|
|
|
if (isa<StmtExpr>(E) && Loc.isMacroID())
|
|
|
|
return;
|
|
|
|
|
Tweak how -Wunused-value interacts with macros
1. Make the warning more strict in C mode. r172696 added code to suppress
warnings from macro expansions in system headers, which checks
`SourceMgr.isMacroBodyExpansion(E->IgnoreParens()->getExprLoc())`. Consider
this snippet:
#define FOO(x) (x)
void f(int a) {
FOO(a);
}
In C, the line `FOO(a)` is an `ImplicitCastExpr(ParenExpr(DeclRefExpr))`,
while it's just a `ParenExpr(DeclRefExpr)` in C++. So in C++,
`E->IgnoreParens()` returns the `DeclRefExpr` and the check tests the
SourceLoc of `a`. In C, the `ImplicitCastExpr` has the effect of checking the
SourceLoc of `FOO`, which is a macro body expansion, which causes the
diagnostic to be skipped. It looks unintentional that clang does different
things for C and C++ here, so use `IgnoreParenImpCasts` instead of
`IgnoreParens` here. This has the effect of the warning firing more often
than previously in C code – it now fires as often as it fires in C++ code.
2. Suppress the warning if it would warn on `UNREFERENCED_PARAMETER`.
`UNREFERENCED_PARAMETER` is a commonly used macro on Windows and it happens
to uselessly trigger -Wunused-value. As discussed in the thread
"rfc: winnt.h's UNREFERENCED_PARAMETER() vs clang's -Wunused-value" on
cfe-dev, fix this by special-casing this specific macro. (This costs a string
comparison and some fast-path lexing per warning, but the warning is emitted
rarely. It fires once in Windows.h itself, so this code runs at least once
per TU including Windows.h, but it doesn't run hundreds of times.)
http://reviews.llvm.org/D13969
llvm-svn: 251441
2015-10-28 03:47:40 +08:00
|
|
|
// Check if this is the UNREFERENCED_PARAMETER from the Microsoft headers.
|
|
|
|
// That macro is frequently used to suppress "unused parameter" warnings,
|
|
|
|
// but its implementation makes clang's -Wunused-value fire. Prevent this.
|
|
|
|
if (isa<ParenExpr>(E->IgnoreImpCasts()) && Loc.isMacroID()) {
|
|
|
|
SourceLocation SpellLoc = Loc;
|
|
|
|
if (findMacroSpelling(SpellLoc, "UNREFERENCED_PARAMETER"))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-08-17 00:57:27 +08:00
|
|
|
// Okay, we have an unused result. Depending on what the base expression is,
|
|
|
|
// we might want to make a more specific diagnostic. Check for one of these
|
|
|
|
// cases now.
|
|
|
|
unsigned DiagID = diag::warn_unused_expr;
|
2010-12-06 16:20:24 +08:00
|
|
|
if (const ExprWithCleanups *Temps = dyn_cast<ExprWithCleanups>(E))
|
2010-02-12 06:55:30 +08:00
|
|
|
E = Temps->getSubExpr();
|
2011-02-21 08:56:56 +08:00
|
|
|
if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E))
|
|
|
|
E = TempExpr->getSubExpr();
|
2010-12-02 09:19:52 +08:00
|
|
|
|
2011-08-17 17:34:37 +08:00
|
|
|
if (DiagnoseUnusedComparison(*this, E))
|
|
|
|
return;
|
|
|
|
|
2012-05-24 08:47:05 +08:00
|
|
|
E = WarnExpr;
|
2009-10-13 12:53:48 +08:00
|
|
|
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
|
2010-03-12 15:11:26 +08:00
|
|
|
if (E->getType()->isVoidType())
|
|
|
|
return;
|
|
|
|
|
2009-10-13 12:53:48 +08:00
|
|
|
// If the callee has attribute pure, const, or warn_unused_result, warn with
|
2013-02-27 03:34:08 +08:00
|
|
|
// a more specific message to make it clear what is happening. If the call
|
|
|
|
// is written in a macro body, only warn if it has the warn_unused_result
|
|
|
|
// attribute.
|
2009-12-21 07:11:08 +08:00
|
|
|
if (const Decl *FD = CE->getCalleeDecl()) {
|
2016-03-08 06:44:55 +08:00
|
|
|
if (const Attr *A = isa<FunctionDecl>(FD)
|
|
|
|
? cast<FunctionDecl>(FD)->getUnusedResultAttr()
|
|
|
|
: FD->getAttr<WarnUnusedResultAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
|
2009-10-13 12:53:48 +08:00
|
|
|
return;
|
|
|
|
}
|
2013-02-27 03:34:08 +08:00
|
|
|
if (ShouldSuppress)
|
|
|
|
return;
|
2013-12-19 10:39:40 +08:00
|
|
|
if (FD->hasAttr<PureAttr>()) {
|
2009-10-13 12:53:48 +08:00
|
|
|
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
|
|
|
|
return;
|
|
|
|
}
|
2013-12-19 10:39:40 +08:00
|
|
|
if (FD->hasAttr<ConstAttr>()) {
|
2009-10-13 12:53:48 +08:00
|
|
|
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const";
|
|
|
|
return;
|
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
}
|
2013-02-27 03:34:08 +08:00
|
|
|
} else if (ShouldSuppress)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) {
|
2011-06-16 07:02:42 +08:00
|
|
|
Diag(Loc, diag::err_arc_unused_init_message) << R1;
|
|
|
|
return;
|
|
|
|
}
|
2010-03-31 02:22:15 +08:00
|
|
|
const ObjCMethodDecl *MD = ME->getMethodDecl();
|
2014-07-19 06:59:10 +08:00
|
|
|
if (MD) {
|
2016-03-08 06:44:55 +08:00
|
|
|
if (const auto *A = MD->getAttr<WarnUnusedResultAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
|
2014-07-19 06:59:10 +08:00
|
|
|
return;
|
|
|
|
}
|
2010-03-31 02:22:15 +08:00
|
|
|
}
|
2012-03-07 04:05:56 +08:00
|
|
|
} else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
|
|
|
|
const Expr *Source = POE->getSyntacticForm();
|
|
|
|
if (isa<ObjCSubscriptRefExpr>(Source))
|
|
|
|
DiagID = diag::warn_unused_container_subscript_expr;
|
|
|
|
else
|
|
|
|
DiagID = diag::warn_unused_property_expr;
|
2010-04-17 06:09:46 +08:00
|
|
|
} else if (const CXXFunctionalCastExpr *FC
|
|
|
|
= dyn_cast<CXXFunctionalCastExpr>(E)) {
|
2017-03-28 00:29:41 +08:00
|
|
|
const Expr *E = FC->getSubExpr();
|
|
|
|
if (const CXXBindTemporaryExpr *TE = dyn_cast<CXXBindTemporaryExpr>(E))
|
|
|
|
E = TE->getSubExpr();
|
|
|
|
if (isa<CXXTemporaryObjectExpr>(E))
|
2010-04-17 06:09:46 +08:00
|
|
|
return;
|
2017-03-28 00:29:41 +08:00
|
|
|
if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E))
|
|
|
|
if (const CXXRecordDecl *RD = CE->getType()->getAsCXXRecordDecl())
|
|
|
|
if (!RD->getAttr<WarnUnusedAttr>())
|
|
|
|
return;
|
2010-03-31 02:22:15 +08:00
|
|
|
}
|
2010-04-07 06:24:14 +08:00
|
|
|
// Diagnose "(void*) blah" as a typo for "(void) blah".
|
|
|
|
else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) {
|
|
|
|
TypeSourceInfo *TI = CE->getTypeInfoAsWritten();
|
|
|
|
QualType T = TI->getType();
|
|
|
|
|
|
|
|
// We really do want to use the non-canonical type here.
|
|
|
|
if (T == Context.VoidPtrTy) {
|
2013-02-19 06:06:02 +08:00
|
|
|
PointerTypeLoc TL = TI->getTypeLoc().castAs<PointerTypeLoc>();
|
2010-04-07 06:24:14 +08:00
|
|
|
|
|
|
|
Diag(Loc, diag::warn_unused_voidptr)
|
|
|
|
<< FixItHint::CreateRemoval(TL.getStarLoc());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-24 08:47:05 +08:00
|
|
|
if (E->isGLValue() && E->getType().isVolatileQualified()) {
|
|
|
|
Diag(Loc, diag::warn_unused_volatile) << R1 << R2;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-26 14:22:03 +08:00
|
|
|
DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2);
|
2009-07-31 06:17:18 +08:00
|
|
|
}
|
|
|
|
|
2012-02-15 06:14:32 +08:00
|
|
|
void Sema::ActOnStartOfCompoundStmt() {
|
|
|
|
PushCompoundScope();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::ActOnFinishOfCompoundStmt() {
|
|
|
|
PopCompoundScope();
|
|
|
|
}
|
|
|
|
|
|
|
|
sema::CompoundScopeInfo &Sema::getCurCompoundScope() const {
|
|
|
|
return getCurFunction()->CompoundScopes.back();
|
|
|
|
}
|
|
|
|
|
2013-08-20 04:51:20 +08:00
|
|
|
StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
|
|
|
|
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
|
|
|
|
const unsigned NumElts = Elts.size();
|
|
|
|
|
2007-08-27 12:29:41 +08:00
|
|
|
// If we're in C89 mode, check that we don't have any decls after stmts. If
|
|
|
|
// so, emit an extension diagnostic.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
|
2007-08-27 12:29:41 +08:00
|
|
|
// Note that __extension__ can be around a decl.
|
|
|
|
unsigned i = 0;
|
|
|
|
// Skip over all declarations.
|
|
|
|
for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i)
|
|
|
|
/*empty*/;
|
|
|
|
|
|
|
|
// We found the end of the list or a statement. Scan for another declstmt.
|
|
|
|
for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
|
|
|
|
/*empty*/;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-27 12:29:41 +08:00
|
|
|
if (i != NumElts) {
|
2009-01-20 09:17:11 +08:00
|
|
|
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
|
2007-08-27 12:29:41 +08:00
|
|
|
Diag(D->getLocation(), diag::ext_mixed_decls_code);
|
|
|
|
}
|
|
|
|
}
|
2007-09-01 05:49:55 +08:00
|
|
|
// Warn about unused expressions in statements.
|
|
|
|
for (unsigned i = 0; i != NumElts; ++i) {
|
2009-07-31 06:17:18 +08:00
|
|
|
// Ignore statements that are last in a statement expression.
|
|
|
|
if (isStmtExpr && i == NumElts - 1)
|
2007-09-01 05:49:55 +08:00
|
|
|
continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-31 06:17:18 +08:00
|
|
|
DiagnoseUnusedExprResult(Elts[i]);
|
2007-09-01 05:49:55 +08:00
|
|
|
}
|
2008-12-21 20:04:03 +08:00
|
|
|
|
2012-02-15 06:14:32 +08:00
|
|
|
// Check for suspicious empty body (null statement) in `for' and `while'
|
|
|
|
// statements. Don't do anything for template instantiations, this just adds
|
|
|
|
// noise.
|
|
|
|
if (NumElts != 0 && !CurrentInstantiationScope &&
|
|
|
|
getCurCompoundScope().HasEmptyLoopBodies) {
|
|
|
|
for (unsigned i = 0; i != NumElts - 1; ++i)
|
|
|
|
DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]);
|
|
|
|
}
|
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) CompoundStmt(Context, Elts, L, R);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2010-08-24 07:25:46 +08:00
|
|
|
Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
|
|
|
|
SourceLocation DotDotDotLoc, Expr *RHSVal,
|
2009-03-04 12:23:07 +08:00
|
|
|
SourceLocation ColonLoc) {
|
2014-05-26 14:22:03 +08:00
|
|
|
assert(LHSVal && "missing expression in case statement");
|
2008-12-29 00:13:43 +08:00
|
|
|
|
2012-01-19 07:55:52 +08:00
|
|
|
if (getCurFunction()->SwitchStack.empty()) {
|
|
|
|
Diag(CaseLoc, diag::err_case_not_in_switch);
|
2009-03-04 12:23:07 +08:00
|
|
|
return StmtError();
|
2012-01-19 07:55:52 +08:00
|
|
|
}
|
2007-05-09 05:09:37 +08:00
|
|
|
|
2014-11-21 06:06:40 +08:00
|
|
|
ExprResult LHS =
|
|
|
|
CorrectDelayedTyposInExpr(LHSVal, [this](class Expr *E) {
|
|
|
|
if (!getLangOpts().CPlusPlus11)
|
|
|
|
return VerifyIntegerConstantExpression(E);
|
|
|
|
if (Expr *CondExpr =
|
|
|
|
getCurFunction()->SwitchStack.back()->getCond()) {
|
|
|
|
QualType CondType = CondExpr->getType();
|
|
|
|
llvm::APSInt TempVal;
|
|
|
|
return CheckConvertedConstantExpression(E, CondType, TempVal,
|
|
|
|
CCEK_CaseValue);
|
|
|
|
}
|
|
|
|
return ExprError();
|
|
|
|
});
|
|
|
|
if (LHS.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
LHSVal = LHS.get();
|
|
|
|
|
2013-01-02 19:42:31 +08:00
|
|
|
if (!getLangOpts().CPlusPlus11) {
|
2012-01-19 07:55:52 +08:00
|
|
|
// C99 6.8.4.2p3: The expression shall be an integer constant.
|
|
|
|
// However, GCC allows any evaluatable integer expression.
|
2012-02-04 17:53:13 +08:00
|
|
|
if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent()) {
|
2014-05-29 18:55:11 +08:00
|
|
|
LHSVal = VerifyIntegerConstantExpression(LHSVal).get();
|
2012-02-04 17:53:13 +08:00
|
|
|
if (!LHSVal)
|
|
|
|
return StmtError();
|
|
|
|
}
|
2008-12-29 00:13:43 +08:00
|
|
|
|
2012-01-19 07:55:52 +08:00
|
|
|
// GCC extension: The expression shall be an integer constant.
|
2008-12-29 00:13:43 +08:00
|
|
|
|
2012-02-04 17:53:13 +08:00
|
|
|
if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent()) {
|
2014-05-29 18:55:11 +08:00
|
|
|
RHSVal = VerifyIntegerConstantExpression(RHSVal).get();
|
2012-02-04 17:53:13 +08:00
|
|
|
// Recover from an error by just forgetting about it.
|
2012-01-19 07:55:52 +08:00
|
|
|
}
|
2007-07-24 01:05:23 +08:00
|
|
|
}
|
2013-04-29 21:07:42 +08:00
|
|
|
|
2014-11-21 06:06:40 +08:00
|
|
|
LHS = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false,
|
2014-11-20 09:24:12 +08:00
|
|
|
getLangOpts().CPlusPlus11);
|
|
|
|
if (LHS.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
auto RHS = RHSVal ? ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false,
|
|
|
|
getLangOpts().CPlusPlus11)
|
|
|
|
: ExprResult();
|
|
|
|
if (RHS.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
CaseStmt *CS = new (Context)
|
|
|
|
CaseStmt(LHS.get(), RHS.get(), CaseLoc, DotDotDotLoc, ColonLoc);
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->SwitchStack.back()->addSwitchCase(CS);
|
2014-05-29 22:05:12 +08:00
|
|
|
return CS;
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
/// ActOnCaseStmtBody - This installs a statement as the body of a case.
|
2010-08-24 07:25:46 +08:00
|
|
|
void Sema::ActOnCaseStmtBody(Stmt *caseStmt, Stmt *SubStmt) {
|
2011-08-18 10:04:29 +08:00
|
|
|
DiagnoseUnusedExprResult(SubStmt);
|
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
CaseStmt *CS = static_cast<CaseStmt*>(caseStmt);
|
|
|
|
CS->setSubStmt(SubStmt);
|
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2009-09-09 23:08:12 +08:00
|
|
|
Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
|
2010-08-24 07:25:46 +08:00
|
|
|
Stmt *SubStmt, Scope *CurScope) {
|
2011-08-18 10:04:29 +08:00
|
|
|
DiagnoseUnusedExprResult(SubStmt);
|
|
|
|
|
2010-08-25 16:40:02 +08:00
|
|
|
if (getCurFunction()->SwitchStack.empty()) {
|
2007-07-21 11:00:26 +08:00
|
|
|
Diag(DefaultLoc, diag::err_default_not_in_switch);
|
2014-05-29 22:05:12 +08:00
|
|
|
return SubStmt;
|
2007-07-21 11:00:26 +08:00
|
|
|
}
|
2008-12-29 00:13:43 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt);
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->SwitchStack.back()->addSwitchCase(DS);
|
2014-05-29 22:05:12 +08:00
|
|
|
return DS;
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2011-02-18 04:34:02 +08:00
|
|
|
StmtResult
|
|
|
|
Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
|
|
|
|
SourceLocation ColonLoc, Stmt *SubStmt) {
|
2011-02-17 15:39:24 +08:00
|
|
|
// If the label was multiply defined, reject it now.
|
|
|
|
if (TheDecl->getStmt()) {
|
|
|
|
Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName();
|
|
|
|
Diag(TheDecl->getLocation(), diag::note_previous_definition);
|
2014-05-29 22:05:12 +08:00
|
|
|
return SubStmt;
|
2007-05-28 14:28:18 +08:00
|
|
|
}
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2011-02-17 15:39:24 +08:00
|
|
|
// Otherwise, things are good. Fill in the declaration and return it.
|
|
|
|
LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt);
|
|
|
|
TheDecl->setStmt(LS);
|
2012-10-16 05:07:44 +08:00
|
|
|
if (!TheDecl->isGnuLocal()) {
|
|
|
|
TheDecl->setLocStart(IdentLoc);
|
2014-09-22 10:21:54 +08:00
|
|
|
if (!TheDecl->isMSAsmLabel()) {
|
|
|
|
// Don't update the location of MS ASM labels. These will result in
|
|
|
|
// a diagnostic, and changing the location here will mess that up.
|
|
|
|
TheDecl->setLocation(IdentLoc);
|
|
|
|
}
|
2012-10-16 05:07:44 +08:00
|
|
|
}
|
2014-05-29 22:05:12 +08:00
|
|
|
return LS;
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc,
|
2012-07-09 18:04:07 +08:00
|
|
|
ArrayRef<const Attr*> Attrs,
|
2012-04-14 08:33:13 +08:00
|
|
|
Stmt *SubStmt) {
|
2012-07-09 18:04:07 +08:00
|
|
|
// Fill in the declaration and return it.
|
|
|
|
AttributedStmt *LS = AttributedStmt::Create(Context, AttrLoc, Attrs, SubStmt);
|
2014-05-29 22:05:12 +08:00
|
|
|
return LS;
|
2012-04-14 08:33:13 +08:00
|
|
|
}
|
|
|
|
|
2016-02-19 07:58:40 +08:00
|
|
|
namespace {
|
|
|
|
class CommaVisitor : public EvaluatedExprVisitor<CommaVisitor> {
|
|
|
|
typedef EvaluatedExprVisitor<CommaVisitor> Inherited;
|
|
|
|
Sema &SemaRef;
|
|
|
|
public:
|
|
|
|
CommaVisitor(Sema &SemaRef) : Inherited(SemaRef.Context), SemaRef(SemaRef) {}
|
|
|
|
void VisitBinaryOperator(BinaryOperator *E) {
|
|
|
|
if (E->getOpcode() == BO_Comma)
|
|
|
|
SemaRef.DiagnoseCommaOperator(E->getLHS(), E->getExprLoc());
|
|
|
|
EvaluatedExprVisitor<CommaVisitor>::VisitBinaryOperator(E);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2016-06-30 05:17:59 +08:00
|
|
|
Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
|
|
|
|
ConditionResult Cond,
|
2010-11-20 10:04:01 +08:00
|
|
|
Stmt *thenStmt, SourceLocation ElseLoc,
|
|
|
|
Stmt *elseStmt) {
|
2016-06-24 03:16:49 +08:00
|
|
|
if (Cond.isInvalid())
|
|
|
|
Cond = ConditionResult(
|
|
|
|
*this, nullptr,
|
|
|
|
MakeFullExpr(new (Context) OpaqueValueExpr(SourceLocation(),
|
|
|
|
Context.BoolTy, VK_RValue),
|
|
|
|
IfLoc),
|
|
|
|
false);
|
|
|
|
|
|
|
|
Expr *CondExpr = Cond.get().second;
|
2016-06-24 03:02:52 +08:00
|
|
|
if (!Diags.isIgnored(diag::warn_comma_operator,
|
2016-06-24 03:16:49 +08:00
|
|
|
CondExpr->getExprLoc()))
|
|
|
|
CommaVisitor(*this).Visit(CondExpr);
|
2007-10-11 04:50:11 +08:00
|
|
|
|
2017-11-21 01:48:54 +08:00
|
|
|
if (!elseStmt)
|
Revert r318556 "Loosen -Wempty-body warning"
It seems this somehow made -Wempty-body fire in some macro cases where
it didn't before, e.g.
../../third_party/ffmpeg/libavcodec/bitstream.c(169,5): error: if statement has empty body [-Werror,-Wempty-body]
ff_dlog(NULL, "new table index=%d size=%d\n", table_index, table_size);
^
../../third_party/ffmpeg\libavutil/internal.h(276,80): note: expanded from macro 'ff_dlog'
# define ff_dlog(ctx, ...) do { if (0) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0)
^
../../third_party/ffmpeg/libavcodec/bitstream.c(169,5): note: put the
semicolon on a separate line to silence this warning
Reverting until this can be figured out.
> Do not show it when `if` or `else` come from macros.
> E.g.,
>
> #define USED(A) if (A); else
> #define SOME_IF(A) if (A)
>
> void test() {
> // No warnings are shown in those cases now.
> USED(0);
> SOME_IF(0);
> }
>
> Patch by Ilya Biryukov!
>
> Differential Revision: https://reviews.llvm.org/D40185
llvm-svn: 318665
2017-11-21 01:38:16 +08:00
|
|
|
DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt,
|
|
|
|
diag::warn_empty_if_body);
|
2016-06-23 16:41:20 +08:00
|
|
|
|
2016-07-14 08:11:03 +08:00
|
|
|
return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc,
|
|
|
|
elseStmt);
|
2016-06-24 03:16:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
|
2016-07-14 08:11:03 +08:00
|
|
|
Stmt *InitStmt, ConditionResult Cond,
|
|
|
|
Stmt *thenStmt, SourceLocation ElseLoc,
|
|
|
|
Stmt *elseStmt) {
|
2016-06-24 03:16:49 +08:00
|
|
|
if (Cond.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
2016-08-17 01:44:11 +08:00
|
|
|
if (IsConstexpr || isa<ObjCAvailabilityCheckExpr>(Cond.get().second))
|
2016-06-24 03:16:49 +08:00
|
|
|
getCurFunction()->setHasBranchProtectedScope();
|
|
|
|
|
|
|
|
DiagnoseUnusedExprResult(thenStmt);
|
2016-06-24 03:02:52 +08:00
|
|
|
DiagnoseUnusedExprResult(elseStmt);
|
|
|
|
|
2016-07-14 08:11:03 +08:00
|
|
|
return new (Context)
|
|
|
|
IfStmt(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
|
|
|
|
Cond.get().second, thenStmt, ElseLoc, elseStmt);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2007-08-24 02:29:20 +08:00
|
|
|
namespace {
|
|
|
|
struct CaseCompareFunctor {
|
|
|
|
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
|
|
|
const llvm::APSInt &RHS) {
|
|
|
|
return LHS.first < RHS;
|
|
|
|
}
|
2007-09-04 02:31:57 +08:00
|
|
|
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
|
|
|
const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
|
|
|
|
return LHS.first < RHS.first;
|
|
|
|
}
|
2007-08-24 02:29:20 +08:00
|
|
|
bool operator()(const llvm::APSInt &LHS,
|
|
|
|
const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
|
|
|
|
return LHS < RHS.first;
|
|
|
|
}
|
|
|
|
};
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2007-08-24 02:29:20 +08:00
|
|
|
|
2007-09-22 02:15:22 +08:00
|
|
|
/// CmpCaseVals - Comparison predicate for sorting case values.
|
|
|
|
///
|
|
|
|
static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs,
|
|
|
|
const std::pair<llvm::APSInt, CaseStmt*>& rhs) {
|
|
|
|
if (lhs.first < rhs.first)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (lhs.first == rhs.first &&
|
|
|
|
lhs.second->getCaseLoc().getRawEncoding()
|
|
|
|
< rhs.second->getCaseLoc().getRawEncoding())
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-02-09 06:24:16 +08:00
|
|
|
/// CmpEnumVals - Comparison predicate for sorting enumeration values.
|
|
|
|
///
|
|
|
|
static bool CmpEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
|
|
|
|
const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs)
|
|
|
|
{
|
|
|
|
return lhs.first < rhs.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// EqEnumVals - Comparison preficate for uniqing enumeration values.
|
|
|
|
///
|
|
|
|
static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
|
|
|
|
const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs)
|
|
|
|
{
|
|
|
|
return lhs.first == rhs.first;
|
|
|
|
}
|
|
|
|
|
2009-10-17 00:45:22 +08:00
|
|
|
/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of
|
|
|
|
/// potentially integral-promoted expression @p expr.
|
2017-08-09 16:57:09 +08:00
|
|
|
static QualType GetTypeBeforeIntegralPromotion(const Expr *&E) {
|
|
|
|
if (const auto *CleanUps = dyn_cast<ExprWithCleanups>(E))
|
|
|
|
E = CleanUps->getSubExpr();
|
|
|
|
while (const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
|
|
|
|
if (ImpCast->getCastKind() != CK_IntegralCast) break;
|
|
|
|
E = ImpCast->getSubExpr();
|
2009-10-17 00:45:22 +08:00
|
|
|
}
|
2017-08-09 16:57:09 +08:00
|
|
|
return E->getType();
|
2009-10-17 00:45:22 +08:00
|
|
|
}
|
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) {
|
2012-05-05 06:38:52 +08:00
|
|
|
class SwitchConvertDiagnoser : public ICEConvertDiagnoser {
|
|
|
|
Expr *Cond;
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2012-05-05 06:38:52 +08:00
|
|
|
public:
|
|
|
|
SwitchConvertDiagnoser(Expr *Cond)
|
2013-05-22 03:05:48 +08:00
|
|
|
: ICEConvertDiagnoser(/*AllowScopedEnumerations*/true, false, true),
|
|
|
|
Cond(Cond) {}
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2014-03-12 12:55:44 +08:00
|
|
|
SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
|
|
|
|
QualType T) override {
|
2012-05-05 06:38:52 +08:00
|
|
|
return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T;
|
|
|
|
}
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2014-03-12 12:55:44 +08:00
|
|
|
SemaDiagnosticBuilder diagnoseIncomplete(
|
|
|
|
Sema &S, SourceLocation Loc, QualType T) override {
|
2012-05-05 06:38:52 +08:00
|
|
|
return S.Diag(Loc, diag::err_switch_incomplete_class_type)
|
|
|
|
<< T << Cond->getSourceRange();
|
|
|
|
}
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2014-03-12 12:55:44 +08:00
|
|
|
SemaDiagnosticBuilder diagnoseExplicitConv(
|
|
|
|
Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
|
2012-05-05 06:38:52 +08:00
|
|
|
return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy;
|
|
|
|
}
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2014-03-12 12:55:44 +08:00
|
|
|
SemaDiagnosticBuilder noteExplicitConv(
|
|
|
|
Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
|
2012-05-05 06:38:52 +08:00
|
|
|
return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
|
|
|
|
<< ConvTy->isEnumeralType() << ConvTy;
|
|
|
|
}
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2014-03-12 12:55:44 +08:00
|
|
|
SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
|
|
|
|
QualType T) override {
|
2012-05-05 06:38:52 +08:00
|
|
|
return S.Diag(Loc, diag::err_switch_multiple_conversions) << T;
|
|
|
|
}
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2014-03-12 12:55:44 +08:00
|
|
|
SemaDiagnosticBuilder noteAmbiguous(
|
|
|
|
Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
|
2012-05-05 06:38:52 +08:00
|
|
|
return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
|
|
|
|
<< ConvTy->isEnumeralType() << ConvTy;
|
|
|
|
}
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2014-03-12 12:55:44 +08:00
|
|
|
SemaDiagnosticBuilder diagnoseConversion(
|
|
|
|
Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
|
2013-05-22 03:05:48 +08:00
|
|
|
llvm_unreachable("conversion functions are permitted");
|
2012-05-05 06:38:52 +08:00
|
|
|
}
|
|
|
|
} SwitchDiagnoser(Cond);
|
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
ExprResult CondResult =
|
2013-05-22 03:05:48 +08:00
|
|
|
PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser);
|
2016-06-24 03:02:52 +08:00
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return ExprError();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-08-06 15:30:58 +08:00
|
|
|
// C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
|
2016-06-24 03:02:52 +08:00
|
|
|
return UsualUnaryConversions(CondResult.get());
|
|
|
|
}
|
2011-08-06 15:30:58 +08:00
|
|
|
|
2016-06-30 05:17:59 +08:00
|
|
|
StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
|
|
|
|
Stmt *InitStmt, ConditionResult Cond) {
|
2016-06-24 03:02:52 +08:00
|
|
|
if (Cond.isInvalid())
|
2015-06-26 06:06:40 +08:00
|
|
|
return StmtError();
|
2010-08-01 08:26:45 +08:00
|
|
|
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->setHasBranchIntoScope();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2016-07-14 08:11:03 +08:00
|
|
|
SwitchStmt *SS = new (Context)
|
|
|
|
SwitchStmt(Context, InitStmt, Cond.get().first, Cond.get().second);
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->SwitchStack.push_back(SS);
|
2014-05-29 22:05:12 +08:00
|
|
|
return SS;
|
2010-01-24 09:50:29 +08:00
|
|
|
}
|
|
|
|
|
2010-10-02 06:05:14 +08:00
|
|
|
static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) {
|
2014-08-04 08:40:48 +08:00
|
|
|
Val = Val.extOrTrunc(BitWidth);
|
2010-10-02 06:05:14 +08:00
|
|
|
Val.setIsSigned(IsSigned);
|
|
|
|
}
|
|
|
|
|
2014-08-04 08:40:48 +08:00
|
|
|
/// Check the specified case value is in range for the given unpromoted switch
|
|
|
|
/// type.
|
|
|
|
static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val,
|
|
|
|
unsigned UnpromotedWidth, bool UnpromotedSign) {
|
|
|
|
// If the case value was signed and negative and the switch expression is
|
|
|
|
// unsigned, don't bother to warn: this is implementation-defined behavior.
|
|
|
|
// FIXME: Introduce a second, default-ignored warning for this case?
|
|
|
|
if (UnpromotedWidth < Val.getBitWidth()) {
|
|
|
|
llvm::APSInt ConvVal(Val);
|
|
|
|
AdjustAPSInt(ConvVal, UnpromotedWidth, UnpromotedSign);
|
|
|
|
AdjustAPSInt(ConvVal, Val.getBitWidth(), Val.isSigned());
|
|
|
|
// FIXME: Use different diagnostics for overflow in conversion to promoted
|
|
|
|
// type versus "switch expression cannot have this value". Use proper
|
|
|
|
// IntRange checking rather than just looking at the unpromoted type here.
|
|
|
|
if (ConvVal != Val)
|
|
|
|
S.Diag(Loc, diag::warn_case_value_overflow) << Val.toString(10)
|
|
|
|
<< ConvVal.toString(10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-28 08:53:20 +08:00
|
|
|
typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
|
|
|
|
|
2013-12-06 06:52:07 +08:00
|
|
|
/// Returns true if we should emit a diagnostic about this case expression not
|
|
|
|
/// being a part of the enum used in the switch controlling expression.
|
2014-11-28 08:53:20 +08:00
|
|
|
static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S,
|
2013-12-06 06:52:07 +08:00
|
|
|
const EnumDecl *ED,
|
2014-11-28 08:53:20 +08:00
|
|
|
const Expr *CaseExpr,
|
|
|
|
EnumValsTy::iterator &EI,
|
|
|
|
EnumValsTy::iterator &EIEnd,
|
|
|
|
const llvm::APSInt &Val) {
|
2017-03-21 10:23:00 +08:00
|
|
|
if (!ED->isClosed())
|
|
|
|
return false;
|
|
|
|
|
2014-11-28 08:53:20 +08:00
|
|
|
if (const DeclRefExpr *DRE =
|
|
|
|
dyn_cast<DeclRefExpr>(CaseExpr->IgnoreParenImpCasts())) {
|
2013-12-06 06:52:07 +08:00
|
|
|
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
|
|
|
|
QualType VarType = VD->getType();
|
2014-11-28 08:53:20 +08:00
|
|
|
QualType EnumType = S.Context.getTypeDeclType(ED);
|
|
|
|
if (VD->hasGlobalStorage() && VarType.isConstQualified() &&
|
|
|
|
S.Context.hasSameUnqualifiedType(EnumType, VarType))
|
2013-12-06 06:52:07 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2014-11-28 08:53:20 +08:00
|
|
|
|
2017-03-21 10:23:00 +08:00
|
|
|
if (ED->hasAttr<FlagEnumAttr>())
|
2014-11-28 08:53:20 +08:00
|
|
|
return !S.IsValueInFlagEnum(ED, Val, false);
|
|
|
|
|
2017-03-21 10:23:00 +08:00
|
|
|
while (EI != EIEnd && EI->first < Val)
|
|
|
|
EI++;
|
|
|
|
|
|
|
|
if (EI != EIEnd && EI->first == Val)
|
|
|
|
return false;
|
2014-11-28 08:53:20 +08:00
|
|
|
|
2013-12-06 06:52:07 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-08-09 16:57:09 +08:00
|
|
|
static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond,
|
|
|
|
const Expr *Case) {
|
|
|
|
QualType CondType = GetTypeBeforeIntegralPromotion(Cond);
|
|
|
|
QualType CaseType = Case->getType();
|
|
|
|
|
|
|
|
const EnumType *CondEnumType = CondType->getAs<EnumType>();
|
|
|
|
const EnumType *CaseEnumType = CaseType->getAs<EnumType>();
|
|
|
|
if (!CondEnumType || !CaseEnumType)
|
|
|
|
return;
|
|
|
|
|
2017-08-09 20:34:58 +08:00
|
|
|
// Ignore anonymous enums.
|
2017-09-09 08:25:05 +08:00
|
|
|
if (!CondEnumType->getDecl()->getIdentifier() &&
|
|
|
|
!CondEnumType->getDecl()->getTypedefNameForAnonDecl())
|
2017-08-09 20:34:58 +08:00
|
|
|
return;
|
2017-09-09 08:25:05 +08:00
|
|
|
if (!CaseEnumType->getDecl()->getIdentifier() &&
|
|
|
|
!CaseEnumType->getDecl()->getTypedefNameForAnonDecl())
|
2017-08-09 20:34:58 +08:00
|
|
|
return;
|
|
|
|
|
2017-08-09 16:57:09 +08:00
|
|
|
if (S.Context.hasSameUnqualifiedType(CondType, CaseType))
|
|
|
|
return;
|
|
|
|
|
2017-08-10 04:56:43 +08:00
|
|
|
S.Diag(Case->getExprLoc(), diag::warn_comparison_of_mixed_enum_types_switch)
|
2017-08-09 16:57:09 +08:00
|
|
|
<< CondType << CaseType << Cond->getSourceRange()
|
|
|
|
<< Case->getSourceRange();
|
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2010-08-24 07:25:46 +08:00
|
|
|
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
|
|
|
Stmt *BodyStmt) {
|
|
|
|
SwitchStmt *SS = cast<SwitchStmt>(Switch);
|
2010-08-25 16:40:02 +08:00
|
|
|
assert(SS == getCurFunction()->SwitchStack.back() &&
|
|
|
|
"switch stack missing push/pop!");
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2014-12-15 15:46:12 +08:00
|
|
|
getCurFunction()->SwitchStack.pop_back();
|
|
|
|
|
2014-05-21 22:48:43 +08:00
|
|
|
if (!BodyStmt) return StmtError();
|
2007-09-02 05:08:38 +08:00
|
|
|
SS->setBody(BodyStmt, SwitchLoc);
|
2007-07-22 15:07:56 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
Expr *CondExpr = SS->getCond();
|
2011-08-06 15:30:58 +08:00
|
|
|
if (!CondExpr) return StmtError();
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2009-11-25 13:02:21 +08:00
|
|
|
QualType CondType = CondExpr->getType();
|
2011-08-06 15:30:58 +08:00
|
|
|
|
2017-08-09 16:57:09 +08:00
|
|
|
const Expr *CondExprBeforePromotion = CondExpr;
|
2011-08-06 15:30:58 +08:00
|
|
|
QualType CondTypeBeforePromotion =
|
|
|
|
GetTypeBeforeIntegralPromotion(CondExprBeforePromotion);
|
2009-11-23 21:46:08 +08:00
|
|
|
|
2009-10-17 00:45:22 +08:00
|
|
|
// C++ 6.4.2.p2:
|
|
|
|
// Integral promotions are performed (on the switch condition).
|
|
|
|
//
|
|
|
|
// A case value unrepresentable by the original switch condition
|
|
|
|
// type (before the promotion) doesn't make sense, even when it can
|
|
|
|
// be represented by the promoted type. Therefore we need to find
|
|
|
|
// the pre-promotion type of the switch condition.
|
2009-10-18 03:32:54 +08:00
|
|
|
if (!CondExpr->isTypeDependent()) {
|
2010-06-30 07:25:20 +08:00
|
|
|
// We have already converted the expression to an integral or enumeration
|
2011-01-27 15:10:08 +08:00
|
|
|
// type, when we started the switch statement. If we don't have an
|
2010-06-30 07:25:20 +08:00
|
|
|
// appropriate type now, just return an error.
|
|
|
|
if (!CondType->isIntegralOrEnumerationType())
|
2009-10-18 03:32:54 +08:00
|
|
|
return StmtError();
|
|
|
|
|
2010-04-17 07:34:13 +08:00
|
|
|
if (CondExpr->isKnownToHaveBooleanValue()) {
|
2009-10-18 03:32:54 +08:00
|
|
|
// switch(bool_expr) {...} is often a programmer error, e.g.
|
|
|
|
// switch(n && mask) { ... } // Doh - should be "n & mask".
|
|
|
|
// One can always use an if statement instead of switch(bool_expr).
|
|
|
|
Diag(SwitchLoc, diag::warn_bool_switch_condition)
|
|
|
|
<< CondExpr->getSourceRange();
|
|
|
|
}
|
2007-07-22 15:07:56 +08:00
|
|
|
}
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2014-08-04 08:40:48 +08:00
|
|
|
// Get the bitwidth of the switched-on value after promotions. We must
|
2007-08-23 13:46:52 +08:00
|
|
|
// convert the integer case values to this width before comparison.
|
2009-09-09 23:08:12 +08:00
|
|
|
bool HasDependentValue
|
2009-05-16 07:57:33 +08:00
|
|
|
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
|
2014-08-04 08:40:48 +08:00
|
|
|
unsigned CondWidth = HasDependentValue ? 0 : Context.getIntWidth(CondType);
|
|
|
|
bool CondIsSigned = CondType->isSignedIntegerOrEnumerationType();
|
|
|
|
|
|
|
|
// Get the width and signedness that the condition might actually have, for
|
|
|
|
// warning purposes.
|
|
|
|
// FIXME: Grab an IntRange for the condition rather than using the unpromoted
|
|
|
|
// type.
|
|
|
|
unsigned CondWidthBeforePromotion
|
2011-02-24 15:31:28 +08:00
|
|
|
= HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
|
2014-08-04 08:40:48 +08:00
|
|
|
bool CondIsSignedBeforePromotion
|
2011-05-21 00:38:50 +08:00
|
|
|
= CondTypeBeforePromotion->isSignedIntegerOrEnumerationType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// Accumulate all of the case values in a vector so that we can sort them
|
|
|
|
// and detect duplicates. This vector contains the APInt for the case after
|
|
|
|
// it has been converted to the condition type.
|
2011-07-23 18:55:15 +08:00
|
|
|
typedef SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy;
|
2007-08-24 02:29:20 +08:00
|
|
|
CaseValsTy CaseVals;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// Keep track of any GNU case ranges we see. The APSInt is the low value.
|
2010-02-09 06:24:16 +08:00
|
|
|
typedef std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRangesTy;
|
|
|
|
CaseRangesTy CaseRanges;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-05-26 14:22:03 +08:00
|
|
|
DefaultStmt *TheDefaultStmt = nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 14:23:56 +08:00
|
|
|
bool CaseListIsErroneous = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue;
|
2007-07-22 15:07:56 +08:00
|
|
|
SC = SC->getNextSwitchCase()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-22 15:07:56 +08:00
|
|
|
if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) {
|
2007-08-23 13:46:52 +08:00
|
|
|
if (TheDefaultStmt) {
|
|
|
|
Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined);
|
2008-11-24 07:12:31 +08:00
|
|
|
Diag(TheDefaultStmt->getDefaultLoc(), diag::note_duplicate_case_prev);
|
2009-01-11 08:38:46 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// FIXME: Remove the default statement from the switch block so that
|
2009-05-16 15:39:55 +08:00
|
|
|
// we'll return a valid AST. This requires recursing down the AST and
|
|
|
|
// finding it, not something we are set up to do right now. For now,
|
|
|
|
// just lop the entire switch stmt out of the AST.
|
2007-08-23 14:23:56 +08:00
|
|
|
CaseListIsErroneous = true;
|
2007-07-22 15:07:56 +08:00
|
|
|
}
|
2007-08-23 13:46:52 +08:00
|
|
|
TheDefaultStmt = DS;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
} else {
|
|
|
|
CaseStmt *CS = cast<CaseStmt>(SC);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-17 03:17:22 +08:00
|
|
|
Expr *Lo = CS->getLHS();
|
2009-05-16 07:57:33 +08:00
|
|
|
|
|
|
|
if (Lo->isTypeDependent() || Lo->isValueDependent()) {
|
|
|
|
HasDependentValue = true;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2017-08-09 16:57:09 +08:00
|
|
|
checkEnumTypesInSwitchStmt(*this, CondExpr, Lo);
|
|
|
|
|
2012-01-19 07:55:52 +08:00
|
|
|
llvm::APSInt LoVal;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-01-02 19:42:31 +08:00
|
|
|
if (getLangOpts().CPlusPlus11) {
|
2012-01-19 07:55:52 +08:00
|
|
|
// C++11 [stmt.switch]p2: the constant-expression shall be a converted
|
|
|
|
// constant expression of the promoted type of the switch condition.
|
|
|
|
ExprResult ConvLo =
|
|
|
|
CheckConvertedConstantExpression(Lo, CondType, LoVal, CCEK_CaseValue);
|
|
|
|
if (ConvLo.isInvalid()) {
|
|
|
|
CaseListIsErroneous = true;
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
Lo = ConvLo.get();
|
2012-01-19 07:55:52 +08:00
|
|
|
} else {
|
|
|
|
// We already verified that the expression has a i-c-e value (C99
|
|
|
|
// 6.8.4.2p3) - get that value now.
|
2013-01-25 06:11:45 +08:00
|
|
|
LoVal = Lo->EvaluateKnownConstInt(Context);
|
2012-01-19 07:55:52 +08:00
|
|
|
|
|
|
|
// If the LHS is not the same type as the condition, insert an implicit
|
|
|
|
// cast.
|
2014-05-29 18:55:11 +08:00
|
|
|
Lo = DefaultLvalueConversion(Lo).get();
|
|
|
|
Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).get();
|
2012-01-19 07:55:52 +08:00
|
|
|
}
|
|
|
|
|
2014-08-04 08:40:48 +08:00
|
|
|
// Check the unconverted value is within the range of possible values of
|
|
|
|
// the switch expression.
|
|
|
|
checkCaseValue(*this, Lo->getLocStart(), LoVal,
|
|
|
|
CondWidthBeforePromotion, CondIsSignedBeforePromotion);
|
|
|
|
|
|
|
|
// Convert the value to the same width/sign as the condition.
|
|
|
|
AdjustAPSInt(LoVal, CondWidth, CondIsSigned);
|
2007-07-18 10:28:47 +08:00
|
|
|
|
2008-01-17 03:17:22 +08:00
|
|
|
CS->setLHS(Lo);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 14:23:56 +08:00
|
|
|
// If this is a case range, remember it in CaseRanges, otherwise CaseVals.
|
2009-05-16 07:57:33 +08:00
|
|
|
if (CS->getRHS()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (CS->getRHS()->isTypeDependent() ||
|
2009-05-16 07:57:33 +08:00
|
|
|
CS->getRHS()->isValueDependent()) {
|
|
|
|
HasDependentValue = true;
|
|
|
|
break;
|
|
|
|
}
|
2007-08-23 13:46:52 +08:00
|
|
|
CaseRanges.push_back(std::make_pair(LoVal, CS));
|
2009-09-09 23:08:12 +08:00
|
|
|
} else
|
2007-08-23 14:23:56 +08:00
|
|
|
CaseVals.push_back(std::make_pair(LoVal, CS));
|
2007-08-23 13:46:52 +08:00
|
|
|
}
|
|
|
|
}
|
2007-08-23 14:23:56 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
if (!HasDependentValue) {
|
2010-05-18 11:19:21 +08:00
|
|
|
// If we don't have a default statement, check whether the
|
|
|
|
// condition is constant.
|
|
|
|
llvm::APSInt ConstantCondValue;
|
|
|
|
bool HasConstantCond = false;
|
|
|
|
if (!HasDependentValue && !TheDefaultStmt) {
|
2014-08-04 08:40:48 +08:00
|
|
|
HasConstantCond = CondExpr->EvaluateAsInt(ConstantCondValue, Context,
|
|
|
|
Expr::SE_AllowSideEffects);
|
2011-12-29 03:48:30 +08:00
|
|
|
assert(!HasConstantCond ||
|
|
|
|
(ConstantCondValue.getBitWidth() == CondWidth &&
|
|
|
|
ConstantCondValue.isSigned() == CondIsSigned));
|
2010-05-18 11:19:21 +08:00
|
|
|
}
|
2011-12-29 03:48:30 +08:00
|
|
|
bool ShouldCheckConstantCond = HasConstantCond;
|
2010-05-18 11:19:21 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// Sort all the scalar case values so we can easily detect duplicates.
|
|
|
|
std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals);
|
|
|
|
|
|
|
|
if (!CaseVals.empty()) {
|
2010-05-18 11:19:21 +08:00
|
|
|
for (unsigned i = 0, e = CaseVals.size(); i != e; ++i) {
|
|
|
|
if (ShouldCheckConstantCond &&
|
|
|
|
CaseVals[i].first == ConstantCondValue)
|
|
|
|
ShouldCheckConstantCond = false;
|
|
|
|
|
|
|
|
if (i != 0 && CaseVals[i].first == CaseVals[i-1].first) {
|
2009-05-16 07:57:33 +08:00
|
|
|
// If we have a duplicate, report it.
|
2012-05-16 13:32:58 +08:00
|
|
|
// 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();
|
|
|
|
}
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallString<16> CaseValStr;
|
2012-05-17 00:11:17 +08:00
|
|
|
CaseVals[i-1].first.toString(CaseValStr);
|
2012-05-16 13:32:58 +08:00
|
|
|
|
|
|
|
if (PrevString == CurrString)
|
|
|
|
Diag(CaseVals[i].second->getLHS()->getLocStart(),
|
|
|
|
diag::err_duplicate_case) <<
|
2015-03-18 18:26:22 +08:00
|
|
|
(PrevString.empty() ? StringRef(CaseValStr) : PrevString);
|
2012-05-16 13:32:58 +08:00
|
|
|
else
|
|
|
|
Diag(CaseVals[i].second->getLHS()->getLocStart(),
|
|
|
|
diag::err_duplicate_case_differing_expr) <<
|
2015-03-18 18:26:22 +08:00
|
|
|
(PrevString.empty() ? StringRef(CaseValStr) : PrevString) <<
|
|
|
|
(CurrString.empty() ? StringRef(CaseValStr) : CurrString) <<
|
2012-05-16 13:32:58 +08:00
|
|
|
CaseValStr;
|
|
|
|
|
2010-05-18 11:19:21 +08:00
|
|
|
Diag(CaseVals[i-1].second->getLHS()->getLocStart(),
|
2009-05-16 07:57:33 +08:00
|
|
|
diag::note_duplicate_case_prev);
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: We really want to remove the bogus case stmt from the
|
|
|
|
// substmt, but we have no way to do this right now.
|
2009-05-16 07:57:33 +08:00
|
|
|
CaseListIsErroneous = true;
|
|
|
|
}
|
2007-08-24 01:48:14 +08:00
|
|
|
}
|
2007-08-23 14:23:56 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// 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());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// 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) {
|
2010-05-18 11:19:21 +08:00
|
|
|
llvm::APSInt &LoVal = CaseRanges[i].first;
|
2009-05-16 07:57:33 +08:00
|
|
|
CaseStmt *CR = CaseRanges[i].second;
|
|
|
|
Expr *Hi = CR->getRHS();
|
2012-01-19 07:55:52 +08:00
|
|
|
llvm::APSInt HiVal;
|
|
|
|
|
2013-01-02 19:42:31 +08:00
|
|
|
if (getLangOpts().CPlusPlus11) {
|
2012-01-19 07:55:52 +08:00
|
|
|
// C++11 [stmt.switch]p2: the constant-expression shall be a converted
|
|
|
|
// constant expression of the promoted type of the switch condition.
|
|
|
|
ExprResult ConvHi =
|
|
|
|
CheckConvertedConstantExpression(Hi, CondType, HiVal,
|
|
|
|
CCEK_CaseValue);
|
|
|
|
if (ConvHi.isInvalid()) {
|
|
|
|
CaseListIsErroneous = true;
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
Hi = ConvHi.get();
|
2012-01-19 07:55:52 +08:00
|
|
|
} else {
|
|
|
|
HiVal = Hi->EvaluateKnownConstInt(Context);
|
|
|
|
|
|
|
|
// If the RHS is not the same type as the condition, insert an
|
|
|
|
// implicit cast.
|
2014-05-29 18:55:11 +08:00
|
|
|
Hi = DefaultLvalueConversion(Hi).get();
|
|
|
|
Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).get();
|
2012-01-19 07:55:52 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-08-04 08:40:48 +08:00
|
|
|
// Check the unconverted value is within the range of possible values of
|
|
|
|
// the switch expression.
|
|
|
|
checkCaseValue(*this, Hi->getLocStart(), HiVal,
|
|
|
|
CondWidthBeforePromotion, CondIsSignedBeforePromotion);
|
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// Convert the value to the same width/sign as the condition.
|
2014-08-04 08:40:48 +08:00
|
|
|
AdjustAPSInt(HiVal, CondWidth, CondIsSigned);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
CR->setRHS(Hi);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// If the low value is bigger than the high value, the case is empty.
|
2010-05-18 11:19:21 +08:00
|
|
|
if (LoVal > HiVal) {
|
2009-05-16 07:57:33 +08:00
|
|
|
Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
|
|
|
|
<< SourceRange(CR->getLHS()->getLocStart(),
|
2010-10-02 06:05:14 +08:00
|
|
|
Hi->getLocEnd());
|
2009-05-16 07:57:33 +08:00
|
|
|
CaseRanges.erase(CaseRanges.begin()+i);
|
2016-02-19 06:34:54 +08:00
|
|
|
--i;
|
|
|
|
--e;
|
2009-05-16 07:57:33 +08:00
|
|
|
continue;
|
|
|
|
}
|
2010-05-18 11:19:21 +08:00
|
|
|
|
|
|
|
if (ShouldCheckConstantCond &&
|
|
|
|
LoVal <= ConstantCondValue &&
|
|
|
|
ConstantCondValue <= HiVal)
|
|
|
|
ShouldCheckConstantCond = false;
|
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
HiVals.push_back(HiVal);
|
2007-08-24 02:29:20 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// 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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// Check to see whether the case range overlaps with any
|
|
|
|
// singleton cases.
|
2014-05-26 14:22:03 +08:00
|
|
|
CaseStmt *OverlapStmt = nullptr;
|
2009-05-16 07:57:33 +08:00
|
|
|
llvm::APSInt OverlapVal(32);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// 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;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// 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;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// 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;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
if (OverlapStmt) {
|
|
|
|
// If we have a duplicate, report it.
|
|
|
|
Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case)
|
|
|
|
<< OverlapVal.toString(10);
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(OverlapStmt->getLHS()->getLocStart(),
|
2009-05-16 07:57:33 +08:00
|
|
|
diag::note_duplicate_case_prev);
|
2009-05-16 15:39:55 +08:00
|
|
|
// FIXME: We really want to remove the bogus case stmt from the
|
|
|
|
// substmt, but we have no way to do this right now.
|
2009-05-16 07:57:33 +08:00
|
|
|
CaseListIsErroneous = true;
|
|
|
|
}
|
2007-08-24 02:29:20 +08:00
|
|
|
}
|
2007-08-23 14:23:56 +08:00
|
|
|
}
|
2010-02-09 06:24:16 +08:00
|
|
|
|
2010-05-18 11:19:21 +08:00
|
|
|
// Complain if we have a constant condition and we didn't find a match.
|
|
|
|
if (!CaseListIsErroneous && ShouldCheckConstantCond) {
|
|
|
|
// TODO: it would be nice if we printed enums as enums, chars as
|
|
|
|
// chars, etc.
|
|
|
|
Diag(CondExpr->getExprLoc(), diag::warn_missing_case_for_condition)
|
|
|
|
<< ConstantCondValue.toString(10)
|
|
|
|
<< CondExpr->getSourceRange();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check to see if switch is over an Enum and handles all of its
|
2010-09-09 08:05:53 +08:00
|
|
|
// values. We only issue a warning if there is not 'default:', but
|
|
|
|
// we still do the analysis to preserve this information in the AST
|
|
|
|
// (which can be used by flow-based analyes).
|
2010-05-18 11:19:21 +08:00
|
|
|
//
|
2010-09-17 01:09:42 +08:00
|
|
|
const EnumType *ET = CondTypeBeforePromotion->getAs<EnumType>();
|
2010-09-09 08:05:53 +08:00
|
|
|
|
2010-02-09 06:24:16 +08:00
|
|
|
// If switch has default case, then ignore it.
|
2016-12-08 22:46:05 +08:00
|
|
|
if (!CaseListIsErroneous && !HasConstantCond && ET &&
|
|
|
|
ET->getDecl()->isCompleteDefinition()) {
|
2010-02-09 06:24:16 +08:00
|
|
|
const EnumDecl *ED = ET->getDecl();
|
|
|
|
EnumValsTy EnumVals;
|
|
|
|
|
2010-05-18 11:19:21 +08:00
|
|
|
// Gather all enum values, set their type and sort them,
|
|
|
|
// allowing easier comparison with CaseVals.
|
2014-03-09 02:45:14 +08:00
|
|
|
for (auto *EDI : ED->enumerators()) {
|
2010-10-02 06:05:14 +08:00
|
|
|
llvm::APSInt Val = EDI->getInitVal();
|
|
|
|
AdjustAPSInt(Val, CondWidth, CondIsSigned);
|
2014-03-09 02:45:14 +08:00
|
|
|
EnumVals.push_back(std::make_pair(Val, EDI));
|
2010-02-09 06:24:16 +08:00
|
|
|
}
|
|
|
|
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
|
2014-11-28 08:53:20 +08:00
|
|
|
auto EI = EnumVals.begin(), EIEnd =
|
2010-05-18 11:19:21 +08:00
|
|
|
std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
|
2010-09-09 08:05:53 +08:00
|
|
|
|
|
|
|
// See which case values aren't in enum.
|
2012-01-22 10:31:55 +08:00
|
|
|
for (CaseValsTy::const_iterator CI = CaseVals.begin();
|
2014-11-28 08:53:20 +08:00
|
|
|
CI != CaseVals.end(); CI++) {
|
|
|
|
Expr *CaseExpr = CI->second->getLHS();
|
|
|
|
if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
|
|
|
|
CI->first))
|
|
|
|
Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
|
|
|
|
<< CondTypeBeforePromotion;
|
2012-01-22 10:31:55 +08:00
|
|
|
}
|
2014-11-28 08:53:20 +08:00
|
|
|
|
2012-01-22 10:31:55 +08:00
|
|
|
// See which of case ranges aren't in enum
|
|
|
|
EI = EnumVals.begin();
|
|
|
|
for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
|
2014-11-28 08:53:20 +08:00
|
|
|
RI != CaseRanges.end(); RI++) {
|
|
|
|
Expr *CaseExpr = RI->second->getLHS();
|
|
|
|
if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
|
|
|
|
RI->first))
|
|
|
|
Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
|
|
|
|
<< CondTypeBeforePromotion;
|
2010-09-09 10:57:51 +08:00
|
|
|
|
2012-08-11 01:56:09 +08:00
|
|
|
llvm::APSInt Hi =
|
2012-01-22 10:31:55 +08:00
|
|
|
RI->second->getRHS()->EvaluateKnownConstInt(Context);
|
|
|
|
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
|
2014-11-28 08:53:20 +08:00
|
|
|
|
|
|
|
CaseExpr = RI->second->getRHS();
|
|
|
|
if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
|
|
|
|
Hi))
|
|
|
|
Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
|
|
|
|
<< CondTypeBeforePromotion;
|
2010-02-09 06:24:16 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-09-09 08:05:53 +08:00
|
|
|
// Check which enum vals aren't in switch
|
2014-11-28 08:53:20 +08:00
|
|
|
auto CI = CaseVals.begin();
|
|
|
|
auto RI = CaseRanges.begin();
|
2010-09-09 08:05:53 +08:00
|
|
|
bool hasCasesNotInSwitch = false;
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<DeclarationName,8> UnhandledNames;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2014-11-28 08:53:20 +08:00
|
|
|
for (EI = EnumVals.begin(); EI != EIEnd; EI++){
|
2010-09-17 01:09:42 +08:00
|
|
|
// Drop unneeded case values
|
2010-02-09 06:24:16 +08:00
|
|
|
while (CI != CaseVals.end() && CI->first < EI->first)
|
|
|
|
CI++;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-02-09 06:24:16 +08:00
|
|
|
if (CI != CaseVals.end() && CI->first == EI->first)
|
|
|
|
continue;
|
|
|
|
|
2010-09-09 08:05:53 +08:00
|
|
|
// Drop unneeded case ranges
|
2010-02-09 06:24:16 +08:00
|
|
|
for (; RI != CaseRanges.end(); RI++) {
|
2011-10-11 02:28:20 +08:00
|
|
|
llvm::APSInt Hi =
|
|
|
|
RI->second->getRHS()->EvaluateKnownConstInt(Context);
|
2010-10-02 06:05:14 +08:00
|
|
|
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
|
2010-02-09 06:24:16 +08:00
|
|
|
if (EI->first <= Hi)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-09-09 08:05:53 +08:00
|
|
|
if (RI == CaseRanges.end() || EI->first < RI->first) {
|
2010-09-09 14:53:59 +08:00
|
|
|
hasCasesNotInSwitch = true;
|
2012-01-22 02:12:07 +08:00
|
|
|
UnhandledNames.push_back(EI->second->getDeclName());
|
2010-09-09 14:53:59 +08:00
|
|
|
}
|
2010-02-09 06:24:16 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2017-03-21 10:23:00 +08:00
|
|
|
if (TheDefaultStmt && UnhandledNames.empty() && ED->isClosedNonFlag())
|
2012-01-23 12:46:12 +08:00
|
|
|
Diag(TheDefaultStmt->getDefaultLoc(), diag::warn_unreachable_default);
|
2012-01-22 02:12:07 +08:00
|
|
|
|
2010-09-17 01:09:42 +08:00
|
|
|
// Produce a nice diagnostic if multiple values aren't handled.
|
2015-03-28 01:23:14 +08:00
|
|
|
if (!UnhandledNames.empty()) {
|
|
|
|
DiagnosticBuilder DB = Diag(CondExpr->getExprLoc(),
|
|
|
|
TheDefaultStmt ? diag::warn_def_missing_case
|
|
|
|
: diag::warn_missing_case)
|
|
|
|
<< (int)UnhandledNames.size();
|
|
|
|
|
|
|
|
for (size_t I = 0, E = std::min(UnhandledNames.size(), (size_t)3);
|
|
|
|
I != E; ++I)
|
|
|
|
DB << UnhandledNames[I];
|
2010-09-17 01:09:42 +08:00
|
|
|
}
|
2010-09-09 08:05:53 +08:00
|
|
|
|
|
|
|
if (!hasCasesNotInSwitch)
|
2010-09-09 14:53:59 +08:00
|
|
|
SS->setAllEnumCasesCovered();
|
2010-02-09 06:24:16 +08:00
|
|
|
}
|
2007-08-23 14:23:56 +08:00
|
|
|
}
|
2009-05-16 07:57:33 +08:00
|
|
|
|
2014-05-21 22:48:43 +08:00
|
|
|
if (BodyStmt)
|
|
|
|
DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), BodyStmt,
|
|
|
|
diag::warn_empty_switch_body);
|
2012-02-15 06:14:32 +08:00
|
|
|
|
2009-05-16 15:39:55 +08:00
|
|
|
// 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.
|
2007-08-23 14:23:56 +08:00
|
|
|
if (CaseListIsErroneous)
|
2009-01-11 08:38:46 +08:00
|
|
|
return StmtError();
|
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return SS;
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2012-07-18 02:00:08 +08:00
|
|
|
void
|
|
|
|
Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
|
|
|
|
Expr *SrcExpr) {
|
2014-06-16 07:30:39 +08:00
|
|
|
if (Diags.isIgnored(diag::warn_not_in_enum_assignment, SrcExpr->getExprLoc()))
|
2012-07-18 02:00:08 +08:00
|
|
|
return;
|
2012-08-11 01:56:09 +08:00
|
|
|
|
2012-07-18 02:00:08 +08:00
|
|
|
if (const EnumType *ET = DstType->getAs<EnumType>())
|
2013-12-06 07:06:53 +08:00
|
|
|
if (!Context.hasSameUnqualifiedType(SrcType, DstType) &&
|
2012-07-18 02:00:08 +08:00
|
|
|
SrcType->isIntegerType()) {
|
|
|
|
if (!SrcExpr->isTypeDependent() && !SrcExpr->isValueDependent() &&
|
|
|
|
SrcExpr->isIntegerConstantExpr(Context)) {
|
|
|
|
// Get the bitwidth of the enum value before promotions.
|
2013-06-06 21:48:00 +08:00
|
|
|
unsigned DstWidth = Context.getIntWidth(DstType);
|
2012-07-18 02:00:08 +08:00
|
|
|
bool DstIsSigned = DstType->isSignedIntegerOrEnumerationType();
|
|
|
|
|
|
|
|
llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context);
|
2013-06-06 21:48:00 +08:00
|
|
|
AdjustAPSInt(RhsVal, DstWidth, DstIsSigned);
|
2012-07-18 02:00:08 +08:00
|
|
|
const EnumDecl *ED = ET->getDecl();
|
2014-11-28 08:53:20 +08:00
|
|
|
|
2017-03-21 10:23:00 +08:00
|
|
|
if (!ED->isClosed())
|
|
|
|
return;
|
|
|
|
|
2014-11-28 08:53:20 +08:00
|
|
|
if (ED->hasAttr<FlagEnumAttr>()) {
|
|
|
|
if (!IsValueInFlagEnum(ED, RhsVal, true))
|
|
|
|
Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
|
2013-12-06 07:06:53 +08:00
|
|
|
<< DstType.getUnqualifiedType();
|
2014-11-28 08:53:20 +08:00
|
|
|
} else {
|
|
|
|
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 (auto *EDI : ED->enumerators()) {
|
|
|
|
llvm::APSInt Val = EDI->getInitVal();
|
|
|
|
AdjustAPSInt(Val, DstWidth, 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 values aren't in the 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_assignment)
|
|
|
|
<< DstType.getUnqualifiedType();
|
|
|
|
}
|
2012-07-18 02:00:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond,
|
|
|
|
Stmt *Body) {
|
|
|
|
if (Cond.isInvalid())
|
2009-11-25 08:27:52 +08:00
|
|
|
return StmtError();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
auto CondVal = Cond.get();
|
|
|
|
CheckBreakContinueBinding(CondVal.second);
|
|
|
|
|
|
|
|
if (CondVal.second &&
|
|
|
|
!Diags.isIgnored(diag::warn_comma_operator, CondVal.second->getExprLoc()))
|
|
|
|
CommaVisitor(*this).Visit(CondVal.second);
|
2016-02-19 07:58:40 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
DiagnoseUnusedExprResult(Body);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-15 06:14:32 +08:00
|
|
|
if (isa<NullStmt>(Body))
|
|
|
|
getCurCompoundScope().setHasEmptyLoopBodies();
|
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context)
|
2016-06-24 03:02:52 +08:00
|
|
|
WhileStmt(Context, CondVal.first, CondVal.second, Body, WhileLoc);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2010-08-24 07:25:46 +08:00
|
|
|
Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
|
2009-06-13 07:04:47 +08:00
|
|
|
SourceLocation WhileLoc, SourceLocation CondLParen,
|
2010-08-24 07:25:46 +08:00
|
|
|
Expr *Cond, SourceLocation CondRParen) {
|
|
|
|
assert(Cond && "ActOnDoStmt(): missing expression");
|
2009-01-17 07:28:06 +08:00
|
|
|
|
2014-01-23 23:05:00 +08:00
|
|
|
CheckBreakContinueBinding(Cond);
|
2016-06-24 03:02:52 +08:00
|
|
|
ExprResult CondResult = CheckBooleanCondition(DoLoc, Cond);
|
2012-11-19 06:28:42 +08:00
|
|
|
if (CondResult.isInvalid())
|
2009-10-13 05:59:07 +08:00
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
Cond = CondResult.get();
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2013-01-15 06:39:08 +08:00
|
|
|
CondResult = ActOnFinishFullExpr(Cond, DoLoc);
|
2010-08-24 07:25:46 +08:00
|
|
|
if (CondResult.isInvalid())
|
2010-05-07 01:25:47 +08:00
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
Cond = CondResult.get();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
DiagnoseUnusedExprResult(Body);
|
2009-07-31 06:39:03 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2012-05-01 02:01:30 +08:00
|
|
|
namespace {
|
2017-06-02 12:24:46 +08:00
|
|
|
// Use SetVector since the diagnostic cares about the ordering of the Decl's.
|
|
|
|
using DeclSetVector =
|
|
|
|
llvm::SetVector<VarDecl *, llvm::SmallVector<VarDecl *, 8>,
|
|
|
|
llvm::SmallPtrSet<VarDecl *, 8>>;
|
|
|
|
|
2012-05-01 02:01:30 +08:00
|
|
|
// 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> {
|
2017-06-02 12:24:46 +08:00
|
|
|
DeclSetVector &Decls;
|
2013-07-15 00:47:36 +08:00
|
|
|
SmallVectorImpl<SourceRange> &Ranges;
|
2012-05-01 02:01:30 +08:00
|
|
|
bool Simple;
|
2013-06-01 06:46:45 +08:00
|
|
|
public:
|
|
|
|
typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2017-06-02 12:24:46 +08:00
|
|
|
DeclExtractor(Sema &S, DeclSetVector &Decls,
|
2013-07-15 00:47:36 +08:00
|
|
|
SmallVectorImpl<SourceRange> &Ranges) :
|
2013-06-01 06:46:45 +08:00
|
|
|
Inherited(S.Context),
|
|
|
|
Decls(Decls),
|
|
|
|
Ranges(Ranges),
|
|
|
|
Simple(true) {}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
bool isSimple() { return Simple; }
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
// Replaces the method in EvaluatedExprVisitor.
|
|
|
|
void VisitMemberExpr(MemberExpr* E) {
|
|
|
|
Simple = false;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
// Any Stmt not whitelisted will cause the condition to be marked complex.
|
|
|
|
void VisitStmt(Stmt *S) {
|
|
|
|
Simple = false;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitBinaryOperator(BinaryOperator *E) {
|
|
|
|
Visit(E->getLHS());
|
|
|
|
Visit(E->getRHS());
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitCastExpr(CastExpr *E) {
|
2012-05-01 02:01:30 +08:00
|
|
|
Visit(E->getSubExpr());
|
2013-06-01 06:46:45 +08:00
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitUnaryOperator(UnaryOperator *E) {
|
|
|
|
// Skip checking conditionals with derefernces.
|
|
|
|
if (E->getOpcode() == UO_Deref)
|
|
|
|
Simple = false;
|
|
|
|
else
|
|
|
|
Visit(E->getSubExpr());
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitConditionalOperator(ConditionalOperator *E) {
|
|
|
|
Visit(E->getCond());
|
|
|
|
Visit(E->getTrueExpr());
|
|
|
|
Visit(E->getFalseExpr());
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitParenExpr(ParenExpr *E) {
|
|
|
|
Visit(E->getSubExpr());
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
|
|
|
|
Visit(E->getOpaqueValue()->getSourceExpr());
|
|
|
|
Visit(E->getFalseExpr());
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitIntegerLiteral(IntegerLiteral *E) { }
|
|
|
|
void VisitFloatingLiteral(FloatingLiteral *E) { }
|
|
|
|
void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { }
|
|
|
|
void VisitCharacterLiteral(CharacterLiteral *E) { }
|
|
|
|
void VisitGNUNullExpr(GNUNullExpr *E) { }
|
|
|
|
void VisitImaginaryLiteral(ImaginaryLiteral *E) { }
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitDeclRefExpr(DeclRefExpr *E) {
|
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
|
|
|
|
if (!VD) return;
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
Ranges.push_back(E->getSourceRange());
|
|
|
|
|
|
|
|
Decls.insert(VD);
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
|
|
|
}; // end class DeclExtractor
|
|
|
|
|
2015-08-28 22:42:54 +08:00
|
|
|
// DeclMatcher checks to see if the decls are used in a non-evaluated
|
2012-08-11 01:56:09 +08:00
|
|
|
// context.
|
2012-05-01 02:01:30 +08:00
|
|
|
class DeclMatcher : public EvaluatedExprVisitor<DeclMatcher> {
|
2017-06-02 12:24:46 +08:00
|
|
|
DeclSetVector &Decls;
|
2012-05-01 02:01:30 +08:00
|
|
|
bool FoundDecl;
|
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
public:
|
|
|
|
typedef EvaluatedExprVisitor<DeclMatcher> Inherited;
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2017-06-02 12:24:46 +08:00
|
|
|
DeclMatcher(Sema &S, DeclSetVector &Decls, Stmt *Statement) :
|
2013-06-01 06:46:45 +08:00
|
|
|
Inherited(S.Context), Decls(Decls), FoundDecl(false) {
|
|
|
|
if (!Statement) return;
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
Visit(Statement);
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitReturnStmt(ReturnStmt *S) {
|
|
|
|
FoundDecl = true;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitBreakStmt(BreakStmt *S) {
|
|
|
|
FoundDecl = true;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitGotoStmt(GotoStmt *S) {
|
|
|
|
FoundDecl = true;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitCastExpr(CastExpr *E) {
|
|
|
|
if (E->getCastKind() == CK_LValueToRValue)
|
|
|
|
CheckLValueToRValueCast(E->getSubExpr());
|
|
|
|
else
|
|
|
|
Visit(E->getSubExpr());
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void CheckLValueToRValueCast(Expr *E) {
|
|
|
|
E = E->IgnoreParenImpCasts();
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
if (isa<DeclRefExpr>(E)) {
|
|
|
|
return;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
|
|
|
|
Visit(CO->getCond());
|
|
|
|
CheckLValueToRValueCast(CO->getTrueExpr());
|
|
|
|
CheckLValueToRValueCast(CO->getFalseExpr());
|
|
|
|
return;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
if (BinaryConditionalOperator *BCO =
|
|
|
|
dyn_cast<BinaryConditionalOperator>(E)) {
|
|
|
|
CheckLValueToRValueCast(BCO->getOpaqueValue()->getSourceExpr());
|
|
|
|
CheckLValueToRValueCast(BCO->getFalseExpr());
|
|
|
|
return;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
Visit(E);
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
void VisitDeclRefExpr(DeclRefExpr *E) {
|
|
|
|
if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
|
|
|
|
if (Decls.count(VD))
|
|
|
|
FoundDecl = true;
|
|
|
|
}
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2016-03-10 10:02:48 +08:00
|
|
|
void VisitPseudoObjectExpr(PseudoObjectExpr *POE) {
|
|
|
|
// Only need to visit the semantics for POE.
|
|
|
|
// SyntaticForm doesn't really use the Decal.
|
|
|
|
for (auto *S : POE->semantics()) {
|
|
|
|
if (auto *OVE = dyn_cast<OpaqueValueExpr>(S))
|
|
|
|
// Look past the OVE into the expression it binds.
|
|
|
|
Visit(OVE->getSourceExpr());
|
|
|
|
else
|
|
|
|
Visit(S);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-01 06:46:45 +08:00
|
|
|
bool FoundDeclInUse() { return FoundDecl; }
|
2012-05-01 02:01:30 +08:00
|
|
|
|
|
|
|
}; // end class DeclMatcher
|
|
|
|
|
|
|
|
void CheckForLoopConditionalStatement(Sema &S, Expr *Second,
|
|
|
|
Expr *Third, Stmt *Body) {
|
|
|
|
// Condition is empty
|
|
|
|
if (!Second) return;
|
|
|
|
|
2014-06-16 07:30:39 +08:00
|
|
|
if (S.Diags.isIgnored(diag::warn_variables_not_in_loop_body,
|
|
|
|
Second->getLocStart()))
|
2012-05-01 02:01:30 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body);
|
2017-06-02 12:24:46 +08:00
|
|
|
DeclSetVector Decls;
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVector<SourceRange, 10> Ranges;
|
2012-06-07 01:32:50 +08:00
|
|
|
DeclExtractor DE(S, Decls, Ranges);
|
2012-05-01 02:01:30 +08:00
|
|
|
DE.Visit(Second);
|
|
|
|
|
|
|
|
// Don't analyze complex conditionals.
|
|
|
|
if (!DE.isSimple()) return;
|
|
|
|
|
|
|
|
// No decls found.
|
|
|
|
if (Decls.size() == 0) return;
|
|
|
|
|
2012-05-04 11:01:54 +08:00
|
|
|
// Don't warn on volatile, static, or global variables.
|
2017-06-02 12:24:46 +08:00
|
|
|
for (auto *VD : Decls)
|
|
|
|
if (VD->getType().isVolatileQualified() || VD->hasGlobalStorage())
|
|
|
|
return;
|
2012-05-01 02:01:30 +08:00
|
|
|
|
|
|
|
if (DeclMatcher(S, Decls, Second).FoundDeclInUse() ||
|
|
|
|
DeclMatcher(S, Decls, Third).FoundDeclInUse() ||
|
|
|
|
DeclMatcher(S, Decls, Body).FoundDeclInUse())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Load decl names into diagnostic.
|
2017-06-02 12:24:46 +08:00
|
|
|
if (Decls.size() > 4) {
|
2012-05-01 02:01:30 +08:00
|
|
|
PDiag << 0;
|
2017-06-02 12:24:46 +08:00
|
|
|
} else {
|
|
|
|
PDiag << (unsigned)Decls.size();
|
|
|
|
for (auto *VD : Decls)
|
|
|
|
PDiag << VD->getDeclName();
|
2012-05-01 02:01:30 +08:00
|
|
|
}
|
|
|
|
|
2017-06-02 12:24:46 +08:00
|
|
|
for (auto Range : Ranges)
|
|
|
|
PDiag << Range;
|
2012-05-01 02:01:30 +08:00
|
|
|
|
|
|
|
S.Diag(Ranges.begin()->getBegin(), PDiag);
|
|
|
|
}
|
|
|
|
|
2013-08-07 05:31:54 +08:00
|
|
|
// If Statement is an incemement or decrement, return true and sets the
|
|
|
|
// variables Increment and DRE.
|
|
|
|
bool ProcessIterationStmt(Sema &S, Stmt* Statement, bool &Increment,
|
|
|
|
DeclRefExpr *&DRE) {
|
2016-06-22 04:29:17 +08:00
|
|
|
if (auto Cleanups = dyn_cast<ExprWithCleanups>(Statement))
|
|
|
|
if (!Cleanups->cleanupsHaveSideEffects())
|
|
|
|
Statement = Cleanups->getSubExpr();
|
|
|
|
|
2013-08-07 05:31:54 +08:00
|
|
|
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(Statement)) {
|
|
|
|
switch (UO->getOpcode()) {
|
|
|
|
default: return false;
|
|
|
|
case UO_PostInc:
|
|
|
|
case UO_PreInc:
|
|
|
|
Increment = true;
|
|
|
|
break;
|
|
|
|
case UO_PostDec:
|
|
|
|
case UO_PreDec:
|
|
|
|
Increment = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr());
|
|
|
|
return DRE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(Statement)) {
|
|
|
|
FunctionDecl *FD = Call->getDirectCallee();
|
|
|
|
if (!FD || !FD->isOverloadedOperator()) return false;
|
|
|
|
switch (FD->getOverloadedOperator()) {
|
|
|
|
default: return false;
|
|
|
|
case OO_PlusPlus:
|
|
|
|
Increment = true;
|
|
|
|
break;
|
|
|
|
case OO_MinusMinus:
|
|
|
|
Increment = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
DRE = dyn_cast<DeclRefExpr>(Call->getArg(0));
|
|
|
|
return DRE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-23 23:05:00 +08:00
|
|
|
// A visitor to determine if a continue or break statement is a
|
|
|
|
// subexpression.
|
2017-07-04 08:52:24 +08:00
|
|
|
class BreakContinueFinder : public ConstEvaluatedExprVisitor<BreakContinueFinder> {
|
2014-01-23 23:05:00 +08:00
|
|
|
SourceLocation BreakLoc;
|
|
|
|
SourceLocation ContinueLoc;
|
2017-07-04 08:52:24 +08:00
|
|
|
bool InSwitch = false;
|
|
|
|
|
2013-08-07 05:31:54 +08:00
|
|
|
public:
|
2017-07-04 08:52:24 +08:00
|
|
|
BreakContinueFinder(Sema &S, const Stmt* Body) :
|
2014-01-23 23:05:00 +08:00
|
|
|
Inherited(S.Context) {
|
2013-08-07 05:31:54 +08:00
|
|
|
Visit(Body);
|
|
|
|
}
|
|
|
|
|
2017-07-04 08:52:24 +08:00
|
|
|
typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited;
|
2013-08-07 05:31:54 +08:00
|
|
|
|
2017-07-04 08:52:24 +08:00
|
|
|
void VisitContinueStmt(const ContinueStmt* E) {
|
2014-01-23 23:05:00 +08:00
|
|
|
ContinueLoc = E->getContinueLoc();
|
|
|
|
}
|
|
|
|
|
2017-07-04 08:52:24 +08:00
|
|
|
void VisitBreakStmt(const BreakStmt* E) {
|
|
|
|
if (!InSwitch)
|
|
|
|
BreakLoc = E->getBreakLoc();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitSwitchStmt(const SwitchStmt* S) {
|
|
|
|
if (const Stmt *Init = S->getInit())
|
|
|
|
Visit(Init);
|
|
|
|
if (const Stmt *CondVar = S->getConditionVariableDeclStmt())
|
|
|
|
Visit(CondVar);
|
|
|
|
if (const Stmt *Cond = S->getCond())
|
|
|
|
Visit(Cond);
|
|
|
|
|
|
|
|
// Don't return break statements from the body of a switch.
|
|
|
|
InSwitch = true;
|
|
|
|
if (const Stmt *Body = S->getBody())
|
|
|
|
Visit(Body);
|
|
|
|
InSwitch = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitForStmt(const ForStmt *S) {
|
|
|
|
// Only visit the init statement of a for loop; the body
|
|
|
|
// has a different break/continue scope.
|
|
|
|
if (const Stmt *Init = S->getInit())
|
|
|
|
Visit(Init);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitWhileStmt(const WhileStmt *) {
|
|
|
|
// Do nothing; the children of a while loop have a different
|
|
|
|
// break/continue scope.
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitDoStmt(const DoStmt *) {
|
|
|
|
// Do nothing; the children of a while loop have a different
|
|
|
|
// break/continue scope.
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
|
|
|
|
// Only visit the initialization of a for loop; the body
|
|
|
|
// has a different break/continue scope.
|
|
|
|
if (const Stmt *Range = S->getRangeStmt())
|
|
|
|
Visit(Range);
|
|
|
|
if (const Stmt *Begin = S->getBeginStmt())
|
|
|
|
Visit(Begin);
|
|
|
|
if (const Stmt *End = S->getEndStmt())
|
|
|
|
Visit(End);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
|
|
|
|
// Only visit the initialization of a for loop; the body
|
|
|
|
// has a different break/continue scope.
|
|
|
|
if (const Stmt *Element = S->getElement())
|
|
|
|
Visit(Element);
|
|
|
|
if (const Stmt *Collection = S->getCollection())
|
|
|
|
Visit(Collection);
|
2013-08-07 05:31:54 +08:00
|
|
|
}
|
|
|
|
|
2014-01-23 23:05:00 +08:00
|
|
|
bool ContinueFound() { return ContinueLoc.isValid(); }
|
|
|
|
bool BreakFound() { return BreakLoc.isValid(); }
|
|
|
|
SourceLocation GetContinueLoc() { return ContinueLoc; }
|
|
|
|
SourceLocation GetBreakLoc() { return BreakLoc; }
|
2013-08-07 05:31:54 +08:00
|
|
|
|
2014-01-23 23:05:00 +08:00
|
|
|
}; // end class BreakContinueFinder
|
2013-08-07 05:31:54 +08:00
|
|
|
|
|
|
|
// Emit a warning when a loop increment/decrement appears twice per loop
|
|
|
|
// iteration. The conditions which trigger this warning are:
|
|
|
|
// 1) The last statement in the loop body and the third expression in the
|
|
|
|
// for loop are both increment or both decrement of the same variable
|
|
|
|
// 2) No continue statements in the loop body.
|
|
|
|
void CheckForRedundantIteration(Sema &S, Expr *Third, Stmt *Body) {
|
|
|
|
// Return when there is nothing to check.
|
|
|
|
if (!Body || !Third) return;
|
|
|
|
|
2014-06-16 07:30:39 +08:00
|
|
|
if (S.Diags.isIgnored(diag::warn_redundant_loop_iteration,
|
|
|
|
Third->getLocStart()))
|
2013-08-07 05:31:54 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Get the last statement from the loop body.
|
|
|
|
CompoundStmt *CS = dyn_cast<CompoundStmt>(Body);
|
|
|
|
if (!CS || CS->body_empty()) return;
|
|
|
|
Stmt *LastStmt = CS->body_back();
|
|
|
|
if (!LastStmt) return;
|
|
|
|
|
|
|
|
bool LoopIncrement, LastIncrement;
|
|
|
|
DeclRefExpr *LoopDRE, *LastDRE;
|
|
|
|
|
|
|
|
if (!ProcessIterationStmt(S, Third, LoopIncrement, LoopDRE)) return;
|
|
|
|
if (!ProcessIterationStmt(S, LastStmt, LastIncrement, LastDRE)) return;
|
|
|
|
|
|
|
|
// Check that the two statements are both increments or both decrements
|
2014-01-23 23:05:00 +08:00
|
|
|
// on the same variable.
|
2013-08-07 05:31:54 +08:00
|
|
|
if (LoopIncrement != LastIncrement ||
|
|
|
|
LoopDRE->getDecl() != LastDRE->getDecl()) return;
|
|
|
|
|
2014-01-23 23:05:00 +08:00
|
|
|
if (BreakContinueFinder(S, Body).ContinueFound()) return;
|
2013-08-07 05:31:54 +08:00
|
|
|
|
|
|
|
S.Diag(LastDRE->getLocation(), diag::warn_redundant_loop_iteration)
|
|
|
|
<< LastDRE->getDecl() << LastIncrement;
|
|
|
|
S.Diag(LoopDRE->getLocation(), diag::note_loop_iteration_here)
|
|
|
|
<< LoopIncrement;
|
|
|
|
}
|
|
|
|
|
2012-05-01 02:01:30 +08:00
|
|
|
} // end namespace
|
|
|
|
|
2014-01-23 23:05:00 +08:00
|
|
|
|
|
|
|
void Sema::CheckBreakContinueBinding(Expr *E) {
|
|
|
|
if (!E || getLangOpts().CPlusPlus)
|
|
|
|
return;
|
|
|
|
BreakContinueFinder BCFinder(*this, E);
|
|
|
|
Scope *BreakParent = CurScope->getBreakParent();
|
|
|
|
if (BCFinder.BreakFound() && BreakParent) {
|
|
|
|
if (BreakParent->getFlags() & Scope::SwitchScope) {
|
|
|
|
Diag(BCFinder.GetBreakLoc(), diag::warn_break_binds_to_switch);
|
|
|
|
} else {
|
|
|
|
Diag(BCFinder.GetBreakLoc(), diag::warn_loop_ctrl_binds_to_inner)
|
|
|
|
<< "break";
|
|
|
|
}
|
|
|
|
} else if (BCFinder.ContinueFound() && CurScope->getContinueParent()) {
|
|
|
|
Diag(BCFinder.GetContinueLoc(), diag::warn_loop_ctrl_binds_to_inner)
|
|
|
|
<< "continue";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
|
|
|
|
Stmt *First, ConditionResult Second,
|
|
|
|
FullExprArg third, SourceLocation RParenLoc,
|
|
|
|
Stmt *Body) {
|
|
|
|
if (Second.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().CPlusPlus) {
|
2008-09-10 10:17:11 +08:00
|
|
|
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
|
2008-11-20 14:38:18 +08:00
|
|
|
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
|
|
|
|
// declare identifiers for objects having storage class 'auto' or
|
|
|
|
// 'register'.
|
2014-03-15 01:01:24 +08:00
|
|
|
for (auto *DI : DS->decls()) {
|
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(DI);
|
2010-10-15 12:57:14 +08:00
|
|
|
if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage())
|
2014-05-26 14:22:03 +08:00
|
|
|
VD = nullptr;
|
|
|
|
if (!VD) {
|
2014-03-15 01:01:24 +08:00
|
|
|
Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
|
|
|
|
DI->setInvalidDecl();
|
2013-04-09 04:52:24 +08:00
|
|
|
}
|
2008-09-10 10:17:11 +08:00
|
|
|
}
|
2007-08-28 13:03:08 +08:00
|
|
|
}
|
2007-05-29 10:14:17 +08:00
|
|
|
}
|
2009-11-25 08:27:52 +08:00
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
CheckBreakContinueBinding(Second.get().second);
|
2014-01-23 23:05:00 +08:00
|
|
|
CheckBreakContinueBinding(third.get());
|
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
if (!Second.get().first)
|
|
|
|
CheckForLoopConditionalStatement(*this, Second.get().second, third.get(),
|
|
|
|
Body);
|
2013-08-07 05:31:54 +08:00
|
|
|
CheckForRedundantIteration(*this, third.get(), Body);
|
2012-05-01 02:01:30 +08:00
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
if (Second.get().second &&
|
2016-02-19 07:58:40 +08:00
|
|
|
!Diags.isIgnored(diag::warn_comma_operator,
|
2016-06-24 03:02:52 +08:00
|
|
|
Second.get().second->getExprLoc()))
|
|
|
|
CommaVisitor(*this).Visit(Second.get().second);
|
2016-02-19 07:58:40 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
Expr *Third = third.release().getAs<Expr>();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2009-08-01 09:39:59 +08:00
|
|
|
DiagnoseUnusedExprResult(First);
|
|
|
|
DiagnoseUnusedExprResult(Third);
|
2009-07-31 06:39:03 +08:00
|
|
|
DiagnoseUnusedExprResult(Body);
|
|
|
|
|
2012-02-15 06:14:32 +08:00
|
|
|
if (isa<NullStmt>(Body))
|
|
|
|
getCurCompoundScope().setHasEmptyLoopBodies();
|
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
return new (Context)
|
|
|
|
ForStmt(Context, First, Second.get().second, Second.get().first, Third,
|
|
|
|
Body, ForLoc, LParenLoc, RParenLoc);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2010-12-04 11:47:34 +08:00
|
|
|
/// In an Objective C collection iteration statement:
|
|
|
|
/// for (x in y)
|
|
|
|
/// x can be an arbitrary l-value expression. Bind it up as a
|
|
|
|
/// full-expression.
|
|
|
|
StmtResult Sema::ActOnForEachLValueExpr(Expr *E) {
|
2012-03-30 13:43:39 +08:00
|
|
|
// Reduce placeholder expressions here. Note that this rejects the
|
|
|
|
// use of pseudo-object l-values in this position.
|
|
|
|
ExprResult result = CheckPlaceholderExpr(E);
|
|
|
|
if (result.isInvalid()) return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
E = result.get();
|
2012-03-30 13:43:39 +08:00
|
|
|
|
2013-01-15 06:39:08 +08:00
|
|
|
ExprResult FullExpr = ActOnFinishFullExpr(E);
|
|
|
|
if (FullExpr.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
return StmtResult(static_cast<Stmt*>(FullExpr.get()));
|
2010-12-04 11:47:34 +08:00
|
|
|
}
|
|
|
|
|
2011-07-27 09:07:15 +08:00
|
|
|
ExprResult
|
2012-07-04 06:00:52 +08:00
|
|
|
Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
|
|
|
|
if (!collection)
|
|
|
|
return ExprError();
|
2012-08-11 01:56:09 +08:00
|
|
|
|
2014-11-22 02:48:04 +08:00
|
|
|
ExprResult result = CorrectDelayedTyposInExpr(collection);
|
|
|
|
if (!result.isUsable())
|
|
|
|
return ExprError();
|
|
|
|
collection = result.get();
|
|
|
|
|
2011-07-27 09:07:15 +08:00
|
|
|
// Bail out early if we've got a type-dependent expression.
|
2014-05-29 22:05:12 +08:00
|
|
|
if (collection->isTypeDependent()) return collection;
|
2011-07-27 09:07:15 +08:00
|
|
|
|
|
|
|
// Perform normal l-value conversion.
|
2014-11-22 02:48:04 +08:00
|
|
|
result = DefaultFunctionArrayLvalueConversion(collection);
|
2011-07-27 09:07:15 +08:00
|
|
|
if (result.isInvalid())
|
|
|
|
return ExprError();
|
2014-05-29 18:55:11 +08:00
|
|
|
collection = result.get();
|
2011-07-27 09:07:15 +08:00
|
|
|
|
|
|
|
// The operand needs to have object-pointer type.
|
|
|
|
// TODO: should we do a contextual conversion?
|
|
|
|
const ObjCObjectPointerType *pointerType =
|
|
|
|
collection->getType()->getAs<ObjCObjectPointerType>();
|
|
|
|
if (!pointerType)
|
|
|
|
return Diag(forLoc, diag::err_collection_expr_type)
|
|
|
|
<< collection->getType() << collection->getSourceRange();
|
|
|
|
|
|
|
|
// Check that the operand provides
|
|
|
|
// - countByEnumeratingWithState:objects:count:
|
|
|
|
const ObjCObjectType *objectType = pointerType->getObjectType();
|
|
|
|
ObjCInterfaceDecl *iface = objectType->getInterface();
|
|
|
|
|
|
|
|
// If we have a forward-declared type, we can't do this check.
|
2011-11-15 06:10:01 +08:00
|
|
|
// Under ARC, it is an error not to have a forward-declared class.
|
2012-08-11 01:56:09 +08:00
|
|
|
if (iface &&
|
2015-12-19 06:40:25 +08:00
|
|
|
(getLangOpts().ObjCAutoRefCount
|
|
|
|
? RequireCompleteType(forLoc, QualType(objectType, 0),
|
|
|
|
diag::err_arc_collection_forward, collection)
|
|
|
|
: !isCompleteType(forLoc, QualType(objectType, 0)))) {
|
2011-07-27 09:07:15 +08:00
|
|
|
// Otherwise, if we have any useful type information, check that
|
|
|
|
// the type declares the appropriate method.
|
|
|
|
} else if (iface || !objectType->qual_empty()) {
|
|
|
|
IdentifierInfo *selectorIdents[] = {
|
|
|
|
&Context.Idents.get("countByEnumeratingWithState"),
|
|
|
|
&Context.Idents.get("objects"),
|
|
|
|
&Context.Idents.get("count")
|
|
|
|
};
|
|
|
|
Selector selector = Context.Selectors.getSelector(3, &selectorIdents[0]);
|
|
|
|
|
2014-05-26 14:22:03 +08:00
|
|
|
ObjCMethodDecl *method = nullptr;
|
2011-07-27 09:07:15 +08:00
|
|
|
|
|
|
|
// If there's an interface, look in both the public and private APIs.
|
|
|
|
if (iface) {
|
|
|
|
method = iface->lookupInstanceMethod(selector);
|
2012-07-28 03:07:44 +08:00
|
|
|
if (!method) method = iface->lookupPrivateMethod(selector);
|
2011-07-27 09:07:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Also check protocol qualifiers.
|
|
|
|
if (!method)
|
|
|
|
method = LookupMethodInQualifiedType(selector, pointerType,
|
|
|
|
/*instance*/ true);
|
|
|
|
|
|
|
|
// If we didn't find it anywhere, give up.
|
|
|
|
if (!method) {
|
|
|
|
Diag(forLoc, diag::warn_collection_expr_type)
|
|
|
|
<< collection->getType() << selector << collection->getSourceRange();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: check for an incompatible signature?
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrap up any cleanups in the expression.
|
2014-05-29 22:05:12 +08:00
|
|
|
return collection;
|
2011-07-27 09:07:15 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2009-01-17 07:28:06 +08:00
|
|
|
Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
|
2012-07-04 06:00:52 +08:00
|
|
|
Stmt *First, Expr *collection,
|
|
|
|
SourceLocation RParenLoc) {
|
2017-04-20 01:54:08 +08:00
|
|
|
getCurFunction()->setHasBranchProtectedScope();
|
2012-08-11 01:56:09 +08:00
|
|
|
|
|
|
|
ExprResult CollectionExprResult =
|
2012-07-04 06:00:52 +08:00
|
|
|
CheckObjCForCollectionOperand(ForLoc, collection);
|
2012-08-11 01:56:09 +08:00
|
|
|
|
2008-01-11 04:33:58 +08:00
|
|
|
if (First) {
|
|
|
|
QualType FirstType;
|
|
|
|
if (DeclStmt *DS = dyn_cast<DeclStmt>(First)) {
|
2009-03-28 14:33:19 +08:00
|
|
|
if (!DS->isSingleDecl())
|
2009-01-17 07:28:06 +08:00
|
|
|
return StmtError(Diag((*DS->decl_begin())->getLocation(),
|
|
|
|
diag::err_toomany_element_decls));
|
|
|
|
|
2013-04-09 04:52:24 +08:00
|
|
|
VarDecl *D = dyn_cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
if (!D || D->isInvalidDecl())
|
|
|
|
return StmtError();
|
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
FirstType = D->getType();
|
2008-11-20 14:38:18 +08:00
|
|
|
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
|
|
|
|
// declare identifiers for objects having storage class 'auto' or
|
|
|
|
// 'register'.
|
2011-06-16 07:02:42 +08:00
|
|
|
if (!D->hasLocalStorage())
|
|
|
|
return StmtError(Diag(D->getLocation(),
|
2013-04-09 04:52:24 +08:00
|
|
|
diag::err_non_local_variable_decl_in_for));
|
2013-04-09 02:25:02 +08:00
|
|
|
|
|
|
|
// If the type contained 'auto', deduce the 'auto' to 'id'.
|
|
|
|
if (FirstType->getContainedAutoType()) {
|
|
|
|
OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(),
|
|
|
|
VK_RValue);
|
|
|
|
Expr *DeducedInit = &OpaqueId;
|
2013-05-01 05:23:01 +08:00
|
|
|
if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) ==
|
|
|
|
DAR_Failed)
|
2013-04-09 02:25:02 +08:00
|
|
|
DiagnoseAutoDeductionFailure(D, DeducedInit);
|
2013-05-01 05:23:01 +08:00
|
|
|
if (FirstType.isNull()) {
|
2013-04-09 02:25:02 +08:00
|
|
|
D->setInvalidDecl();
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2013-05-01 05:23:01 +08:00
|
|
|
D->setType(FirstType);
|
2013-04-09 02:25:02 +08:00
|
|
|
|
2017-02-21 09:17:38 +08:00
|
|
|
if (!inTemplateInstantiation()) {
|
2013-05-01 05:23:01 +08:00
|
|
|
SourceLocation Loc =
|
|
|
|
D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
|
2013-04-09 02:25:02 +08:00
|
|
|
Diag(Loc, diag::warn_auto_var_is_id)
|
|
|
|
<< D->getDeclName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-26 02:16:36 +08:00
|
|
|
} else {
|
2010-04-23 07:10:45 +08:00
|
|
|
Expr *FirstE = cast<Expr>(First);
|
2010-11-24 13:12:34 +08:00
|
|
|
if (!FirstE->isTypeDependent() && !FirstE->isLValue())
|
2009-01-17 07:28:06 +08:00
|
|
|
return StmtError(Diag(First->getLocStart(),
|
|
|
|
diag::err_selector_element_not_lvalue)
|
|
|
|
<< First->getSourceRange());
|
2008-08-26 02:16:36 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
FirstType = static_cast<Expr*>(First)->getType();
|
2013-10-11 05:58:04 +08:00
|
|
|
if (FirstType.isConstQualified())
|
|
|
|
Diag(ForLoc, diag::err_selector_element_const_type)
|
|
|
|
<< FirstType << First->getSourceRange();
|
2008-08-26 02:16:36 +08:00
|
|
|
}
|
2010-04-23 07:10:45 +08:00
|
|
|
if (!FirstType->isDependentType() &&
|
|
|
|
!FirstType->isObjCObjectPointerType() &&
|
2009-08-15 05:53:27 +08:00
|
|
|
!FirstType->isBlockPointerType())
|
2012-07-04 06:00:52 +08:00
|
|
|
return StmtError(Diag(ForLoc, diag::err_selector_element_type)
|
|
|
|
<< FirstType << First->getSourceRange());
|
2008-01-04 01:55:25 +08:00
|
|
|
}
|
2012-08-11 01:56:09 +08:00
|
|
|
|
2013-01-15 06:39:08 +08:00
|
|
|
if (CollectionExprResult.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
CollectionExprResult = ActOnFinishFullExpr(CollectionExprResult.get());
|
2012-07-04 06:00:52 +08:00
|
|
|
if (CollectionExprResult.isInvalid())
|
|
|
|
return StmtError();
|
2012-08-11 01:56:09 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) ObjCForCollectionStmt(First, CollectionExprResult.get(),
|
|
|
|
nullptr, ForLoc, RParenLoc);
|
2008-01-04 01:55:25 +08:00
|
|
|
}
|
2006-11-10 13:07:45 +08:00
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
/// Finish building a variable declaration for a for-range statement.
|
|
|
|
/// \return true if an error occurs.
|
|
|
|
static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
|
2013-05-01 05:23:01 +08:00
|
|
|
SourceLocation Loc, int DiagID) {
|
2015-05-07 08:11:02 +08:00
|
|
|
if (Decl->getType()->isUndeducedType()) {
|
|
|
|
ExprResult Res = SemaRef.CorrectDelayedTyposInExpr(Init);
|
|
|
|
if (!Res.isUsable()) {
|
|
|
|
Decl->setInvalidDecl();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Init = Res.get();
|
|
|
|
}
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
// Deduce the type for the iterator variable now rather than leaving it to
|
|
|
|
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
|
2013-05-01 05:23:01 +08:00
|
|
|
QualType InitType;
|
2012-01-18 06:50:08 +08:00
|
|
|
if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
|
2013-05-01 05:23:01 +08:00
|
|
|
SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) ==
|
2012-01-24 06:09:39 +08:00
|
|
|
Sema::DAR_Failed)
|
2013-05-01 05:23:01 +08:00
|
|
|
SemaRef.Diag(Loc, DiagID) << Init->getType();
|
|
|
|
if (InitType.isNull()) {
|
2011-04-15 06:09:26 +08:00
|
|
|
Decl->setInvalidDecl();
|
|
|
|
return true;
|
|
|
|
}
|
2013-05-01 05:23:01 +08:00
|
|
|
Decl->setType(InitType);
|
2011-04-15 06:09:26 +08:00
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
// In ARC, infer lifetime.
|
|
|
|
// FIXME: ARC may want to turn this into 'const __unsafe_unretained' if
|
|
|
|
// we're doing the equivalent of fast iteration.
|
2012-08-11 01:56:09 +08:00
|
|
|
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
|
2011-06-16 07:02:42 +08:00
|
|
|
SemaRef.inferObjCARCLifetime(Decl))
|
|
|
|
Decl->setInvalidDecl();
|
|
|
|
|
2017-01-12 10:27:38 +08:00
|
|
|
SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false);
|
2011-04-15 06:09:26 +08:00
|
|
|
SemaRef.FinalizeDeclaration(Decl);
|
2011-04-18 23:49:25 +08:00
|
|
|
SemaRef.CurContext->addHiddenDecl(Decl);
|
2011-04-15 06:09:26 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-08-21 08:52:01 +08:00
|
|
|
namespace {
|
2015-10-27 14:02:45 +08:00
|
|
|
// An enum to represent whether something is dealing with a call to begin()
|
|
|
|
// or a call to end() in a range-based for loop.
|
|
|
|
enum BeginEndFunction {
|
|
|
|
BEF_begin,
|
|
|
|
BEF_end
|
|
|
|
};
|
2012-08-21 08:52:01 +08:00
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
/// Produce a note indicating which begin/end function was implicitly called
|
2012-08-21 08:52:01 +08:00
|
|
|
/// by a C++11 for-range statement. This is often not obvious from the code,
|
2011-04-15 06:09:26 +08:00
|
|
|
/// nor from the diagnostics produced when analysing the implicit expressions
|
|
|
|
/// required in a for-range statement.
|
|
|
|
void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
|
2015-10-27 14:02:45 +08:00
|
|
|
BeginEndFunction BEF) {
|
2011-04-15 06:09:26 +08:00
|
|
|
CallExpr *CE = dyn_cast<CallExpr>(E);
|
|
|
|
if (!CE)
|
|
|
|
return;
|
|
|
|
FunctionDecl *D = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
|
|
|
|
if (!D)
|
|
|
|
return;
|
|
|
|
SourceLocation Loc = D->getLocation();
|
|
|
|
|
|
|
|
std::string Description;
|
|
|
|
bool IsTemplate = false;
|
|
|
|
if (FunctionTemplateDecl *FunTmpl = D->getPrimaryTemplate()) {
|
|
|
|
Description = SemaRef.getTemplateArgumentBindingsText(
|
|
|
|
FunTmpl->getTemplateParameters(), *D->getTemplateSpecializationArgs());
|
|
|
|
IsTemplate = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SemaRef.Diag(Loc, diag::note_for_range_begin_end)
|
|
|
|
<< BEF << IsTemplate << Description << E->getType();
|
|
|
|
}
|
|
|
|
|
2012-08-21 08:52:01 +08:00
|
|
|
/// Build a variable declaration for a for-range statement.
|
|
|
|
VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
|
|
|
|
QualType Type, const char *Name) {
|
|
|
|
DeclContext *DC = SemaRef.CurContext;
|
|
|
|
IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
|
|
|
|
TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
|
|
|
|
VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type,
|
2013-04-04 03:27:57 +08:00
|
|
|
TInfo, SC_None);
|
2012-08-21 08:52:01 +08:00
|
|
|
Decl->setImplicit();
|
|
|
|
return Decl;
|
2011-04-15 06:09:26 +08:00
|
|
|
}
|
|
|
|
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2011-04-15 06:09:26 +08:00
|
|
|
|
2012-07-07 03:04:04 +08:00
|
|
|
static bool ObjCEnumerationCollection(Expr *Collection) {
|
|
|
|
return !Collection->isTypeDependent()
|
2014-05-26 14:22:03 +08:00
|
|
|
&& Collection->getType()->getAs<ObjCObjectPointerType>() != nullptr;
|
2012-07-07 03:04:04 +08:00
|
|
|
}
|
|
|
|
|
2012-08-17 05:47:25 +08:00
|
|
|
/// ActOnCXXForRangeStmt - Check and build a C++11 for-range statement.
|
2011-04-15 06:09:26 +08:00
|
|
|
///
|
2012-08-17 05:47:25 +08:00
|
|
|
/// C++11 [stmt.ranged]:
|
2011-04-15 06:09:26 +08:00
|
|
|
/// A range-based for statement is equivalent to
|
|
|
|
///
|
|
|
|
/// {
|
|
|
|
/// auto && __range = range-init;
|
|
|
|
/// for ( auto __begin = begin-expr,
|
|
|
|
/// __end = end-expr;
|
|
|
|
/// __begin != __end;
|
|
|
|
/// ++__begin ) {
|
|
|
|
/// for-range-declaration = *__begin;
|
|
|
|
/// statement
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// The body of the loop is not available yet, since it cannot be analysed until
|
|
|
|
/// we have determined the type of the for-range-declaration.
|
2015-10-27 14:02:45 +08:00
|
|
|
StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
|
|
|
|
SourceLocation CoawaitLoc, Stmt *First,
|
|
|
|
SourceLocation ColonLoc, Expr *Range,
|
|
|
|
SourceLocation RParenLoc,
|
|
|
|
BuildForRangeKind Kind) {
|
2013-08-21 09:40:36 +08:00
|
|
|
if (!First)
|
2011-04-15 06:09:26 +08:00
|
|
|
return StmtError();
|
2012-08-11 01:56:09 +08:00
|
|
|
|
2013-08-21 09:40:36 +08:00
|
|
|
if (Range && ObjCEnumerationCollection(Range))
|
2012-08-17 05:47:25 +08:00
|
|
|
return ActOnObjCForCollectionStmt(ForLoc, First, Range, RParenLoc);
|
2011-04-15 06:09:26 +08:00
|
|
|
|
|
|
|
DeclStmt *DS = dyn_cast<DeclStmt>(First);
|
|
|
|
assert(DS && "first part of for range not a decl stmt");
|
|
|
|
|
|
|
|
if (!DS->isSingleDecl()) {
|
|
|
|
Diag(DS->getStartLoc(), diag::err_type_defined_in_for_range);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2013-08-21 09:40:36 +08:00
|
|
|
Decl *LoopVar = DS->getSingleDecl();
|
|
|
|
if (LoopVar->isInvalidDecl() || !Range ||
|
|
|
|
DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) {
|
|
|
|
LoopVar->setInvalidDecl();
|
2011-04-15 06:09:26 +08:00
|
|
|
return StmtError();
|
2013-08-21 09:40:36 +08:00
|
|
|
}
|
2011-04-15 06:09:26 +08:00
|
|
|
|
2017-06-14 11:24:55 +08:00
|
|
|
// Build the coroutine state immediately and not later during template
|
|
|
|
// instantiation
|
|
|
|
if (!CoawaitLoc.isInvalid()) {
|
|
|
|
if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await"))
|
|
|
|
return StmtError();
|
2015-10-22 14:13:50 +08:00
|
|
|
}
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
// Build auto && __range = range-init
|
|
|
|
SourceLocation RangeLoc = Range->getLocStart();
|
|
|
|
VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
|
|
|
|
Context.getAutoRRefDeductType(),
|
|
|
|
"__range");
|
|
|
|
if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
|
2013-08-21 09:40:36 +08:00
|
|
|
diag::err_for_range_deduction_failure)) {
|
|
|
|
LoopVar->setInvalidDecl();
|
2011-04-15 06:09:26 +08:00
|
|
|
return StmtError();
|
2013-08-21 09:40:36 +08:00
|
|
|
}
|
2011-04-15 06:09:26 +08:00
|
|
|
|
|
|
|
// Claim the type doesn't contain auto: we've already done the checking.
|
|
|
|
DeclGroupPtrTy RangeGroup =
|
2017-01-12 10:27:38 +08:00
|
|
|
BuildDeclaratorGroup(MutableArrayRef<Decl *>((Decl **)&RangeVar, 1));
|
2011-04-15 06:09:26 +08:00
|
|
|
StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
|
2013-08-21 09:40:36 +08:00
|
|
|
if (RangeDecl.isInvalid()) {
|
|
|
|
LoopVar->setInvalidDecl();
|
2011-04-15 06:09:26 +08:00
|
|
|
return StmtError();
|
2013-08-21 09:40:36 +08:00
|
|
|
}
|
2011-04-15 06:09:26 +08:00
|
|
|
|
2015-10-22 14:13:50 +08:00
|
|
|
return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(),
|
2016-03-20 18:33:40 +08:00
|
|
|
/*BeginStmt=*/nullptr, /*EndStmt=*/nullptr,
|
|
|
|
/*Cond=*/nullptr, /*Inc=*/nullptr,
|
|
|
|
DS, RParenLoc, Kind);
|
2012-08-21 08:52:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Create the initialization, compare, and increment steps for
|
|
|
|
/// the range-based for loop expression.
|
|
|
|
/// This function does not handle array-based for loops,
|
|
|
|
/// which are created in Sema::BuildCXXForRangeStmt.
|
|
|
|
///
|
|
|
|
/// \returns a ForRangeStatus indicating success or what kind of error occurred.
|
|
|
|
/// BeginExpr and EndExpr are set and FRS_Success is returned on success;
|
|
|
|
/// CandidateSet and BEF are set and some non-success value is returned on
|
|
|
|
/// failure.
|
2017-06-14 11:24:55 +08:00
|
|
|
static Sema::ForRangeStatus
|
|
|
|
BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange,
|
|
|
|
QualType RangeType, VarDecl *BeginVar, VarDecl *EndVar,
|
|
|
|
SourceLocation ColonLoc, SourceLocation CoawaitLoc,
|
|
|
|
OverloadCandidateSet *CandidateSet, ExprResult *BeginExpr,
|
|
|
|
ExprResult *EndExpr, BeginEndFunction *BEF) {
|
2012-08-21 08:52:01 +08:00
|
|
|
DeclarationNameInfo BeginNameInfo(
|
|
|
|
&SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
|
|
|
|
DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
|
|
|
|
ColonLoc);
|
|
|
|
|
|
|
|
LookupResult BeginMemberLookup(SemaRef, BeginNameInfo,
|
|
|
|
Sema::LookupMemberName);
|
|
|
|
LookupResult EndMemberLookup(SemaRef, EndNameInfo, Sema::LookupMemberName);
|
|
|
|
|
|
|
|
if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) {
|
|
|
|
// - if _RangeT is a class type, the unqualified-ids begin and end are
|
|
|
|
// looked up in the scope of class _RangeT as if by class member access
|
|
|
|
// lookup (3.4.5), and if either (or both) finds at least one
|
|
|
|
// declaration, begin-expr and end-expr are __range.begin() and
|
|
|
|
// __range.end(), respectively;
|
|
|
|
SemaRef.LookupQualifiedName(BeginMemberLookup, D);
|
|
|
|
SemaRef.LookupQualifiedName(EndMemberLookup, D);
|
|
|
|
|
|
|
|
if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
|
|
|
|
SourceLocation RangeLoc = BeginVar->getLocation();
|
2015-10-27 14:02:45 +08:00
|
|
|
*BEF = BeginMemberLookup.empty() ? BEF_end : BEF_begin;
|
2012-08-21 08:52:01 +08:00
|
|
|
|
|
|
|
SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch)
|
|
|
|
<< RangeLoc << BeginRange->getType() << *BEF;
|
|
|
|
return Sema::FRS_DiagnosticIssued;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// - otherwise, begin-expr and end-expr are begin(__range) and
|
|
|
|
// end(__range), respectively, where begin and end are looked up with
|
|
|
|
// argument-dependent lookup (3.4.2). For the purposes of this name
|
|
|
|
// lookup, namespace std is an associated namespace.
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-10-27 14:02:45 +08:00
|
|
|
*BEF = BEF_begin;
|
2012-08-21 08:52:01 +08:00
|
|
|
Sema::ForRangeStatus RangeStatus =
|
2015-10-27 14:02:45 +08:00
|
|
|
SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, BeginNameInfo,
|
2012-08-21 08:52:01 +08:00
|
|
|
BeginMemberLookup, CandidateSet,
|
|
|
|
BeginRange, BeginExpr);
|
|
|
|
|
2015-10-27 14:02:45 +08:00
|
|
|
if (RangeStatus != Sema::FRS_Success) {
|
|
|
|
if (RangeStatus == Sema::FRS_DiagnosticIssued)
|
|
|
|
SemaRef.Diag(BeginRange->getLocStart(), diag::note_in_for_range)
|
|
|
|
<< ColonLoc << BEF_begin << BeginRange->getType();
|
2012-08-21 08:52:01 +08:00
|
|
|
return RangeStatus;
|
2015-10-27 14:02:45 +08:00
|
|
|
}
|
2017-06-14 11:24:55 +08:00
|
|
|
if (!CoawaitLoc.isInvalid()) {
|
|
|
|
// FIXME: getCurScope() should not be used during template instantiation.
|
|
|
|
// We should pick up the set of unqualified lookup results for operator
|
|
|
|
// co_await during the initial parse.
|
|
|
|
*BeginExpr = SemaRef.ActOnCoawaitExpr(SemaRef.getCurScope(), ColonLoc,
|
|
|
|
BeginExpr->get());
|
|
|
|
if (BeginExpr->isInvalid())
|
|
|
|
return Sema::FRS_DiagnosticIssued;
|
|
|
|
}
|
2012-08-21 08:52:01 +08:00
|
|
|
if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
|
|
|
|
diag::err_for_range_iter_deduction_failure)) {
|
|
|
|
NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
|
|
|
|
return Sema::FRS_DiagnosticIssued;
|
|
|
|
}
|
|
|
|
|
2015-10-27 14:02:45 +08:00
|
|
|
*BEF = BEF_end;
|
2012-08-21 08:52:01 +08:00
|
|
|
RangeStatus =
|
2015-10-27 14:02:45 +08:00
|
|
|
SemaRef.BuildForRangeBeginEndCall(ColonLoc, ColonLoc, EndNameInfo,
|
2012-08-21 08:52:01 +08:00
|
|
|
EndMemberLookup, CandidateSet,
|
|
|
|
EndRange, EndExpr);
|
2015-10-27 14:02:45 +08:00
|
|
|
if (RangeStatus != Sema::FRS_Success) {
|
|
|
|
if (RangeStatus == Sema::FRS_DiagnosticIssued)
|
|
|
|
SemaRef.Diag(EndRange->getLocStart(), diag::note_in_for_range)
|
|
|
|
<< ColonLoc << BEF_end << EndRange->getType();
|
2012-08-21 08:52:01 +08:00
|
|
|
return RangeStatus;
|
2015-10-27 14:02:45 +08:00
|
|
|
}
|
2012-08-21 08:52:01 +08:00
|
|
|
if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc,
|
|
|
|
diag::err_for_range_iter_deduction_failure)) {
|
|
|
|
NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF);
|
|
|
|
return Sema::FRS_DiagnosticIssued;
|
|
|
|
}
|
|
|
|
return Sema::FRS_Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Speculatively attempt to dereference an invalid range expression.
|
2012-09-21 05:52:32 +08:00
|
|
|
/// If the attempt fails, this function will return a valid, null StmtResult
|
|
|
|
/// and emit no diagnostics.
|
2012-08-21 08:52:01 +08:00
|
|
|
static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
|
|
|
|
SourceLocation ForLoc,
|
2015-10-22 14:13:50 +08:00
|
|
|
SourceLocation CoawaitLoc,
|
2012-08-21 08:52:01 +08:00
|
|
|
Stmt *LoopVarDecl,
|
|
|
|
SourceLocation ColonLoc,
|
|
|
|
Expr *Range,
|
|
|
|
SourceLocation RangeLoc,
|
|
|
|
SourceLocation RParenLoc) {
|
2012-09-21 05:52:32 +08:00
|
|
|
// Determine whether we can rebuild the for-range statement with a
|
|
|
|
// dereferenced range expression.
|
|
|
|
ExprResult AdjustedRange;
|
|
|
|
{
|
|
|
|
Sema::SFINAETrap Trap(SemaRef);
|
|
|
|
|
|
|
|
AdjustedRange = SemaRef.BuildUnaryOp(S, RangeLoc, UO_Deref, Range);
|
|
|
|
if (AdjustedRange.isInvalid())
|
|
|
|
return StmtResult();
|
|
|
|
|
2015-10-27 14:02:45 +08:00
|
|
|
StmtResult SR = SemaRef.ActOnCXXForRangeStmt(
|
|
|
|
S, ForLoc, CoawaitLoc, LoopVarDecl, ColonLoc, AdjustedRange.get(),
|
|
|
|
RParenLoc, Sema::BFRK_Check);
|
2012-09-21 05:52:32 +08:00
|
|
|
if (SR.isInvalid())
|
|
|
|
return StmtResult();
|
|
|
|
}
|
|
|
|
|
|
|
|
// The attempt to dereference worked well enough that it could produce a valid
|
|
|
|
// loop. Produce a fixit, and rebuild the loop with diagnostics enabled, in
|
|
|
|
// case there are any other (non-fatal) problems with it.
|
|
|
|
SemaRef.Diag(RangeLoc, diag::err_for_range_dereference)
|
|
|
|
<< Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*");
|
2015-10-27 14:02:45 +08:00
|
|
|
return SemaRef.ActOnCXXForRangeStmt(S, ForLoc, CoawaitLoc, LoopVarDecl,
|
|
|
|
ColonLoc, AdjustedRange.get(), RParenLoc,
|
2012-09-21 05:52:32 +08:00
|
|
|
Sema::BFRK_Rebuild);
|
2011-04-15 06:09:26 +08:00
|
|
|
}
|
|
|
|
|
2013-08-21 09:40:36 +08:00
|
|
|
namespace {
|
|
|
|
/// RAII object to automatically invalidate a declaration if an error occurs.
|
|
|
|
struct InvalidateOnErrorScope {
|
|
|
|
InvalidateOnErrorScope(Sema &SemaRef, Decl *D, bool Enabled)
|
|
|
|
: Trap(SemaRef.Diags), D(D), Enabled(Enabled) {}
|
|
|
|
~InvalidateOnErrorScope() {
|
|
|
|
if (Enabled && Trap.hasErrorOccurred())
|
|
|
|
D->setInvalidDecl();
|
|
|
|
}
|
|
|
|
|
|
|
|
DiagnosticErrorTrap Trap;
|
|
|
|
Decl *D;
|
|
|
|
bool Enabled;
|
|
|
|
};
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2013-08-21 09:40:36 +08:00
|
|
|
|
2012-09-21 05:52:32 +08:00
|
|
|
/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
|
2011-04-15 06:09:26 +08:00
|
|
|
StmtResult
|
2015-10-22 14:13:50 +08:00
|
|
|
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
2016-03-20 18:33:40 +08:00
|
|
|
SourceLocation ColonLoc, Stmt *RangeDecl,
|
|
|
|
Stmt *Begin, Stmt *End, Expr *Cond,
|
2011-04-15 06:09:26 +08:00
|
|
|
Expr *Inc, Stmt *LoopVarDecl,
|
2012-09-21 05:52:32 +08:00
|
|
|
SourceLocation RParenLoc, BuildForRangeKind Kind) {
|
2015-10-27 14:02:45 +08:00
|
|
|
// FIXME: This should not be used during template instantiation. We should
|
|
|
|
// pick up the set of unqualified lookup results for the != and + operators
|
|
|
|
// in the initial parse.
|
|
|
|
//
|
|
|
|
// Testcase (accepts-invalid):
|
|
|
|
// template<typename T> void f() { for (auto x : T()) {} }
|
|
|
|
// namespace N { struct X { X begin(); X end(); int operator*(); }; }
|
|
|
|
// bool operator!=(N::X, N::X); void operator++(N::X);
|
|
|
|
// void g() { f<N::X>(); }
|
2011-04-15 06:09:26 +08:00
|
|
|
Scope *S = getCurScope();
|
|
|
|
|
|
|
|
DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl);
|
|
|
|
VarDecl *RangeVar = cast<VarDecl>(RangeDS->getSingleDecl());
|
|
|
|
QualType RangeVarType = RangeVar->getType();
|
|
|
|
|
|
|
|
DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl);
|
|
|
|
VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl());
|
|
|
|
|
2013-08-21 09:40:36 +08:00
|
|
|
// If we hit any errors, mark the loop variable as invalid if its type
|
|
|
|
// contains 'auto'.
|
|
|
|
InvalidateOnErrorScope Invalidate(*this, LoopVar,
|
|
|
|
LoopVar->getType()->isUndeducedType());
|
|
|
|
|
2016-03-20 18:33:40 +08:00
|
|
|
StmtResult BeginDeclStmt = Begin;
|
|
|
|
StmtResult EndDeclStmt = End;
|
2011-04-15 06:09:26 +08:00
|
|
|
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
|
|
|
|
|
2013-04-30 21:56:41 +08:00
|
|
|
if (RangeVarType->isDependentType()) {
|
|
|
|
// The range is implicitly used as a placeholder when it is dependent.
|
2013-09-05 08:02:25 +08:00
|
|
|
RangeVar->markUsed(Context);
|
2013-04-30 21:56:41 +08:00
|
|
|
|
|
|
|
// Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
|
|
|
|
// them in properly when we instantiate the loop.
|
2017-06-13 00:11:06 +08:00
|
|
|
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
|
|
|
|
if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
|
|
|
|
for (auto *Binding : DD->bindings())
|
|
|
|
Binding->setType(Context.DependentTy);
|
2013-04-30 21:56:41 +08:00
|
|
|
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
|
2017-06-13 00:11:06 +08:00
|
|
|
}
|
2016-03-20 18:33:40 +08:00
|
|
|
} else if (!BeginDeclStmt.get()) {
|
2011-04-15 06:09:26 +08:00
|
|
|
SourceLocation RangeLoc = RangeVar->getLocation();
|
|
|
|
|
2011-10-11 06:36:28 +08:00
|
|
|
const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
|
|
|
|
|
|
|
|
ExprResult BeginRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType,
|
|
|
|
VK_LValue, ColonLoc);
|
|
|
|
if (BeginRangeRef.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
ExprResult EndRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType,
|
|
|
|
VK_LValue, ColonLoc);
|
|
|
|
if (EndRangeRef.isInvalid())
|
2011-04-15 06:09:26 +08:00
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
QualType AutoType = Context.getAutoDeductType();
|
|
|
|
Expr *Range = RangeVar->getInit();
|
|
|
|
if (!Range)
|
|
|
|
return StmtError();
|
|
|
|
QualType RangeType = Range->getType();
|
|
|
|
|
|
|
|
if (RequireCompleteType(RangeLoc, RangeType,
|
2012-05-05 00:32:21 +08:00
|
|
|
diag::err_for_range_incomplete_type))
|
2011-04-15 06:09:26 +08:00
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
// Build auto __begin = begin-expr, __end = end-expr.
|
|
|
|
VarDecl *BeginVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
|
|
|
|
"__begin");
|
|
|
|
VarDecl *EndVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
|
|
|
|
"__end");
|
|
|
|
|
|
|
|
// Build begin-expr and end-expr and attach to __begin and __end variables.
|
|
|
|
ExprResult BeginExpr, EndExpr;
|
|
|
|
if (const ArrayType *UnqAT = RangeType->getAsArrayTypeUnsafe()) {
|
|
|
|
// - if _RangeT is an array type, begin-expr and end-expr are __range and
|
|
|
|
// __range + __bound, respectively, where __bound is the array bound. If
|
|
|
|
// _RangeT is an array of unknown size or an array of incomplete type,
|
|
|
|
// the program is ill-formed;
|
|
|
|
|
|
|
|
// begin-expr is __range.
|
2011-10-11 06:36:28 +08:00
|
|
|
BeginExpr = BeginRangeRef;
|
2017-06-14 11:24:55 +08:00
|
|
|
if (!CoawaitLoc.isInvalid()) {
|
|
|
|
BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
|
|
|
|
if (BeginExpr.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
}
|
2011-10-11 06:36:28 +08:00
|
|
|
if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
|
2011-04-15 06:09:26 +08:00
|
|
|
diag::err_for_range_iter_deduction_failure)) {
|
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the array bound.
|
|
|
|
ExprResult BoundExpr;
|
|
|
|
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
|
2014-05-29 22:05:12 +08:00
|
|
|
BoundExpr = IntegerLiteral::Create(
|
|
|
|
Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc);
|
2011-04-15 06:09:26 +08:00
|
|
|
else if (const VariableArrayType *VAT =
|
2017-05-15 09:49:19 +08:00
|
|
|
dyn_cast<VariableArrayType>(UnqAT)) {
|
|
|
|
// For a variably modified type we can't just use the expression within
|
|
|
|
// the array bounds, since we don't want that to be re-evaluated here.
|
|
|
|
// Rather, we need to determine what it was when the array was first
|
|
|
|
// created - so we resort to using sizeof(vla)/sizeof(element).
|
|
|
|
// For e.g.
|
|
|
|
// void f(int b) {
|
|
|
|
// int vla[b];
|
|
|
|
// b = -1; <-- This should not affect the num of iterations below
|
|
|
|
// for (int &c : vla) { .. }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// FIXME: This results in codegen generating IR that recalculates the
|
|
|
|
// run-time number of elements (as opposed to just using the IR Value
|
|
|
|
// that corresponds to the run-time value of each bound that was
|
|
|
|
// generated when the array was created.) If this proves too embarassing
|
|
|
|
// even for unoptimized IR, consider passing a magic-value/cookie to
|
|
|
|
// codegen that then knows to simply use that initial llvm::Value (that
|
|
|
|
// corresponds to the bound at time of array creation) within
|
|
|
|
// getelementptr. But be prepared to pay the price of increasing a
|
|
|
|
// customized form of coupling between the two components - which could
|
|
|
|
// be hard to maintain as the codebase evolves.
|
|
|
|
|
|
|
|
ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr(
|
|
|
|
EndVar->getLocation(), UETT_SizeOf,
|
|
|
|
/*isType=*/true,
|
|
|
|
CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
|
|
|
|
VAT->desugar(), RangeLoc))
|
|
|
|
.getAsOpaquePtr(),
|
|
|
|
EndVar->getSourceRange());
|
|
|
|
if (SizeOfVLAExprR.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr(
|
|
|
|
EndVar->getLocation(), UETT_SizeOf,
|
|
|
|
/*isType=*/true,
|
|
|
|
CreateParsedType(VAT->desugar(),
|
|
|
|
Context.getTrivialTypeSourceInfo(
|
|
|
|
VAT->getElementType(), RangeLoc))
|
|
|
|
.getAsOpaquePtr(),
|
|
|
|
EndVar->getSourceRange());
|
|
|
|
if (SizeOfEachElementExprR.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
BoundExpr =
|
|
|
|
ActOnBinOp(S, EndVar->getLocation(), tok::slash,
|
|
|
|
SizeOfVLAExprR.get(), SizeOfEachElementExprR.get());
|
|
|
|
if (BoundExpr.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
} else {
|
2011-04-15 06:09:26 +08:00
|
|
|
// Can't be a DependentSizedArrayType or an IncompleteArrayType since
|
|
|
|
// UnqAT is not incomplete and Range is not type-dependent.
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Unexpected array type in for-range");
|
2011-04-15 06:09:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// end-expr is __range + __bound.
|
2011-10-11 06:36:28 +08:00
|
|
|
EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, EndRangeRef.get(),
|
2011-04-15 06:09:26 +08:00
|
|
|
BoundExpr.get());
|
|
|
|
if (EndExpr.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
if (FinishForRangeVarDecl(*this, EndVar, EndExpr.get(), ColonLoc,
|
|
|
|
diag::err_for_range_iter_deduction_failure)) {
|
|
|
|
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
} else {
|
2014-04-17 09:52:14 +08:00
|
|
|
OverloadCandidateSet CandidateSet(RangeLoc,
|
|
|
|
OverloadCandidateSet::CSK_Normal);
|
2015-10-27 14:02:45 +08:00
|
|
|
BeginEndFunction BEFFailure;
|
2017-06-14 11:24:55 +08:00
|
|
|
ForRangeStatus RangeStatus = BuildNonArrayForRange(
|
|
|
|
*this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar,
|
|
|
|
EndVar, ColonLoc, CoawaitLoc, &CandidateSet, &BeginExpr, &EndExpr,
|
|
|
|
&BEFFailure);
|
2012-08-21 08:52:01 +08:00
|
|
|
|
2012-09-21 05:52:32 +08:00
|
|
|
if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
|
2012-08-21 08:52:01 +08:00
|
|
|
BEFFailure == BEF_begin) {
|
2013-10-12 06:16:04 +08:00
|
|
|
// If the range is being built from an array parameter, emit a
|
|
|
|
// a diagnostic that it is being treated as a pointer.
|
|
|
|
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Range)) {
|
|
|
|
if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
|
|
|
|
QualType ArrayTy = PVD->getOriginalType();
|
|
|
|
QualType PointerTy = PVD->getType();
|
|
|
|
if (PointerTy->isPointerType() && ArrayTy->isArrayType()) {
|
|
|
|
Diag(Range->getLocStart(), diag::err_range_on_array_parameter)
|
|
|
|
<< RangeLoc << PVD << ArrayTy << PointerTy;
|
|
|
|
Diag(PVD->getLocation(), diag::note_declared_at);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If building the range failed, try dereferencing the range expression
|
|
|
|
// unless a diagnostic was issued or the end function is problematic.
|
2012-08-21 08:52:01 +08:00
|
|
|
StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc,
|
2015-10-22 14:13:50 +08:00
|
|
|
CoawaitLoc,
|
2012-08-21 08:52:01 +08:00
|
|
|
LoopVarDecl, ColonLoc,
|
|
|
|
Range, RangeLoc,
|
|
|
|
RParenLoc);
|
2012-09-21 05:52:32 +08:00
|
|
|
if (SR.isInvalid() || SR.isUsable())
|
2012-08-21 08:52:01 +08:00
|
|
|
return SR;
|
2011-04-15 06:09:26 +08:00
|
|
|
}
|
|
|
|
|
2012-08-21 08:52:01 +08:00
|
|
|
// Otherwise, emit diagnostics if we haven't already.
|
|
|
|
if (RangeStatus == FRS_NoViableFunction) {
|
2012-09-21 05:52:32 +08:00
|
|
|
Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get();
|
2012-08-21 08:52:01 +08:00
|
|
|
Diag(Range->getLocStart(), diag::err_for_range_invalid)
|
|
|
|
<< RangeLoc << Range->getType() << BEFFailure;
|
2012-12-30 04:03:39 +08:00
|
|
|
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Range);
|
2012-08-21 08:52:01 +08:00
|
|
|
}
|
|
|
|
// Return an error if no fix was discovered.
|
|
|
|
if (RangeStatus != FRS_Success)
|
2011-04-15 06:09:26 +08:00
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2012-08-21 08:52:01 +08:00
|
|
|
assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() &&
|
|
|
|
"invalid range expression in for loop");
|
|
|
|
|
|
|
|
// C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same.
|
2016-03-20 18:33:40 +08:00
|
|
|
// C++1z removes this restriction.
|
2011-04-15 06:09:26 +08:00
|
|
|
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
|
|
|
|
if (!Context.hasSameType(BeginType, EndType)) {
|
2016-03-20 18:33:40 +08:00
|
|
|
Diag(RangeLoc, getLangOpts().CPlusPlus1z
|
|
|
|
? diag::warn_for_range_begin_end_types_differ
|
|
|
|
: diag::ext_for_range_begin_end_types_differ)
|
|
|
|
<< BeginType << EndType;
|
2011-04-15 06:09:26 +08:00
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
|
|
|
|
}
|
|
|
|
|
2016-03-20 18:33:40 +08:00
|
|
|
BeginDeclStmt =
|
|
|
|
ActOnDeclStmt(ConvertDeclToDeclGroup(BeginVar), ColonLoc, ColonLoc);
|
|
|
|
EndDeclStmt =
|
|
|
|
ActOnDeclStmt(ConvertDeclToDeclGroup(EndVar), ColonLoc, ColonLoc);
|
2011-04-15 06:09:26 +08:00
|
|
|
|
2011-10-11 06:36:28 +08:00
|
|
|
const QualType BeginRefNonRefType = BeginType.getNonReferenceType();
|
|
|
|
ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
|
2011-04-15 06:09:26 +08:00
|
|
|
VK_LValue, ColonLoc);
|
2011-10-11 06:36:28 +08:00
|
|
|
if (BeginRef.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
ExprResult EndRef = BuildDeclRefExpr(EndVar, EndType.getNonReferenceType(),
|
|
|
|
VK_LValue, ColonLoc);
|
2011-10-11 06:36:28 +08:00
|
|
|
if (EndRef.isInvalid())
|
|
|
|
return StmtError();
|
2011-04-15 06:09:26 +08:00
|
|
|
|
|
|
|
// Build and check __begin != __end expression.
|
|
|
|
NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal,
|
|
|
|
BeginRef.get(), EndRef.get());
|
2016-06-24 03:02:52 +08:00
|
|
|
if (!NotEqExpr.isInvalid())
|
|
|
|
NotEqExpr = CheckBooleanCondition(ColonLoc, NotEqExpr.get());
|
|
|
|
if (!NotEqExpr.isInvalid())
|
|
|
|
NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get());
|
2011-04-15 06:09:26 +08:00
|
|
|
if (NotEqExpr.isInvalid()) {
|
2012-09-07 05:50:08 +08:00
|
|
|
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
|
|
|
|
<< RangeLoc << 0 << BeginRangeRef.get()->getType();
|
2011-04-15 06:09:26 +08:00
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
if (!Context.hasSameType(BeginType, EndType))
|
|
|
|
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build and check ++__begin expression.
|
2011-10-11 06:36:28 +08:00
|
|
|
BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
|
|
|
|
VK_LValue, ColonLoc);
|
|
|
|
if (BeginRef.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
|
2015-10-22 14:13:50 +08:00
|
|
|
if (!IncrExpr.isInvalid() && CoawaitLoc.isValid())
|
2017-06-14 11:24:55 +08:00
|
|
|
// FIXME: getCurScope() should not be used during template instantiation.
|
|
|
|
// We should pick up the set of unqualified lookup results for operator
|
|
|
|
// co_await during the initial parse.
|
2015-10-27 14:02:45 +08:00
|
|
|
IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get());
|
2015-10-22 14:13:50 +08:00
|
|
|
if (!IncrExpr.isInvalid())
|
|
|
|
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
|
2011-04-15 06:09:26 +08:00
|
|
|
if (IncrExpr.isInvalid()) {
|
2012-09-07 05:50:08 +08:00
|
|
|
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
|
|
|
|
<< RangeLoc << 2 << BeginRangeRef.get()->getType() ;
|
2011-04-15 06:09:26 +08:00
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build and check *__begin expression.
|
2011-10-11 06:36:28 +08:00
|
|
|
BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
|
|
|
|
VK_LValue, ColonLoc);
|
|
|
|
if (BeginRef.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
|
|
|
|
if (DerefExpr.isInvalid()) {
|
2012-09-07 05:50:08 +08:00
|
|
|
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
|
|
|
|
<< RangeLoc << 1 << BeginRangeRef.get()->getType();
|
2011-04-15 06:09:26 +08:00
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
2012-09-21 05:52:32 +08:00
|
|
|
// Attach *__begin as initializer for VD. Don't touch it if we're just
|
|
|
|
// trying to determine whether this would be a valid range.
|
|
|
|
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
|
2017-01-12 10:27:38 +08:00
|
|
|
AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false);
|
2011-04-15 06:09:26 +08:00
|
|
|
if (LoopVar->isInvalidDecl())
|
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-21 05:52:32 +08:00
|
|
|
// Don't bother to actually allocate the result if we're just trying to
|
|
|
|
// determine whether it would be valid.
|
|
|
|
if (Kind == BFRK_Check)
|
|
|
|
return StmtResult();
|
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) CXXForRangeStmt(
|
2016-03-20 18:33:40 +08:00
|
|
|
RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
|
|
|
|
cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),
|
2015-10-27 14:02:45 +08:00
|
|
|
IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc,
|
|
|
|
ColonLoc, RParenLoc);
|
2011-04-15 06:09:26 +08:00
|
|
|
}
|
|
|
|
|
2012-08-11 01:56:09 +08:00
|
|
|
/// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach
|
2012-07-04 06:00:52 +08:00
|
|
|
/// statement.
|
|
|
|
StmtResult Sema::FinishObjCForCollectionStmt(Stmt *S, Stmt *B) {
|
|
|
|
if (!S || !B)
|
|
|
|
return StmtError();
|
|
|
|
ObjCForCollectionStmt * ForStmt = cast<ObjCForCollectionStmt>(S);
|
2012-08-11 01:56:09 +08:00
|
|
|
|
2012-07-04 06:00:52 +08:00
|
|
|
ForStmt->setBody(B);
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2015-04-14 06:08:55 +08:00
|
|
|
// Warn when the loop variable is a const reference that creates a copy.
|
|
|
|
// Suggest using the non-reference type for copies. If a copy can be prevented
|
|
|
|
// suggest the const reference type that would do so.
|
|
|
|
// For instance, given "for (const &Foo : Range)", suggest
|
|
|
|
// "for (const Foo : Range)" to denote a copy is made for the loop. If
|
|
|
|
// possible, also suggest "for (const &Bar : Range)" if this type prevents
|
|
|
|
// the copy altogether.
|
|
|
|
static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
|
|
|
|
const VarDecl *VD,
|
|
|
|
QualType RangeInitType) {
|
|
|
|
const Expr *InitExpr = VD->getInit();
|
|
|
|
if (!InitExpr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QualType VariableType = VD->getType();
|
|
|
|
|
2016-06-22 04:29:17 +08:00
|
|
|
if (auto Cleanups = dyn_cast<ExprWithCleanups>(InitExpr))
|
|
|
|
if (!Cleanups->cleanupsHaveSideEffects())
|
|
|
|
InitExpr = Cleanups->getSubExpr();
|
|
|
|
|
2015-04-14 06:08:55 +08:00
|
|
|
const MaterializeTemporaryExpr *MTE =
|
|
|
|
dyn_cast<MaterializeTemporaryExpr>(InitExpr);
|
|
|
|
|
|
|
|
// No copy made.
|
|
|
|
if (!MTE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const Expr *E = MTE->GetTemporaryExpr()->IgnoreImpCasts();
|
|
|
|
|
|
|
|
// Searching for either UnaryOperator for dereference of a pointer or
|
|
|
|
// CXXOperatorCallExpr for handling iterators.
|
|
|
|
while (!isa<CXXOperatorCallExpr>(E) && !isa<UnaryOperator>(E)) {
|
|
|
|
if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(E)) {
|
|
|
|
E = CCE->getArg(0);
|
|
|
|
} else if (const CXXMemberCallExpr *Call = dyn_cast<CXXMemberCallExpr>(E)) {
|
|
|
|
const MemberExpr *ME = cast<MemberExpr>(Call->getCallee());
|
|
|
|
E = ME->getBase();
|
|
|
|
} else {
|
|
|
|
const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E);
|
|
|
|
E = MTE->GetTemporaryExpr();
|
|
|
|
}
|
|
|
|
E = E->IgnoreImpCasts();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ReturnsReference = false;
|
|
|
|
if (isa<UnaryOperator>(E)) {
|
|
|
|
ReturnsReference = true;
|
|
|
|
} else {
|
|
|
|
const CXXOperatorCallExpr *Call = cast<CXXOperatorCallExpr>(E);
|
|
|
|
const FunctionDecl *FD = Call->getDirectCallee();
|
|
|
|
QualType ReturnType = FD->getReturnType();
|
|
|
|
ReturnsReference = ReturnType->isReferenceType();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ReturnsReference) {
|
|
|
|
// Loop variable creates a temporary. Suggest either to go with
|
|
|
|
// non-reference loop variable to indiciate a copy is made, or
|
|
|
|
// the correct time to bind a const reference.
|
|
|
|
SemaRef.Diag(VD->getLocation(), diag::warn_for_range_const_reference_copy)
|
|
|
|
<< VD << VariableType << E->getType();
|
|
|
|
QualType NonReferenceType = VariableType.getNonReferenceType();
|
|
|
|
NonReferenceType.removeLocalConst();
|
|
|
|
QualType NewReferenceType =
|
|
|
|
SemaRef.Context.getLValueReferenceType(E->getType().withConst());
|
|
|
|
SemaRef.Diag(VD->getLocStart(), diag::note_use_type_or_non_reference)
|
|
|
|
<< NonReferenceType << NewReferenceType << VD->getSourceRange();
|
|
|
|
} else {
|
|
|
|
// The range always returns a copy, so a temporary is always created.
|
|
|
|
// Suggest removing the reference from the loop variable.
|
|
|
|
SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy)
|
|
|
|
<< VD << RangeInitType;
|
|
|
|
QualType NonReferenceType = VariableType.getNonReferenceType();
|
|
|
|
NonReferenceType.removeLocalConst();
|
|
|
|
SemaRef.Diag(VD->getLocStart(), diag::note_use_non_reference_type)
|
|
|
|
<< NonReferenceType << VD->getSourceRange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Warns when the loop variable can be changed to a reference type to
|
|
|
|
// prevent a copy. For instance, if given "for (const Foo x : Range)" suggest
|
|
|
|
// "for (const Foo &x : Range)" if this form does not make a copy.
|
|
|
|
static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
|
|
|
|
const VarDecl *VD) {
|
|
|
|
const Expr *InitExpr = VD->getInit();
|
|
|
|
if (!InitExpr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QualType VariableType = VD->getType();
|
|
|
|
|
|
|
|
if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitExpr)) {
|
|
|
|
if (!CE->getConstructor()->isCopyConstructor())
|
|
|
|
return;
|
|
|
|
} else if (const CastExpr *CE = dyn_cast<CastExpr>(InitExpr)) {
|
|
|
|
if (CE->getCastKind() != CK_LValueToRValue)
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Determine a maximum size that a POD type can be before a diagnostic
|
|
|
|
// should be emitted. Also, only ignore POD types with trivial copy
|
|
|
|
// constructors.
|
|
|
|
if (VariableType.isPODType(SemaRef.Context))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Suggest changing from a const variable to a const reference variable
|
|
|
|
// if doing so will prevent a copy.
|
|
|
|
SemaRef.Diag(VD->getLocation(), diag::warn_for_range_copy)
|
|
|
|
<< VD << VariableType << InitExpr->getType();
|
|
|
|
SemaRef.Diag(VD->getLocStart(), diag::note_use_reference_type)
|
|
|
|
<< SemaRef.Context.getLValueReferenceType(VariableType)
|
|
|
|
<< VD->getSourceRange();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// DiagnoseForRangeVariableCopies - Diagnose three cases and fixes for them.
|
|
|
|
/// 1) for (const foo &x : foos) where foos only returns a copy. Suggest
|
|
|
|
/// using "const foo x" to show that a copy is made
|
|
|
|
/// 2) for (const bar &x : foos) where bar is a temporary intialized by bar.
|
|
|
|
/// Suggest either "const bar x" to keep the copying or "const foo& x" to
|
|
|
|
/// prevent the copy.
|
|
|
|
/// 3) for (const foo x : foos) where x is constructed from a reference foo.
|
|
|
|
/// Suggest "const foo &x" to prevent the copy.
|
|
|
|
static void DiagnoseForRangeVariableCopies(Sema &SemaRef,
|
|
|
|
const CXXForRangeStmt *ForStmt) {
|
|
|
|
if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy,
|
|
|
|
ForStmt->getLocStart()) &&
|
|
|
|
SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy,
|
|
|
|
ForStmt->getLocStart()) &&
|
|
|
|
SemaRef.Diags.isIgnored(diag::warn_for_range_copy,
|
|
|
|
ForStmt->getLocStart())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const VarDecl *VD = ForStmt->getLoopVariable();
|
|
|
|
if (!VD)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QualType VariableType = VD->getType();
|
|
|
|
|
|
|
|
if (VariableType->isIncompleteType())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const Expr *InitExpr = VD->getInit();
|
|
|
|
if (!InitExpr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (VariableType->isReferenceType()) {
|
|
|
|
DiagnoseForRangeReferenceVariableCopies(SemaRef, VD,
|
|
|
|
ForStmt->getRangeInit()->getType());
|
|
|
|
} else if (VariableType.isConstQualified()) {
|
|
|
|
DiagnoseForRangeConstVariableCopies(SemaRef, VD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
/// 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
|
|
|
|
/// determined.
|
|
|
|
StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) {
|
|
|
|
if (!S || !B)
|
|
|
|
return StmtError();
|
|
|
|
|
2012-07-07 03:04:04 +08:00
|
|
|
if (isa<ObjCForCollectionStmt>(S))
|
|
|
|
return FinishObjCForCollectionStmt(S, B);
|
2012-08-11 01:56:09 +08:00
|
|
|
|
2012-02-15 06:14:32 +08:00
|
|
|
CXXForRangeStmt *ForStmt = cast<CXXForRangeStmt>(S);
|
|
|
|
ForStmt->setBody(B);
|
|
|
|
|
|
|
|
DiagnoseEmptyStmtBody(ForStmt->getRParenLoc(), B,
|
|
|
|
diag::warn_empty_range_based_for_body);
|
|
|
|
|
2015-04-14 06:08:55 +08:00
|
|
|
DiagnoseForRangeVariableCopies(*this, ForStmt);
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2011-02-18 04:34:02 +08:00
|
|
|
StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
|
|
|
|
SourceLocation LabelLoc,
|
|
|
|
LabelDecl *TheDecl) {
|
|
|
|
getCurFunction()->setHasBranchIntoScope();
|
2013-09-05 08:02:25 +08:00
|
|
|
TheDecl->markUsed(Context);
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
2007-05-31 14:00:00 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2009-04-19 09:04:21 +08:00
|
|
|
Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
|
2010-08-24 07:25:46 +08:00
|
|
|
Expr *E) {
|
2009-03-26 08:18:06 +08:00
|
|
|
// Convert operand to void*
|
2009-05-16 08:20:29 +08:00
|
|
|
if (!E->isTypeDependent()) {
|
|
|
|
QualType ETy = E->getType();
|
2010-01-31 18:26:25 +08:00
|
|
|
QualType DestTy = Context.getPointerType(Context.VoidTy.withConst());
|
2014-05-29 22:05:12 +08:00
|
|
|
ExprResult ExprRes = E;
|
2009-05-16 08:20:29 +08:00
|
|
|
AssignConvertType ConvTy =
|
2011-04-09 02:41:53 +08:00
|
|
|
CheckSingleAssignmentConstraints(DestTy, ExprRes);
|
|
|
|
if (ExprRes.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
E = ExprRes.get();
|
2010-01-31 18:26:25 +08:00
|
|
|
if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
|
2009-05-16 08:20:29 +08:00
|
|
|
return StmtError();
|
|
|
|
}
|
2010-08-01 08:26:45 +08:00
|
|
|
|
2013-01-15 06:39:08 +08:00
|
|
|
ExprResult ExprRes = ActOnFinishFullExpr(E);
|
|
|
|
if (ExprRes.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
E = ExprRes.get();
|
2013-01-15 06:39:08 +08:00
|
|
|
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->setHasIndirectGoto();
|
2010-08-01 08:26:45 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
static void CheckJumpOutOfSEHFinally(Sema &S, SourceLocation Loc,
|
|
|
|
const Scope &DestScope) {
|
|
|
|
if (!S.CurrentSEHFinally.empty() &&
|
|
|
|
DestScope.Contains(*S.CurrentSEHFinally.back())) {
|
|
|
|
S.Diag(Loc, diag::warn_jump_out_of_seh_finally);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
|
2006-11-10 13:17:58 +08:00
|
|
|
Scope *S = CurScope->getContinueParent();
|
|
|
|
if (!S) {
|
|
|
|
// C99 6.8.6.2p1: A break shall appear only in or as a loop body.
|
2009-01-18 21:19:59 +08:00
|
|
|
return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
|
2006-11-10 13:17:58 +08:00
|
|
|
}
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S);
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) ContinueStmt(ContinueLoc);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
|
2006-11-10 13:17:58 +08:00
|
|
|
Scope *S = CurScope->getBreakParent();
|
|
|
|
if (!S) {
|
|
|
|
// C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
|
2009-01-18 21:19:59 +08:00
|
|
|
return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
|
2006-11-10 13:17:58 +08:00
|
|
|
}
|
2014-06-03 18:16:47 +08:00
|
|
|
if (S->isOpenMPLoopScope())
|
|
|
|
return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)
|
|
|
|
<< "break");
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
CheckJumpOutOfSEHFinally(*this, BreakLoc, *S);
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) BreakStmt(BreakLoc);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2011-01-27 15:10:08 +08:00
|
|
|
/// \brief Determine whether the given expression is a candidate for
|
2011-01-22 02:05:27 +08:00
|
|
|
/// copy elision in either a return statement or a throw expression.
|
2010-05-15 14:01:05 +08:00
|
|
|
///
|
2011-01-22 02:05:27 +08:00
|
|
|
/// \param ReturnType If we're determining the copy elision candidate for
|
|
|
|
/// a return statement, this is the return type of the function. If we're
|
|
|
|
/// determining the copy elision candidate for a throw expression, this will
|
|
|
|
/// be a NULL type.
|
2010-05-15 14:01:05 +08:00
|
|
|
///
|
2011-01-22 02:05:27 +08:00
|
|
|
/// \param E The expression being returned from the function or block, or
|
|
|
|
/// being thrown.
|
2010-05-15 14:01:05 +08:00
|
|
|
///
|
2016-07-01 07:09:13 +08:00
|
|
|
/// \param AllowParamOrMoveConstructible Whether we allow function parameters or
|
|
|
|
/// id-expressions that could be moved out of the function to be considered NRVO
|
|
|
|
/// candidates. C++ prohibits these for NRVO itself, but we re-use this logic to
|
|
|
|
/// determine whether we should try to move as part of a return or throw (which
|
|
|
|
/// does allow function parameters).
|
2010-05-15 14:01:05 +08:00
|
|
|
///
|
|
|
|
/// \returns The NRVO candidate variable, if the return statement may use the
|
|
|
|
/// NRVO, or NULL if there is no such candidate.
|
2016-07-01 07:09:13 +08:00
|
|
|
VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E,
|
|
|
|
bool AllowParamOrMoveConstructible) {
|
2014-05-03 08:41:18 +08:00
|
|
|
if (!getLangOpts().CPlusPlus)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
// - in a return statement in a function [where] ...
|
|
|
|
// ... the expression is the name of a non-volatile automatic object ...
|
|
|
|
DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens());
|
2015-01-12 18:17:46 +08:00
|
|
|
if (!DR || DR->refersToEnclosingVariableOrCapture())
|
2014-05-03 08:41:18 +08:00
|
|
|
return nullptr;
|
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
|
|
|
|
if (!VD)
|
|
|
|
return nullptr;
|
|
|
|
|
2016-07-01 07:09:13 +08:00
|
|
|
if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible))
|
2014-05-03 08:41:18 +08:00
|
|
|
return VD;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
|
2016-07-01 07:09:13 +08:00
|
|
|
bool AllowParamOrMoveConstructible) {
|
2014-05-03 08:41:18 +08:00
|
|
|
QualType VDType = VD->getType();
|
2010-05-15 08:13:29 +08:00
|
|
|
// - in a return statement in a function with ...
|
|
|
|
// ... a class return type ...
|
2014-05-03 08:41:18 +08:00
|
|
|
if (!ReturnType.isNull() && !ReturnType->isDependentType()) {
|
2011-01-22 02:05:27 +08:00
|
|
|
if (!ReturnType->isRecordType())
|
2014-05-03 08:41:18 +08:00
|
|
|
return false;
|
2011-01-22 02:05:27 +08:00
|
|
|
// ... the same cv-unqualified type as the function return type ...
|
2016-07-01 07:09:13 +08:00
|
|
|
// When considering moving this expression out, allow dissimilar types.
|
|
|
|
if (!AllowParamOrMoveConstructible && !VDType->isDependentType() &&
|
2014-05-03 08:41:18 +08:00
|
|
|
!Context.hasSameUnqualifiedType(ReturnType, VDType))
|
|
|
|
return false;
|
2011-01-22 02:05:27 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-11-11 11:57:31 +08:00
|
|
|
// ...object (other than a function or catch-clause parameter)...
|
|
|
|
if (VD->getKind() != Decl::Var &&
|
2016-07-01 07:09:13 +08:00
|
|
|
!(AllowParamOrMoveConstructible && VD->getKind() == Decl::ParmVar))
|
2014-05-03 08:41:18 +08:00
|
|
|
return false;
|
|
|
|
if (VD->isExceptionVariable()) return false;
|
2011-11-11 11:57:31 +08:00
|
|
|
|
|
|
|
// ...automatic...
|
2014-05-03 08:41:18 +08:00
|
|
|
if (!VD->hasLocalStorage()) return false;
|
2011-11-11 11:57:31 +08:00
|
|
|
|
2017-02-15 13:15:28 +08:00
|
|
|
// Return false if VD is a __block variable. We don't want to implicitly move
|
|
|
|
// out of a __block variable during a return because we cannot assume the
|
|
|
|
// variable will no longer be used.
|
|
|
|
if (VD->hasAttr<BlocksAttr>()) return false;
|
|
|
|
|
2016-07-01 07:09:13 +08:00
|
|
|
if (AllowParamOrMoveConstructible)
|
|
|
|
return true;
|
|
|
|
|
2011-11-11 11:57:31 +08:00
|
|
|
// ...non-volatile...
|
2014-05-03 08:41:18 +08:00
|
|
|
if (VD->getType().isVolatileQualified()) return false;
|
2011-11-11 11:57:31 +08:00
|
|
|
|
|
|
|
// Variables with higher required alignment than their type's ABI
|
|
|
|
// alignment cannot use NRVO.
|
2014-05-03 08:41:18 +08:00
|
|
|
if (!VD->getType()->isDependentType() && VD->hasAttr<AlignedAttr>() &&
|
2011-11-11 11:57:31 +08:00
|
|
|
Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VD->getType()))
|
2014-05-03 08:41:18 +08:00
|
|
|
return false;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2014-05-03 08:41:18 +08:00
|
|
|
return true;
|
2010-05-15 08:13:29 +08:00
|
|
|
}
|
|
|
|
|
2011-01-22 05:08:57 +08:00
|
|
|
/// \brief Perform the initialization of a potentially-movable value, which
|
|
|
|
/// is the result of return value.
|
2011-01-22 03:38:21 +08:00
|
|
|
///
|
2016-07-01 07:09:13 +08:00
|
|
|
/// This routine implements C++14 [class.copy]p32, which attempts to treat
|
2011-01-22 03:38:21 +08:00
|
|
|
/// returned lvalues as rvalues in certain cases (to prefer move construction),
|
|
|
|
/// then falls back to treating them as lvalues if that failed.
|
2011-01-27 15:10:08 +08:00
|
|
|
ExprResult
|
2011-01-22 05:08:57 +08:00
|
|
|
Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
|
|
|
|
const VarDecl *NRVOCandidate,
|
|
|
|
QualType ResultType,
|
2011-07-07 06:04:06 +08:00
|
|
|
Expr *Value,
|
|
|
|
bool AllowNRVO) {
|
2016-07-01 07:09:13 +08:00
|
|
|
// C++14 [class.copy]p32:
|
|
|
|
// When the criteria for elision of a copy/move operation are met, but not for
|
|
|
|
// an exception-declaration, and the object to be copied is designated by an
|
|
|
|
// lvalue, or when the expression in a return statement is a (possibly
|
|
|
|
// parenthesized) id-expression that names an object with automatic storage
|
|
|
|
// duration declared in the body or parameter-declaration-clause of the
|
|
|
|
// innermost enclosing function or lambda-expression, overload resolution to
|
|
|
|
// select the constructor for the copy is first performed as if the object
|
|
|
|
// were designated by an rvalue.
|
2011-01-22 03:38:21 +08:00
|
|
|
ExprResult Res = ExprError();
|
2016-07-01 07:09:13 +08:00
|
|
|
|
|
|
|
if (AllowNRVO && !NRVOCandidate)
|
|
|
|
NRVOCandidate = getCopyElisionCandidate(ResultType, Value, true);
|
|
|
|
|
|
|
|
if (AllowNRVO && NRVOCandidate) {
|
|
|
|
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
|
|
|
|
CK_NoOp, Value, VK_XValue);
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-01-22 03:38:21 +08:00
|
|
|
Expr *InitExpr = &AsRvalue;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2016-07-01 07:09:13 +08:00
|
|
|
InitializationKind Kind = InitializationKind::CreateCopy(
|
|
|
|
Value->getLocStart(), Value->getLocStart());
|
|
|
|
|
|
|
|
InitializationSequence Seq(*this, Entity, Kind, InitExpr);
|
2011-06-05 20:23:28 +08:00
|
|
|
if (Seq) {
|
2016-07-01 07:09:13 +08:00
|
|
|
for (const InitializationSequence::Step &Step : Seq.steps()) {
|
|
|
|
if (!(Step.Kind ==
|
|
|
|
InitializationSequence::SK_ConstructorInitialization ||
|
|
|
|
(Step.Kind == InitializationSequence::SK_UserConversion &&
|
|
|
|
isa<CXXConstructorDecl>(Step.Function.Function))))
|
2011-01-22 03:38:21 +08:00
|
|
|
continue;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2016-07-01 07:09:13 +08:00
|
|
|
CXXConstructorDecl *Constructor =
|
|
|
|
cast<CXXConstructorDecl>(Step.Function.Function);
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-01-22 03:38:21 +08:00
|
|
|
const RValueReferenceType *RRefType
|
2011-01-22 05:08:57 +08:00
|
|
|
= Constructor->getParamDecl(0)->getType()
|
|
|
|
->getAs<RValueReferenceType>();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2016-07-01 07:09:13 +08:00
|
|
|
// [...] If the first overload resolution fails or was not performed, or
|
|
|
|
// if the type of the first parameter of the selected constructor is not
|
2017-05-06 01:15:08 +08:00
|
|
|
// an rvalue reference to the object's type (possibly cv-qualified),
|
2016-07-01 07:09:13 +08:00
|
|
|
// overload resolution is performed again, considering the object as an
|
|
|
|
// lvalue.
|
2011-01-27 15:10:08 +08:00
|
|
|
if (!RRefType ||
|
2011-01-22 05:08:57 +08:00
|
|
|
!Context.hasSameUnqualifiedType(RRefType->getPointeeType(),
|
2016-07-01 07:09:13 +08:00
|
|
|
NRVOCandidate->getType()))
|
2011-01-22 03:38:21 +08:00
|
|
|
break;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-01-22 03:38:21 +08:00
|
|
|
// Promote "AsRvalue" to the heap, since we now need this
|
|
|
|
// expression node to persist.
|
2016-07-01 07:09:13 +08:00
|
|
|
Value = ImplicitCastExpr::Create(Context, Value->getType(), CK_NoOp,
|
|
|
|
Value, nullptr, VK_XValue);
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-01-22 03:38:21 +08:00
|
|
|
// Complete type-checking the initialization of the return type
|
|
|
|
// using the constructor we found.
|
2013-05-03 23:05:50 +08:00
|
|
|
Res = Seq.Perform(*this, Entity, Kind, Value);
|
2011-01-22 03:38:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-01-22 03:38:21 +08:00
|
|
|
// Either we didn't meet the criteria for treating an lvalue as an rvalue,
|
2011-01-27 15:10:08 +08:00
|
|
|
// above, or overload resolution failed. Either way, we need to try
|
2011-01-22 03:38:21 +08:00
|
|
|
// (again) now with the return value expression as written.
|
|
|
|
if (Res.isInvalid())
|
2011-01-22 05:08:57 +08:00
|
|
|
Res = PerformCopyInitialization(Entity, SourceLocation(), Value);
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-01-22 03:38:21 +08:00
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2013-09-25 13:02:54 +08:00
|
|
|
/// \brief Determine whether the declared return type of the specified function
|
|
|
|
/// contains 'auto'.
|
|
|
|
static bool hasDeducedReturnType(FunctionDecl *FD) {
|
|
|
|
const FunctionProtoType *FPT =
|
|
|
|
FD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
|
2014-01-26 00:55:45 +08:00
|
|
|
return FPT->getReturnType()->isUndeducedType();
|
2013-09-25 13:02:54 +08:00
|
|
|
}
|
|
|
|
|
2012-01-26 11:00:14 +08:00
|
|
|
/// ActOnCapScopeReturnStmt - Utility routine to type-check return statements
|
|
|
|
/// for capturing scopes.
|
2008-09-04 02:15:37 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2012-01-26 11:00:14 +08:00
|
|
|
Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
|
|
|
// If this is the first return we've seen, infer the return type.
|
2013-05-12 11:09:35 +08:00
|
|
|
// [expr.prim.lambda]p4 in C++11; block literals follow the same rules.
|
2012-01-26 11:00:14 +08:00
|
|
|
CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
|
2012-07-03 05:19:23 +08:00
|
|
|
QualType FnRetType = CurCap->ReturnType;
|
2013-09-25 13:02:54 +08:00
|
|
|
LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap);
|
2016-06-24 03:16:49 +08:00
|
|
|
bool HasDeducedReturnType =
|
|
|
|
CurLambda && hasDeducedReturnType(CurLambda->CallOperator);
|
|
|
|
|
2017-04-02 05:30:49 +08:00
|
|
|
if (ExprEvalContexts.back().Context ==
|
|
|
|
ExpressionEvaluationContext::DiscardedStatement &&
|
2016-06-24 03:16:49 +08:00
|
|
|
(HasDeducedReturnType || CurCap->HasImplicitReturnType)) {
|
|
|
|
if (RetValExp) {
|
|
|
|
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
|
|
|
|
if (ER.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
RetValExp = ER.get();
|
|
|
|
}
|
|
|
|
return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
|
|
|
|
}
|
2013-09-25 13:02:54 +08:00
|
|
|
|
2016-06-24 03:16:49 +08:00
|
|
|
if (HasDeducedReturnType) {
|
2013-09-25 13:02:54 +08:00
|
|
|
// In C++1y, the return type may involve 'auto'.
|
|
|
|
// FIXME: Blocks might have a return type of 'auto' explicitly specified.
|
|
|
|
FunctionDecl *FD = CurLambda->CallOperator;
|
|
|
|
if (CurCap->ReturnType.isNull())
|
2014-01-26 00:55:45 +08:00
|
|
|
CurCap->ReturnType = FD->getReturnType();
|
2013-08-22 20:12:24 +08:00
|
|
|
|
2013-09-25 13:02:54 +08:00
|
|
|
AutoType *AT = CurCap->ReturnType->getContainedAutoType();
|
|
|
|
assert(AT && "lost auto type from lambda return type");
|
|
|
|
if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
|
|
|
|
FD->setInvalidDecl();
|
|
|
|
return StmtError();
|
|
|
|
}
|
2014-01-26 00:55:45 +08:00
|
|
|
CurCap->ReturnType = FnRetType = FD->getReturnType();
|
2013-09-25 13:02:54 +08:00
|
|
|
} else if (CurCap->HasImplicitReturnType) {
|
|
|
|
// 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.
|
|
|
|
// FIXME: Fold this into the 'auto' codepath above.
|
2012-02-10 02:40:39 +08:00
|
|
|
if (RetValExp && !isa<InitListExpr>(RetValExp)) {
|
2011-04-09 02:41:53 +08:00
|
|
|
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
|
|
|
|
if (Result.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
RetValExp = Result.get();
|
2011-06-05 13:04:23 +08:00
|
|
|
|
2014-12-20 06:10:51 +08:00
|
|
|
// DR1048: even prior to C++14, we should use the 'auto' deduction rules
|
|
|
|
// when deducing a return type for a lambda-expression (or by extension
|
|
|
|
// for a block). These rules differ from the stated C++11 rules only in
|
|
|
|
// that they remove top-level cv-qualifiers.
|
2013-09-25 13:02:54 +08:00
|
|
|
if (!CurContext->isDependentContext())
|
2014-12-20 06:10:51 +08:00
|
|
|
FnRetType = RetValExp->getType().getUnqualifiedType();
|
2013-09-25 13:02:54 +08:00
|
|
|
else
|
2012-07-03 05:19:23 +08:00
|
|
|
FnRetType = CurCap->ReturnType = Context.DependentTy;
|
2012-08-11 01:56:09 +08:00
|
|
|
} else {
|
2012-02-10 02:40:39 +08:00
|
|
|
if (RetValExp) {
|
|
|
|
// C++11 [expr.lambda.prim]p4 bans inferring the result from an
|
|
|
|
// initializer list, because it is not an expression (even
|
|
|
|
// though we represent it as one). We still deduce 'void'.
|
|
|
|
Diag(ReturnLoc, diag::err_lambda_return_init_list)
|
|
|
|
<< RetValExp->getSourceRange();
|
|
|
|
}
|
2013-08-22 20:12:24 +08:00
|
|
|
|
2012-07-03 05:19:23 +08:00
|
|
|
FnRetType = Context.VoidTy;
|
2011-12-04 07:53:56 +08:00
|
|
|
}
|
2012-07-03 05:19:23 +08:00
|
|
|
|
|
|
|
// 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;
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2012-01-26 11:00:14 +08:00
|
|
|
assert(!FnRetType.isNull());
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2012-02-16 00:20:15 +08:00
|
|
|
if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
|
2012-01-26 11:00:14 +08:00
|
|
|
if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
|
|
|
|
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
|
|
|
|
return StmtError();
|
|
|
|
}
|
2013-04-17 03:37:38 +08:00
|
|
|
} else if (CapturedRegionScopeInfo *CurRegion =
|
|
|
|
dyn_cast<CapturedRegionScopeInfo>(CurCap)) {
|
|
|
|
Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName();
|
|
|
|
return StmtError();
|
2012-02-16 00:20:15 +08:00
|
|
|
} else {
|
2013-09-25 13:02:54 +08:00
|
|
|
assert(CurLambda && "unknown kind of captured scope");
|
|
|
|
if (CurLambda->CallOperator->getType()->getAs<FunctionType>()
|
|
|
|
->getNoReturnAttr()) {
|
2012-02-16 00:20:15 +08:00
|
|
|
Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
}
|
2009-04-30 05:40:37 +08:00
|
|
|
|
2008-09-04 02:15:37 +08:00
|
|
|
// Otherwise, verify that this result type matches the previous one. We are
|
|
|
|
// pickier with blocks than for normal functions because we don't have GCC
|
|
|
|
// compatibility to worry about here.
|
2014-05-26 14:22:03 +08:00
|
|
|
const VarDecl *NRVOCandidate = nullptr;
|
2013-08-22 20:12:24 +08:00
|
|
|
if (FnRetType->isDependentType()) {
|
2011-08-18 06:09:46 +08:00
|
|
|
// Delay processing for now. TODO: there are lots of dependent
|
|
|
|
// types we can conclusively prove aren't void.
|
|
|
|
} else if (FnRetType->isVoidType()) {
|
2012-02-23 01:38:04 +08:00
|
|
|
if (RetValExp && !isa<InitListExpr>(RetValExp) &&
|
2012-03-11 15:00:24 +08:00
|
|
|
!(getLangOpts().CPlusPlus &&
|
2011-08-18 06:09:46 +08:00
|
|
|
(RetValExp->isTypeDependent() ||
|
|
|
|
RetValExp->getType()->isVoidType()))) {
|
2012-03-22 00:45:13 +08:00
|
|
|
if (!getLangOpts().CPlusPlus &&
|
|
|
|
RetValExp->getType()->isVoidType())
|
2012-03-22 04:28:39 +08:00
|
|
|
Diag(ReturnLoc, diag::ext_return_has_void_expr) << "literal" << 2;
|
2012-03-22 00:45:13 +08:00
|
|
|
else {
|
|
|
|
Diag(ReturnLoc, diag::err_return_block_has_expr);
|
2014-05-26 14:22:03 +08:00
|
|
|
RetValExp = nullptr;
|
2012-03-22 00:45:13 +08:00
|
|
|
}
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2010-05-15 14:01:05 +08:00
|
|
|
} else if (!RetValExp) {
|
2011-08-18 06:09:46 +08:00
|
|
|
return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
|
|
|
|
} else if (!RetValExp->isTypeDependent()) {
|
|
|
|
// we have a non-void block with an expression, continue checking
|
|
|
|
|
|
|
|
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
|
|
|
|
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
|
|
|
|
// function return.
|
|
|
|
|
|
|
|
// In C++ the return statement is handled via a copy initialization.
|
|
|
|
// the C version of which boils down to CheckSingleAssignmentConstraints.
|
|
|
|
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
|
|
|
|
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
|
|
|
|
FnRetType,
|
2014-05-26 14:22:03 +08:00
|
|
|
NRVOCandidate != nullptr);
|
2011-08-18 06:09:46 +08:00
|
|
|
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
|
|
|
|
FnRetType, RetValExp);
|
|
|
|
if (Res.isInvalid()) {
|
|
|
|
// FIXME: Cleanup temporaries here, anyway?
|
|
|
|
return StmtError();
|
2010-01-30 02:30:20 +08:00
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
RetValExp = Res.get();
|
2014-01-22 14:10:28 +08:00
|
|
|
CheckReturnValExpr(RetValExp, FnRetType, ReturnLoc);
|
2014-05-03 08:41:18 +08:00
|
|
|
} else {
|
|
|
|
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
|
2011-08-18 05:34:14 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-08-18 05:34:14 +08:00
|
|
|
if (RetValExp) {
|
2013-01-15 06:39:08 +08:00
|
|
|
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
|
|
|
|
if (ER.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
RetValExp = ER.get();
|
2009-02-05 06:31:32 +08:00
|
|
|
}
|
2011-08-18 06:09:46 +08:00
|
|
|
ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp,
|
|
|
|
NRVOCandidate);
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2012-07-03 05:19:23 +08:00
|
|
|
// 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.
|
2014-05-03 08:41:18 +08:00
|
|
|
if (CurCap->HasImplicitReturnType || NRVOCandidate)
|
2010-05-15 14:01:05 +08:00
|
|
|
FunctionScopes.back()->Returns.push_back(Result);
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2015-10-27 14:02:45 +08:00
|
|
|
if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
|
|
|
|
FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
|
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return Result;
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2013-08-22 20:12:24 +08:00
|
|
|
|
Add -Wunused-local-typedef, a warning that finds unused local typedefs.
The warning warns on TypedefNameDecls -- typedefs and C++11 using aliases --
that are !isReferenced(). Since the isReferenced() bit on TypedefNameDecls
wasn't used for anything before this warning it wasn't always set correctly,
so this patch also adds a few missing MarkAnyDeclReferenced() calls in
various places for TypedefNameDecls.
This is made a bit complicated due to local typedefs possibly being used only
after their local scope has closed. Consider:
template <class T>
void template_fun(T t) {
typename T::Foo s3foo; // YYY
(void)s3foo;
}
void template_fun_user() {
struct Local {
typedef int Foo; // XXX
} p;
template_fun(p);
}
Here the typedef in XXX is only used at end-of-translation unit, when YYY in
template_fun() gets instantiated. To handle this, typedefs that are unused when
their scope exits are added to a set of potentially unused typedefs, and that
set gets checked at end-of-TU. Typedefs that are still unused at that point then
get warned on. There's also serialization code for this set, so that the
warning works with precompiled headers and modules. For modules, the warning
is emitted when the module is built, for precompiled headers each time the
header gets used.
Finally, consider a function using C++14 auto return types to return a local
type defined in a header:
auto f() {
struct S { typedef int a; };
return S();
}
Here, the typedef escapes its local scope and could be used by only some
translation units including the header. To not warn on this, add a
RecursiveASTVisitor that marks all delcs on local types returned from auto
functions as referenced. (Except if it's a function with internal linkage, or
the decls are private and the local type has no friends -- in these cases, it
_is_ safe to warn.)
Several of the included testcases (most of the interesting ones) were provided
by Richard Smith.
(gcc's spelling -Wunused-local-typedefs is supported as an alias for this
warning.)
llvm-svn: 217298
2014-09-06 09:25:55 +08:00
|
|
|
namespace {
|
|
|
|
/// \brief Marks all typedefs in all local classes in a type referenced.
|
|
|
|
///
|
|
|
|
/// In a function like
|
|
|
|
/// auto f() {
|
|
|
|
/// struct S { typedef int a; };
|
|
|
|
/// return S();
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// the local type escapes and could be referenced in some TUs but not in
|
|
|
|
/// others. Pretend that all local typedefs are always referenced, to not warn
|
|
|
|
/// on this. This isn't necessary if f has internal linkage, or the typedef
|
|
|
|
/// is private.
|
|
|
|
class LocalTypedefNameReferencer
|
|
|
|
: public RecursiveASTVisitor<LocalTypedefNameReferencer> {
|
|
|
|
public:
|
|
|
|
LocalTypedefNameReferencer(Sema &S) : S(S) {}
|
|
|
|
bool VisitRecordType(const RecordType *RT);
|
|
|
|
private:
|
|
|
|
Sema &S;
|
|
|
|
};
|
|
|
|
bool LocalTypedefNameReferencer::VisitRecordType(const RecordType *RT) {
|
|
|
|
auto *R = dyn_cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
if (!R || !R->isLocalClass() || !R->isLocalClass()->isExternallyVisible() ||
|
|
|
|
R->isDependentType())
|
|
|
|
return true;
|
|
|
|
for (auto *TmpD : R->decls())
|
|
|
|
if (auto *T = dyn_cast<TypedefNameDecl>(TmpD))
|
|
|
|
if (T->getAccess() != AS_private || R->hasFriends())
|
|
|
|
S.MarkAnyDeclReferenced(T->getLocation(), T, /*OdrUse=*/false);
|
|
|
|
return true;
|
|
|
|
}
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
Add -Wunused-local-typedef, a warning that finds unused local typedefs.
The warning warns on TypedefNameDecls -- typedefs and C++11 using aliases --
that are !isReferenced(). Since the isReferenced() bit on TypedefNameDecls
wasn't used for anything before this warning it wasn't always set correctly,
so this patch also adds a few missing MarkAnyDeclReferenced() calls in
various places for TypedefNameDecls.
This is made a bit complicated due to local typedefs possibly being used only
after their local scope has closed. Consider:
template <class T>
void template_fun(T t) {
typename T::Foo s3foo; // YYY
(void)s3foo;
}
void template_fun_user() {
struct Local {
typedef int Foo; // XXX
} p;
template_fun(p);
}
Here the typedef in XXX is only used at end-of-translation unit, when YYY in
template_fun() gets instantiated. To handle this, typedefs that are unused when
their scope exits are added to a set of potentially unused typedefs, and that
set gets checked at end-of-TU. Typedefs that are still unused at that point then
get warned on. There's also serialization code for this set, so that the
warning works with precompiled headers and modules. For modules, the warning
is emitted when the module is built, for precompiled headers each time the
header gets used.
Finally, consider a function using C++14 auto return types to return a local
type defined in a header:
auto f() {
struct S { typedef int a; };
return S();
}
Here, the typedef escapes its local scope and could be used by only some
translation units including the header. To not warn on this, add a
RecursiveASTVisitor that marks all delcs on local types returned from auto
functions as referenced. (Except if it's a function with internal linkage, or
the decls are private and the local type has no friends -- in these cases, it
_is_ safe to warn.)
Several of the included testcases (most of the interesting ones) were provided
by Richard Smith.
(gcc's spelling -Wunused-local-typedefs is supported as an alias for this
warning.)
llvm-svn: 217298
2014-09-06 09:25:55 +08:00
|
|
|
|
2014-10-17 06:42:53 +08:00
|
|
|
TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const {
|
2014-10-18 01:20:33 +08:00
|
|
|
TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
|
2014-10-17 06:42:53 +08:00
|
|
|
while (auto ATL = TL.getAs<AttributedTypeLoc>())
|
|
|
|
TL = ATL.getModifiedLoc().IgnoreParens();
|
2014-10-18 01:20:33 +08:00
|
|
|
return TL.castAs<FunctionProtoTypeLoc>().getReturnLoc();
|
2014-10-17 06:42:53 +08:00
|
|
|
}
|
|
|
|
|
2013-05-04 15:00:32 +08:00
|
|
|
/// Deduce the return type for a function from a returned expression, per
|
|
|
|
/// C++1y [dcl.spec.auto]p6.
|
|
|
|
bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
|
|
|
|
SourceLocation ReturnLoc,
|
|
|
|
Expr *&RetExpr,
|
|
|
|
AutoType *AT) {
|
2014-10-17 06:42:53 +08:00
|
|
|
TypeLoc OrigResultType = getReturnTypeLoc(FD);
|
2013-05-04 15:00:32 +08:00
|
|
|
QualType Deduced;
|
2013-08-22 20:12:24 +08:00
|
|
|
|
2013-08-15 04:16:31 +08:00
|
|
|
if (RetExpr && isa<InitListExpr>(RetExpr)) {
|
|
|
|
// If the deduction is for a return statement and the initializer is
|
|
|
|
// a braced-init-list, the program is ill-formed.
|
2013-09-25 13:02:54 +08:00
|
|
|
Diag(RetExpr->getExprLoc(),
|
|
|
|
getCurLambda() ? diag::err_lambda_return_init_list
|
|
|
|
: diag::err_auto_fn_return_init_list)
|
|
|
|
<< RetExpr->getSourceRange();
|
2013-08-15 04:16:31 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD->isDependentContext()) {
|
|
|
|
// C++1y [dcl.spec.auto]p12:
|
|
|
|
// Return type deduction [...] occurs when the definition is
|
|
|
|
// instantiated even if the function body contains a return
|
|
|
|
// statement with a non-type-dependent operand.
|
|
|
|
assert(AT->isDeduced() && "should have deduced to dependent type");
|
|
|
|
return false;
|
2015-10-02 03:52:44 +08:00
|
|
|
}
|
2013-05-04 15:00:32 +08:00
|
|
|
|
2015-10-02 03:52:44 +08:00
|
|
|
if (RetExpr) {
|
2013-05-04 15:00:32 +08:00
|
|
|
// Otherwise, [...] deduce a value for U using the rules of template
|
|
|
|
// argument deduction.
|
|
|
|
DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced);
|
|
|
|
|
|
|
|
if (DAR == DAR_Failed && !FD->isInvalidDecl())
|
|
|
|
Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
|
|
|
|
<< OrigResultType.getType() << RetExpr->getType();
|
|
|
|
|
|
|
|
if (DAR != DAR_Succeeded)
|
|
|
|
return true;
|
Add -Wunused-local-typedef, a warning that finds unused local typedefs.
The warning warns on TypedefNameDecls -- typedefs and C++11 using aliases --
that are !isReferenced(). Since the isReferenced() bit on TypedefNameDecls
wasn't used for anything before this warning it wasn't always set correctly,
so this patch also adds a few missing MarkAnyDeclReferenced() calls in
various places for TypedefNameDecls.
This is made a bit complicated due to local typedefs possibly being used only
after their local scope has closed. Consider:
template <class T>
void template_fun(T t) {
typename T::Foo s3foo; // YYY
(void)s3foo;
}
void template_fun_user() {
struct Local {
typedef int Foo; // XXX
} p;
template_fun(p);
}
Here the typedef in XXX is only used at end-of-translation unit, when YYY in
template_fun() gets instantiated. To handle this, typedefs that are unused when
their scope exits are added to a set of potentially unused typedefs, and that
set gets checked at end-of-TU. Typedefs that are still unused at that point then
get warned on. There's also serialization code for this set, so that the
warning works with precompiled headers and modules. For modules, the warning
is emitted when the module is built, for precompiled headers each time the
header gets used.
Finally, consider a function using C++14 auto return types to return a local
type defined in a header:
auto f() {
struct S { typedef int a; };
return S();
}
Here, the typedef escapes its local scope and could be used by only some
translation units including the header. To not warn on this, add a
RecursiveASTVisitor that marks all delcs on local types returned from auto
functions as referenced. (Except if it's a function with internal linkage, or
the decls are private and the local type has no friends -- in these cases, it
_is_ safe to warn.)
Several of the included testcases (most of the interesting ones) were provided
by Richard Smith.
(gcc's spelling -Wunused-local-typedefs is supported as an alias for this
warning.)
llvm-svn: 217298
2014-09-06 09:25:55 +08:00
|
|
|
|
|
|
|
// If a local type is part of the returned type, mark its fields as
|
|
|
|
// referenced.
|
|
|
|
LocalTypedefNameReferencer Referencer(*this);
|
|
|
|
Referencer.TraverseType(RetExpr->getType());
|
2013-05-04 15:00:32 +08:00
|
|
|
} else {
|
|
|
|
// In the case of a return with no operand, the initializer is considered
|
|
|
|
// to be void().
|
|
|
|
//
|
|
|
|
// Deduction here can only succeed if the return type is exactly 'cv auto'
|
|
|
|
// or 'decltype(auto)', so just check for that case directly.
|
|
|
|
if (!OrigResultType.getType()->getAs<AutoType>()) {
|
|
|
|
Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
|
|
|
|
<< OrigResultType.getType();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// We always deduce U = void in this case.
|
|
|
|
Deduced = SubstAutoType(OrigResultType.getType(), Context.VoidTy);
|
|
|
|
if (Deduced.isNull())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a function with a declared return type that contains a placeholder type
|
|
|
|
// has multiple return statements, the return type is deduced for each return
|
|
|
|
// statement. [...] if the type deduced is not the same in each deduction,
|
|
|
|
// the program is ill-formed.
|
2016-01-30 09:51:20 +08:00
|
|
|
QualType DeducedT = AT->getDeducedType();
|
|
|
|
if (!DeducedT.isNull() && !FD->isInvalidDecl()) {
|
2013-05-04 15:00:32 +08:00
|
|
|
AutoType *NewAT = Deduced->getContainedAutoType();
|
2016-02-05 04:05:40 +08:00
|
|
|
// It is possible that NewAT->getDeducedType() is null. When that happens,
|
|
|
|
// we should not crash, instead we ignore this deduction.
|
|
|
|
if (NewAT->getDeducedType().isNull())
|
|
|
|
return false;
|
|
|
|
|
2015-10-02 04:20:47 +08:00
|
|
|
CanQualType OldDeducedType = Context.getCanonicalFunctionResultType(
|
2016-01-30 09:51:20 +08:00
|
|
|
DeducedT);
|
2015-10-02 04:20:47 +08:00
|
|
|
CanQualType NewDeducedType = Context.getCanonicalFunctionResultType(
|
|
|
|
NewAT->getDeducedType());
|
|
|
|
if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) {
|
2013-09-25 13:02:54 +08:00
|
|
|
const LambdaScopeInfo *LambdaSI = getCurLambda();
|
|
|
|
if (LambdaSI && LambdaSI->HasImplicitReturnType) {
|
|
|
|
Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
|
2016-01-30 09:51:20 +08:00
|
|
|
<< NewAT->getDeducedType() << DeducedT
|
2013-09-25 13:02:54 +08:00
|
|
|
<< true /*IsLambda*/;
|
|
|
|
} else {
|
|
|
|
Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
|
|
|
|
<< (AT->isDecltypeAuto() ? 1 : 0)
|
2016-01-30 09:51:20 +08:00
|
|
|
<< NewAT->getDeducedType() << DeducedT;
|
2013-09-25 13:02:54 +08:00
|
|
|
}
|
2013-05-04 15:00:32 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (!FD->isInvalidDecl()) {
|
|
|
|
// Update all declarations of the function to have the deduced return type.
|
|
|
|
Context.adjustDeducedFunctionResultType(FD, Deduced);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2014-05-03 08:41:18 +08:00
|
|
|
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
|
|
|
|
Scope *CurScope) {
|
|
|
|
StmtResult R = BuildReturnStmt(ReturnLoc, RetValExp);
|
2017-04-02 05:30:49 +08:00
|
|
|
if (R.isInvalid() || ExprEvalContexts.back().Context ==
|
|
|
|
ExpressionEvaluationContext::DiscardedStatement)
|
2014-05-03 08:41:18 +08:00
|
|
|
return R;
|
|
|
|
|
|
|
|
if (VarDecl *VD =
|
|
|
|
const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) {
|
|
|
|
CurScope->addNRVOCandidate(VD);
|
|
|
|
} else {
|
|
|
|
CurScope->setNoNRVO();
|
|
|
|
}
|
|
|
|
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
|
|
|
|
|
2014-05-03 08:41:18 +08:00
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
2011-05-20 23:32:55 +08:00
|
|
|
// Check for unexpanded parameter packs.
|
|
|
|
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
|
|
|
|
return StmtError();
|
2013-08-22 20:12:24 +08:00
|
|
|
|
2012-01-26 11:00:14 +08:00
|
|
|
if (isa<CapturingScopeInfo>(getCurFunction()))
|
|
|
|
return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp);
|
2013-08-22 20:12:24 +08:00
|
|
|
|
2008-12-05 07:50:19 +08:00
|
|
|
QualType FnRetType;
|
2012-03-30 09:13:43 +08:00
|
|
|
QualType RelatedRetType;
|
2014-05-26 14:22:03 +08:00
|
|
|
const AttrVec *Attrs = nullptr;
|
2014-01-22 14:10:28 +08:00
|
|
|
bool isObjCMethod = false;
|
|
|
|
|
2009-04-29 08:43:21 +08:00
|
|
|
if (const FunctionDecl *FD = getCurFunctionDecl()) {
|
2014-01-26 00:55:45 +08:00
|
|
|
FnRetType = FD->getReturnType();
|
2014-01-22 14:10:28 +08:00
|
|
|
if (FD->hasAttrs())
|
|
|
|
Attrs = &FD->getAttrs();
|
2013-01-17 09:30:42 +08:00
|
|
|
if (FD->isNoReturn())
|
2009-06-01 03:32:13 +08:00
|
|
|
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
|
2012-01-05 08:49:17 +08:00
|
|
|
<< FD->getDeclName();
|
2016-11-29 09:35:17 +08:00
|
|
|
if (FD->isMain() && RetValExp)
|
|
|
|
if (isa<CXXBoolLiteralExpr>(RetValExp))
|
|
|
|
Diag(ReturnLoc, diag::warn_main_returns_bool_literal)
|
|
|
|
<< RetValExp->getSourceRange();
|
2011-06-11 09:09:30 +08:00
|
|
|
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
|
2014-01-26 00:55:45 +08:00
|
|
|
FnRetType = MD->getReturnType();
|
2014-01-22 14:10:28 +08:00
|
|
|
isObjCMethod = true;
|
|
|
|
if (MD->hasAttrs())
|
|
|
|
Attrs = &MD->getAttrs();
|
2011-06-11 09:09:30 +08:00
|
|
|
if (MD->hasRelatedResultType() && MD->getClassInterface()) {
|
|
|
|
// In the implementation of a method with a related return type, the
|
2012-08-11 01:56:09 +08:00
|
|
|
// type used to type-check the validity of return statements within the
|
2011-06-11 09:09:30 +08:00
|
|
|
// method body is a pointer to the type of the class being implemented.
|
2012-03-30 09:13:43 +08:00
|
|
|
RelatedRetType = Context.getObjCInterfaceType(MD->getClassInterface());
|
|
|
|
RelatedRetType = Context.getObjCObjectPointerType(RelatedRetType);
|
2011-06-11 09:09:30 +08:00
|
|
|
}
|
|
|
|
} else // If we don't have a function/method context, bail.
|
2009-03-03 08:45:38 +08:00
|
|
|
return StmtError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2016-06-24 03:16:49 +08:00
|
|
|
// C++1z: discarded return statements are not considered when deducing a
|
|
|
|
// return type.
|
2017-04-02 05:30:49 +08:00
|
|
|
if (ExprEvalContexts.back().Context ==
|
|
|
|
ExpressionEvaluationContext::DiscardedStatement &&
|
2016-06-24 03:16:49 +08:00
|
|
|
FnRetType->getContainedAutoType()) {
|
|
|
|
if (RetValExp) {
|
|
|
|
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
|
|
|
|
if (ER.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
RetValExp = ER.get();
|
|
|
|
}
|
|
|
|
return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
|
|
|
|
}
|
|
|
|
|
2013-05-04 15:00:32 +08:00
|
|
|
// FIXME: Add a flag to the ScopeInfo to indicate whether we're performing
|
|
|
|
// deduction.
|
2014-08-19 23:55:55 +08:00
|
|
|
if (getLangOpts().CPlusPlus14) {
|
2013-05-04 15:00:32 +08:00
|
|
|
if (AutoType *AT = FnRetType->getContainedAutoType()) {
|
|
|
|
FunctionDecl *FD = cast<FunctionDecl>(CurContext);
|
2013-08-15 04:16:31 +08:00
|
|
|
if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
|
2013-05-04 15:00:32 +08:00
|
|
|
FD->setInvalidDecl();
|
|
|
|
return StmtError();
|
|
|
|
} else {
|
2014-01-26 00:55:45 +08:00
|
|
|
FnRetType = FD->getReturnType();
|
2013-05-04 15:00:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-15 04:16:31 +08:00
|
|
|
bool HasDependentReturnType = FnRetType->isDependentType();
|
|
|
|
|
2014-05-26 14:22:03 +08:00
|
|
|
ReturnStmt *Result = nullptr;
|
2008-01-05 02:04:52 +08:00
|
|
|
if (FnRetType->isVoidType()) {
|
2011-06-01 15:44:31 +08:00
|
|
|
if (RetValExp) {
|
2012-02-22 18:50:08 +08:00
|
|
|
if (isa<InitListExpr>(RetValExp)) {
|
|
|
|
// We simply never allow init lists as the return value of void
|
|
|
|
// functions. This is compatible because this was never allowed before,
|
|
|
|
// so there's no legacy code to deal with.
|
|
|
|
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
|
|
|
|
int FunctionKind = 0;
|
|
|
|
if (isa<ObjCMethodDecl>(CurDecl))
|
|
|
|
FunctionKind = 1;
|
|
|
|
else if (isa<CXXConstructorDecl>(CurDecl))
|
|
|
|
FunctionKind = 2;
|
|
|
|
else if (isa<CXXDestructorDecl>(CurDecl))
|
|
|
|
FunctionKind = 3;
|
|
|
|
|
|
|
|
Diag(ReturnLoc, diag::err_return_init_list)
|
|
|
|
<< CurDecl->getDeclName() << FunctionKind
|
|
|
|
<< RetValExp->getSourceRange();
|
|
|
|
|
|
|
|
// Drop the expression.
|
2014-05-26 14:22:03 +08:00
|
|
|
RetValExp = nullptr;
|
2012-02-22 18:50:08 +08:00
|
|
|
} else if (!RetValExp->isTypeDependent()) {
|
2011-06-01 15:44:31 +08:00
|
|
|
// C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
|
|
unsigned D = diag::ext_return_has_expr;
|
2013-12-04 01:10:08 +08:00
|
|
|
if (RetValExp->getType()->isVoidType()) {
|
|
|
|
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
|
|
|
|
if (isa<CXXConstructorDecl>(CurDecl) ||
|
|
|
|
isa<CXXDestructorDecl>(CurDecl))
|
|
|
|
D = diag::err_ctor_dtor_returns_void;
|
|
|
|
else
|
|
|
|
D = diag::ext_return_has_void_expr;
|
|
|
|
}
|
2011-06-01 15:44:31 +08:00
|
|
|
else {
|
2014-05-29 22:05:12 +08:00
|
|
|
ExprResult Result = RetValExp;
|
2014-05-29 18:55:11 +08:00
|
|
|
Result = IgnoredValueConversions(Result.get());
|
2011-06-01 15:44:31 +08:00
|
|
|
if (Result.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
RetValExp = Result.get();
|
2011-06-01 15:44:31 +08:00
|
|
|
RetValExp = ImpCastExprToType(RetValExp,
|
2014-05-29 18:55:11 +08:00
|
|
|
Context.VoidTy, CK_ToVoid).get();
|
2011-06-01 15:44:31 +08:00
|
|
|
}
|
2013-12-04 01:10:08 +08:00
|
|
|
// return of void in constructor/destructor is illegal in C++.
|
|
|
|
if (D == diag::err_ctor_dtor_returns_void) {
|
|
|
|
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
|
|
|
|
Diag(ReturnLoc, D)
|
|
|
|
<< CurDecl->getDeclName() << isa<CXXDestructorDecl>(CurDecl)
|
|
|
|
<< RetValExp->getSourceRange();
|
|
|
|
}
|
2011-06-01 15:44:31 +08:00
|
|
|
// return (some void expression); is legal in C++.
|
2013-12-04 01:10:08 +08:00
|
|
|
else if (D != diag::ext_return_has_void_expr ||
|
2015-11-17 13:40:05 +08:00
|
|
|
!getLangOpts().CPlusPlus) {
|
2011-06-01 15:44:31 +08:00
|
|
|
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
|
2011-06-30 16:56:22 +08:00
|
|
|
|
|
|
|
int FunctionKind = 0;
|
|
|
|
if (isa<ObjCMethodDecl>(CurDecl))
|
|
|
|
FunctionKind = 1;
|
|
|
|
else if (isa<CXXConstructorDecl>(CurDecl))
|
|
|
|
FunctionKind = 2;
|
|
|
|
else if (isa<CXXDestructorDecl>(CurDecl))
|
|
|
|
FunctionKind = 3;
|
|
|
|
|
2011-06-01 15:44:31 +08:00
|
|
|
Diag(ReturnLoc, D)
|
2011-06-30 16:56:22 +08:00
|
|
|
<< CurDecl->getDeclName() << FunctionKind
|
2011-06-01 15:44:31 +08:00
|
|
|
<< RetValExp->getSourceRange();
|
|
|
|
}
|
2008-12-18 10:03:48 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-22 18:50:08 +08:00
|
|
|
if (RetValExp) {
|
2013-01-15 06:39:08 +08:00
|
|
|
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
|
|
|
|
if (ER.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
RetValExp = ER.get();
|
2012-02-22 18:50:08 +08:00
|
|
|
}
|
2007-05-29 22:23:36 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2014-05-26 14:22:03 +08:00
|
|
|
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
|
2013-05-04 15:00:32 +08:00
|
|
|
} else if (!RetValExp && !HasDependentReturnType) {
|
2014-12-13 16:12:56 +08:00
|
|
|
FunctionDecl *FD = getCurFunctionDecl();
|
2008-11-19 16:23:25 +08:00
|
|
|
|
2014-12-13 16:12:56 +08:00
|
|
|
unsigned DiagID;
|
|
|
|
if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) {
|
|
|
|
// C++11 [stmt.return]p2
|
|
|
|
DiagID = diag::err_constexpr_return_missing_expr;
|
|
|
|
FD->setInvalidDecl();
|
|
|
|
} else if (getLangOpts().C99) {
|
|
|
|
// C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
|
|
DiagID = diag::ext_return_missing_expr;
|
|
|
|
} else {
|
|
|
|
// C90 6.6.6.4p4
|
|
|
|
DiagID = diag::warn_return_missing_expr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FD)
|
2008-11-24 05:45:46 +08:00
|
|
|
Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
|
2008-11-19 16:23:25 +08:00
|
|
|
else
|
2008-11-24 05:45:46 +08:00
|
|
|
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
|
2014-12-13 16:12:56 +08:00
|
|
|
|
2010-05-15 14:01:05 +08:00
|
|
|
Result = new (Context) ReturnStmt(ReturnLoc);
|
|
|
|
} else {
|
2013-05-04 15:00:32 +08:00
|
|
|
assert(RetValExp || HasDependentReturnType);
|
2014-05-26 14:22:03 +08:00
|
|
|
const VarDecl *NRVOCandidate = nullptr;
|
2010-05-15 14:01:05 +08:00
|
|
|
|
2014-05-03 08:41:18 +08:00
|
|
|
QualType RetType = RelatedRetType.isNull() ? FnRetType : RelatedRetType;
|
2012-03-30 09:13:43 +08:00
|
|
|
|
2014-05-03 08:41:18 +08:00
|
|
|
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
|
|
|
|
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
|
|
|
|
// function return.
|
2010-05-15 14:01:05 +08:00
|
|
|
|
2014-05-03 08:41:18 +08:00
|
|
|
// In C++ the return statement is handled via a copy initialization,
|
|
|
|
// the C version of which boils down to CheckSingleAssignmentConstraints.
|
|
|
|
if (RetValExp)
|
2011-01-22 02:05:27 +08:00
|
|
|
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
|
2014-05-03 08:41:18 +08:00
|
|
|
if (!HasDependentReturnType && !RetValExp->isTypeDependent()) {
|
|
|
|
// we have a non-void function with an expression, continue checking
|
2011-01-27 15:10:08 +08:00
|
|
|
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
|
2013-03-19 15:04:25 +08:00
|
|
|
RetType,
|
2014-05-26 14:22:03 +08:00
|
|
|
NRVOCandidate != nullptr);
|
2011-01-27 15:10:08 +08:00
|
|
|
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
|
2013-03-19 15:04:25 +08:00
|
|
|
RetType, RetValExp);
|
2010-05-15 14:01:05 +08:00
|
|
|
if (Res.isInvalid()) {
|
2013-03-19 15:04:25 +08:00
|
|
|
// FIXME: Clean up temporaries here anyway?
|
2010-05-15 14:01:05 +08:00
|
|
|
return StmtError();
|
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
RetValExp = Res.getAs<Expr>();
|
2013-03-19 15:04:25 +08:00
|
|
|
|
|
|
|
// If we have a related result type, we need to implicitly
|
|
|
|
// convert back to the formal result type. We can't pretend to
|
|
|
|
// initialize the result again --- we might end double-retaining
|
2013-07-12 00:48:06 +08:00
|
|
|
// --- so instead we initialize a notional temporary.
|
2013-03-19 15:04:25 +08:00
|
|
|
if (!RelatedRetType.isNull()) {
|
2013-07-12 00:48:06 +08:00
|
|
|
Entity = InitializedEntity::InitializeRelatedResult(getCurMethodDecl(),
|
|
|
|
FnRetType);
|
2013-03-19 15:04:25 +08:00
|
|
|
Res = PerformCopyInitialization(Entity, ReturnLoc, RetValExp);
|
|
|
|
if (Res.isInvalid()) {
|
|
|
|
// FIXME: Clean up temporaries here anyway?
|
|
|
|
return StmtError();
|
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
RetValExp = Res.getAs<Expr>();
|
2013-03-19 15:04:25 +08:00
|
|
|
}
|
|
|
|
|
2014-01-24 19:10:39 +08:00
|
|
|
CheckReturnValExpr(RetValExp, FnRetType, ReturnLoc, isObjCMethod, Attrs,
|
|
|
|
getCurFunctionDecl());
|
2009-11-14 09:20:54 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-10-08 10:01:28 +08:00
|
|
|
if (RetValExp) {
|
2013-01-15 06:39:08 +08:00
|
|
|
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
|
|
|
|
if (ER.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
RetValExp = ER.get();
|
2010-10-08 10:01:28 +08:00
|
|
|
}
|
2010-05-15 14:01:05 +08:00
|
|
|
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
|
2008-12-06 07:32:09 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
|
|
|
// If we need to check for the named return value optimization, save the
|
2010-05-15 14:01:05 +08:00
|
|
|
// return statement in our scope for later processing.
|
2014-05-03 08:41:18 +08:00
|
|
|
if (Result->getNRVOCandidate())
|
2010-05-15 14:01:05 +08:00
|
|
|
FunctionScopes.back()->Returns.push_back(Result);
|
2012-06-21 02:51:04 +08:00
|
|
|
|
2015-10-27 14:02:45 +08:00
|
|
|
if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
|
|
|
|
FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
|
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return Result;
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2009-01-19 01:43:11 +08:00
|
|
|
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
|
2010-08-21 17:40:31 +08:00
|
|
|
SourceLocation RParen, Decl *Parm,
|
2010-08-24 07:25:46 +08:00
|
|
|
Stmt *Body) {
|
2010-08-21 17:40:31 +08:00
|
|
|
VarDecl *Var = cast_or_null<VarDecl>(Parm);
|
2010-04-27 01:32:49 +08:00
|
|
|
if (Var && Var->isInvalidDecl())
|
|
|
|
return StmtError();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, Body);
|
2007-11-02 07:59:59 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2010-08-24 07:25:46 +08:00
|
|
|
Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body) {
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) ObjCAtFinallyStmt(AtLoc, Body);
|
2007-11-02 08:18:53 +08:00
|
|
|
}
|
2007-11-02 23:39:31 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2011-01-27 15:10:08 +08:00
|
|
|
Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try,
|
2010-08-24 07:25:46 +08:00
|
|
|
MultiStmtArg CatchStmts, Stmt *Finally) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().ObjCExceptions)
|
2011-02-20 07:53:54 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@try";
|
|
|
|
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->setHasBranchProtectedScope();
|
2010-04-24 06:50:49 +08:00
|
|
|
unsigned NumCatchStmts = CatchStmts.size();
|
2014-05-29 22:05:12 +08:00
|
|
|
return ObjCAtTryStmt::Create(Context, AtLoc, Try, CatchStmts.data(),
|
|
|
|
NumCatchStmts, Finally);
|
2007-11-02 23:39:31 +08:00
|
|
|
}
|
|
|
|
|
2012-05-09 05:41:25 +08:00
|
|
|
StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) {
|
2010-04-23 05:44:01 +08:00
|
|
|
if (Throw) {
|
2011-04-09 02:41:53 +08:00
|
|
|
ExprResult Result = DefaultLvalueConversion(Throw);
|
|
|
|
if (Result.isInvalid())
|
|
|
|
return StmtError();
|
2010-12-15 12:42:30 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
Result = ActOnFinishFullExpr(Result.get());
|
2013-01-15 06:39:08 +08:00
|
|
|
if (Result.isInvalid())
|
|
|
|
return StmtError();
|
2014-05-29 18:55:11 +08:00
|
|
|
Throw = Result.get();
|
2013-01-15 06:39:08 +08:00
|
|
|
|
2010-04-23 05:44:01 +08:00
|
|
|
QualType ThrowType = Throw->getType();
|
|
|
|
// Make sure the expression type is an ObjC pointer or "void *".
|
|
|
|
if (!ThrowType->isDependentType() &&
|
|
|
|
!ThrowType->isObjCObjectPointerType()) {
|
|
|
|
const PointerType *PT = ThrowType->getAs<PointerType>();
|
|
|
|
if (!PT || !PT->getPointeeType()->isVoidType())
|
2016-12-03 06:38:31 +08:00
|
|
|
return StmtError(Diag(AtLoc, diag::err_objc_throw_expects_object)
|
2010-04-23 05:44:01 +08:00
|
|
|
<< Throw->getType() << Throw->getSourceRange());
|
|
|
|
}
|
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) ObjCAtThrowStmt(AtLoc, Throw);
|
2010-04-23 05:44:01 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2011-01-27 15:10:08 +08:00
|
|
|
Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw,
|
2010-04-23 05:44:01 +08:00
|
|
|
Scope *CurScope) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().ObjCExceptions)
|
2011-02-20 07:53:54 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@throw";
|
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
if (!Throw) {
|
2015-03-09 10:34:29 +08:00
|
|
|
// @throw without an expression designates a rethrow (which must occur
|
2009-02-12 04:05:44 +08:00
|
|
|
// in the context of an @catch clause).
|
|
|
|
Scope *AtCatchParent = CurScope;
|
|
|
|
while (AtCatchParent && !AtCatchParent->isAtCatchScope())
|
|
|
|
AtCatchParent = AtCatchParent->getParent();
|
|
|
|
if (!AtCatchParent)
|
2016-12-03 06:38:31 +08:00
|
|
|
return StmtError(Diag(AtLoc, diag::err_rethrow_used_outside_catch));
|
2011-01-27 15:10:08 +08:00
|
|
|
}
|
2010-08-24 07:25:46 +08:00
|
|
|
return BuildObjCAtThrowStmt(AtLoc, Throw);
|
2007-11-07 10:00:49 +08:00
|
|
|
}
|
2007-11-02 23:39:31 +08:00
|
|
|
|
2011-07-28 05:50:02 +08:00
|
|
|
ExprResult
|
|
|
|
Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) {
|
|
|
|
ExprResult result = DefaultLvalueConversion(operand);
|
|
|
|
if (result.isInvalid())
|
|
|
|
return ExprError();
|
2014-05-29 18:55:11 +08:00
|
|
|
operand = result.get();
|
2010-12-15 12:42:30 +08:00
|
|
|
|
2009-04-21 14:11:25 +08:00
|
|
|
// Make sure the expression type is an ObjC pointer or "void *".
|
2011-07-28 05:50:02 +08:00
|
|
|
QualType type = operand->getType();
|
|
|
|
if (!type->isDependentType() &&
|
|
|
|
!type->isObjCObjectPointerType()) {
|
|
|
|
const PointerType *pointerType = type->getAs<PointerType>();
|
2014-08-13 00:20:36 +08:00
|
|
|
if (!pointerType || !pointerType->getPointeeType()->isVoidType()) {
|
|
|
|
if (getLangOpts().CPlusPlus) {
|
|
|
|
if (RequireCompleteType(atLoc, type,
|
|
|
|
diag::err_incomplete_receiver_type))
|
2016-12-03 06:38:31 +08:00
|
|
|
return Diag(atLoc, diag::err_objc_synchronized_expects_object)
|
2014-08-13 00:20:36 +08:00
|
|
|
<< type << operand->getSourceRange();
|
|
|
|
|
|
|
|
ExprResult result = PerformContextuallyConvertToObjCPointer(operand);
|
2016-10-07 07:12:58 +08:00
|
|
|
if (result.isInvalid())
|
|
|
|
return ExprError();
|
2014-08-13 00:20:36 +08:00
|
|
|
if (!result.isUsable())
|
2016-12-03 06:38:31 +08:00
|
|
|
return Diag(atLoc, diag::err_objc_synchronized_expects_object)
|
2014-08-13 00:20:36 +08:00
|
|
|
<< type << operand->getSourceRange();
|
|
|
|
|
|
|
|
operand = result.get();
|
|
|
|
} else {
|
2016-12-03 06:38:31 +08:00
|
|
|
return Diag(atLoc, diag::err_objc_synchronized_expects_object)
|
2014-08-13 00:20:36 +08:00
|
|
|
<< type << operand->getSourceRange();
|
|
|
|
}
|
|
|
|
}
|
2009-04-21 14:11:25 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-28 05:50:02 +08:00
|
|
|
// The operand to @synchronized is a full-expression.
|
2013-01-15 06:39:08 +08:00
|
|
|
return ActOnFinishFullExpr(operand);
|
2011-07-28 05:50:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult
|
|
|
|
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr,
|
|
|
|
Stmt *SyncBody) {
|
|
|
|
// We can't jump into or indirect-jump out of a @synchronized block.
|
|
|
|
getCurFunction()->setHasBranchProtectedScope();
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody);
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
2008-12-23 03:15:10 +08:00
|
|
|
|
|
|
|
/// ActOnCXXCatchBlock - Takes an exception declaration and a handler block
|
|
|
|
/// and creates a proper catch handler from them.
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2010-08-21 17:40:31 +08:00
|
|
|
Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl,
|
2010-08-24 07:25:46 +08:00
|
|
|
Stmt *HandlerBlock) {
|
2008-12-23 03:15:10 +08:00
|
|
|
// There's nothing to test that ActOnExceptionDecl didn't already test.
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context)
|
|
|
|
CXXCatchStmt(CatchLoc, cast_or_null<VarDecl>(ExDecl), HandlerBlock);
|
2008-12-23 03:15:10 +08:00
|
|
|
}
|
2008-12-23 05:35:02 +08:00
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
StmtResult
|
|
|
|
Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) {
|
|
|
|
getCurFunction()->setHasBranchProtectedScope();
|
2014-05-29 22:05:12 +08:00
|
|
|
return new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body);
|
2011-06-16 07:02:42 +08:00
|
|
|
}
|
|
|
|
|
2015-05-01 21:59:53 +08:00
|
|
|
namespace {
|
2015-04-08 08:05:29 +08:00
|
|
|
class CatchHandlerType {
|
|
|
|
QualType QT;
|
|
|
|
unsigned IsPointer : 1;
|
2009-07-30 01:15:45 +08:00
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
// This is a special constructor to be used only with DenseMapInfo's
|
|
|
|
// getEmptyKey() and getTombstoneKey() functions.
|
|
|
|
friend struct llvm::DenseMapInfo<CatchHandlerType>;
|
|
|
|
enum Unique { ForDenseMap };
|
|
|
|
CatchHandlerType(QualType QT, Unique) : QT(QT), IsPointer(false) {}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
public:
|
|
|
|
/// Used when creating a CatchHandlerType from a handler type; will determine
|
2015-06-19 09:52:53 +08:00
|
|
|
/// whether the type is a pointer or reference and will strip off the top
|
2015-04-08 08:05:29 +08:00
|
|
|
/// level pointer and cv-qualifiers.
|
|
|
|
CatchHandlerType(QualType Q) : QT(Q), IsPointer(false) {
|
|
|
|
if (QT->isPointerType())
|
|
|
|
IsPointer = true;
|
|
|
|
|
|
|
|
if (IsPointer || QT->isReferenceType())
|
|
|
|
QT = QT->getPointeeType();
|
|
|
|
QT = QT.getUnqualifiedType();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used when creating a CatchHandlerType from a base class type; pretends the
|
|
|
|
/// type passed in had the pointer qualifier, does not need to get an
|
|
|
|
/// unqualified type.
|
|
|
|
CatchHandlerType(QualType QT, bool IsPointer)
|
|
|
|
: QT(QT), IsPointer(IsPointer) {}
|
|
|
|
|
|
|
|
QualType underlying() const { return QT; }
|
|
|
|
bool isPointer() const { return IsPointer; }
|
|
|
|
|
|
|
|
friend bool operator==(const CatchHandlerType &LHS,
|
|
|
|
const CatchHandlerType &RHS) {
|
|
|
|
// If the pointer qualification does not match, we can return early.
|
|
|
|
if (LHS.IsPointer != RHS.IsPointer)
|
2015-02-16 06:18:04 +08:00
|
|
|
return false;
|
2015-04-08 08:05:29 +08:00
|
|
|
// Otherwise, check the underlying type without cv-qualifiers.
|
|
|
|
return LHS.QT == RHS.QT;
|
|
|
|
}
|
|
|
|
};
|
2015-05-01 21:59:53 +08:00
|
|
|
} // namespace
|
2015-04-08 08:05:29 +08:00
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
template <> struct DenseMapInfo<CatchHandlerType> {
|
|
|
|
static CatchHandlerType getEmptyKey() {
|
|
|
|
return CatchHandlerType(DenseMapInfo<QualType>::getEmptyKey(),
|
|
|
|
CatchHandlerType::ForDenseMap);
|
2009-07-30 01:15:45 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
static CatchHandlerType getTombstoneKey() {
|
|
|
|
return CatchHandlerType(DenseMapInfo<QualType>::getTombstoneKey(),
|
|
|
|
CatchHandlerType::ForDenseMap);
|
2015-02-16 06:00:28 +08:00
|
|
|
}
|
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
static unsigned getHashValue(const CatchHandlerType &Base) {
|
|
|
|
return DenseMapInfo<QualType>::getHashValue(Base.underlying());
|
2009-07-30 01:15:45 +08:00
|
|
|
}
|
2015-04-08 08:05:29 +08:00
|
|
|
|
|
|
|
static bool isEqual(const CatchHandlerType &LHS,
|
|
|
|
const CatchHandlerType &RHS) {
|
|
|
|
return LHS == RHS;
|
|
|
|
}
|
|
|
|
};
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2009-07-30 01:15:45 +08:00
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
namespace {
|
|
|
|
class CatchTypePublicBases {
|
|
|
|
ASTContext &Ctx;
|
|
|
|
const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &TypesToCheck;
|
|
|
|
const bool CheckAgainstPointer;
|
|
|
|
|
|
|
|
CXXCatchStmt *FoundHandler;
|
|
|
|
CanQualType FoundHandlerType;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CatchTypePublicBases(
|
|
|
|
ASTContext &Ctx,
|
|
|
|
const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &T, bool C)
|
|
|
|
: Ctx(Ctx), TypesToCheck(T), CheckAgainstPointer(C),
|
|
|
|
FoundHandler(nullptr) {}
|
|
|
|
|
|
|
|
CXXCatchStmt *getFoundHandler() const { return FoundHandler; }
|
|
|
|
CanQualType getFoundHandlerType() const { return FoundHandlerType; }
|
|
|
|
|
2015-07-25 23:07:25 +08:00
|
|
|
bool operator()(const CXXBaseSpecifier *S, CXXBasePath &) {
|
2015-04-08 08:05:29 +08:00
|
|
|
if (S->getAccessSpecifier() == AccessSpecifier::AS_public) {
|
2015-07-25 23:07:25 +08:00
|
|
|
CatchHandlerType Check(S->getType(), CheckAgainstPointer);
|
2016-02-13 23:49:17 +08:00
|
|
|
const auto &M = TypesToCheck;
|
2015-04-08 08:05:29 +08:00
|
|
|
auto I = M.find(Check);
|
|
|
|
if (I != M.end()) {
|
2015-07-25 23:07:25 +08:00
|
|
|
FoundHandler = I->second;
|
|
|
|
FoundHandlerType = Ctx.getCanonicalType(S->getType());
|
2015-04-08 08:05:29 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2010-07-27 05:25:24 +08:00
|
|
|
|
2008-12-23 05:35:02 +08:00
|
|
|
/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
|
|
|
|
/// handlers and creates a try statement from them.
|
2013-08-22 17:20:03 +08:00
|
|
|
StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
|
|
|
|
ArrayRef<Stmt *> Handlers) {
|
2011-02-23 11:46:46 +08:00
|
|
|
// Don't report an error if 'try' is used in system headers.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().CXXExceptions &&
|
2011-02-23 11:46:46 +08:00
|
|
|
!getSourceManager().isInSystemHeader(TryLoc))
|
2015-04-08 08:05:29 +08:00
|
|
|
Diag(TryLoc, diag::err_exceptions_disabled) << "try";
|
2011-02-20 03:26:44 +08:00
|
|
|
|
2016-09-29 06:45:54 +08:00
|
|
|
// Exceptions aren't allowed in CUDA device code.
|
|
|
|
if (getLangOpts().CUDA)
|
2016-10-14 02:45:08 +08:00
|
|
|
CUDADiagIfDeviceCode(TryLoc, diag::err_cuda_device_exceptions)
|
|
|
|
<< "try" << CurrentCUDATarget();
|
2016-09-29 06:45:54 +08:00
|
|
|
|
2014-06-03 18:16:47 +08:00
|
|
|
if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
|
|
|
|
Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try";
|
|
|
|
|
2015-02-06 02:56:03 +08:00
|
|
|
sema::FunctionScopeInfo *FSI = getCurFunction();
|
|
|
|
|
2015-02-03 06:15:31 +08:00
|
|
|
// C++ try is incompatible with SEH __try.
|
2015-02-06 02:56:03 +08:00
|
|
|
if (!getLangOpts().Borland && FSI->FirstSEHTryLoc.isValid()) {
|
2015-02-03 06:15:31 +08:00
|
|
|
Diag(TryLoc, diag::err_mixing_cxx_try_seh_try);
|
2015-02-06 02:56:03 +08:00
|
|
|
Diag(FSI->FirstSEHTryLoc, diag::note_conflicting_try_here) << "'__try'";
|
2015-02-03 06:15:31 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 17:20:03 +08:00
|
|
|
const unsigned NumHandlers = Handlers.size();
|
2015-04-08 08:05:29 +08:00
|
|
|
assert(!Handlers.empty() &&
|
2008-12-23 05:35:02 +08:00
|
|
|
"The parser shouldn't call this if there are no handlers.");
|
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> HandledTypes;
|
2009-09-09 23:08:12 +08:00
|
|
|
for (unsigned i = 0; i < NumHandlers; ++i) {
|
2015-04-08 08:05:29 +08:00
|
|
|
CXXCatchStmt *H = cast<CXXCatchStmt>(Handlers[i]);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
// Diagnose when the handler is a catch-all handler, but it isn't the last
|
|
|
|
// handler for the try block. [except.handle]p5. Also, skip exception
|
|
|
|
// declarations that are invalid, since we can't usefully report on them.
|
|
|
|
if (!H->getExceptionDecl()) {
|
|
|
|
if (i < NumHandlers - 1)
|
|
|
|
return StmtError(Diag(H->getLocStart(), diag::err_early_catch_all));
|
|
|
|
continue;
|
|
|
|
} else if (H->getExceptionDecl()->isInvalidDecl())
|
2009-07-30 01:15:45 +08:00
|
|
|
continue;
|
2015-02-16 06:18:04 +08:00
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
// Walk the type hierarchy to diagnose when this type has already been
|
|
|
|
// handled (duplication), or cannot be handled (derivation inversion). We
|
|
|
|
// ignore top-level cv-qualifiers, per [except.handle]p3
|
2015-04-08 08:13:33 +08:00
|
|
|
CatchHandlerType HandlerCHT =
|
|
|
|
(QualType)Context.getCanonicalType(H->getCaughtType());
|
2015-04-08 08:05:29 +08:00
|
|
|
|
|
|
|
// We can ignore whether the type is a reference or a pointer; we need the
|
|
|
|
// underlying declaration type in order to get at the underlying record
|
|
|
|
// decl, if there is one.
|
|
|
|
QualType Underlying = HandlerCHT.underlying();
|
|
|
|
if (auto *RD = Underlying->getAsCXXRecordDecl()) {
|
|
|
|
if (!RD->hasDefinition())
|
|
|
|
continue;
|
|
|
|
// Check that none of the public, unambiguous base classes are in the
|
|
|
|
// map ([except.handle]p1). Give the base classes the same pointer
|
|
|
|
// qualification as the original type we are basing off of. This allows
|
|
|
|
// comparison against the handler type using the same top-level pointer
|
|
|
|
// as the original type.
|
|
|
|
CXXBasePaths Paths;
|
|
|
|
Paths.setOrigin(RD);
|
|
|
|
CatchTypePublicBases CTPB(Context, HandledTypes, HandlerCHT.isPointer());
|
2015-07-25 23:07:25 +08:00
|
|
|
if (RD->lookupInBases(CTPB, Paths)) {
|
2015-04-08 08:05:29 +08:00
|
|
|
const CXXCatchStmt *Problem = CTPB.getFoundHandler();
|
|
|
|
if (!Paths.isAmbiguous(CTPB.getFoundHandlerType())) {
|
|
|
|
Diag(H->getExceptionDecl()->getTypeSpecStartLoc(),
|
|
|
|
diag::warn_exception_caught_by_earlier_handler)
|
|
|
|
<< H->getCaughtType();
|
|
|
|
Diag(Problem->getExceptionDecl()->getTypeSpecStartLoc(),
|
|
|
|
diag::note_previous_exception_handler)
|
|
|
|
<< Problem->getCaughtType();
|
|
|
|
}
|
2009-07-30 01:15:45 +08:00
|
|
|
}
|
2015-04-08 08:05:29 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-04-08 08:05:29 +08:00
|
|
|
// Add the type the list of ones we have handled; diagnose if we've already
|
|
|
|
// handled it.
|
|
|
|
auto R = HandledTypes.insert(std::make_pair(H->getCaughtType(), H));
|
|
|
|
if (!R.second) {
|
|
|
|
const CXXCatchStmt *Problem = R.first->second;
|
|
|
|
Diag(H->getExceptionDecl()->getTypeSpecStartLoc(),
|
|
|
|
diag::warn_exception_caught_by_earlier_handler)
|
|
|
|
<< H->getCaughtType();
|
|
|
|
Diag(Problem->getExceptionDecl()->getTypeSpecStartLoc(),
|
|
|
|
diag::note_previous_exception_handler)
|
|
|
|
<< Problem->getCaughtType();
|
2009-07-30 01:15:45 +08:00
|
|
|
}
|
2008-12-23 05:35:02 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-02-06 02:56:03 +08:00
|
|
|
FSI->setHasCXXTry(TryLoc);
|
2010-08-01 08:26:45 +08:00
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers);
|
2008-12-23 05:35:02 +08:00
|
|
|
}
|
2011-04-28 09:08:34 +08:00
|
|
|
|
2015-02-03 06:15:31 +08:00
|
|
|
StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
|
|
|
|
Stmt *TryBlock, Stmt *Handler) {
|
2011-04-28 09:08:34 +08:00
|
|
|
assert(TryBlock && Handler);
|
|
|
|
|
2015-02-06 02:56:03 +08:00
|
|
|
sema::FunctionScopeInfo *FSI = getCurFunction();
|
|
|
|
|
2015-02-03 06:15:31 +08:00
|
|
|
// SEH __try is incompatible with C++ try. Borland appears to support this,
|
|
|
|
// however.
|
2015-02-06 02:56:03 +08:00
|
|
|
if (!getLangOpts().Borland) {
|
|
|
|
if (FSI->FirstCXXTryLoc.isValid()) {
|
|
|
|
Diag(TryLoc, diag::err_mixing_cxx_try_seh_try);
|
|
|
|
Diag(FSI->FirstCXXTryLoc, diag::note_conflicting_try_here) << "'try'";
|
|
|
|
}
|
2015-02-03 06:15:31 +08:00
|
|
|
}
|
|
|
|
|
2015-02-06 02:56:03 +08:00
|
|
|
FSI->setHasSEHTry(TryLoc);
|
|
|
|
|
|
|
|
// Reject __try in Obj-C methods, blocks, and captured decls, since we don't
|
|
|
|
// track if they use SEH.
|
|
|
|
DeclContext *DC = CurContext;
|
|
|
|
while (DC && !DC->isFunctionOrMethod())
|
|
|
|
DC = DC->getParent();
|
|
|
|
FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DC);
|
|
|
|
if (FD)
|
|
|
|
FD->setUsesSEHTry(true);
|
|
|
|
else
|
|
|
|
Diag(TryLoc, diag::err_seh_try_outside_functions);
|
2011-04-28 09:08:34 +08:00
|
|
|
|
2015-07-10 08:16:25 +08:00
|
|
|
// Reject __try on unsupported targets.
|
|
|
|
if (!Context.getTargetInfo().isSEHTrySupported())
|
|
|
|
Diag(TryLoc, diag::err_seh_try_unsupported);
|
|
|
|
|
2015-02-03 06:15:31 +08:00
|
|
|
return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult
|
|
|
|
Sema::ActOnSEHExceptBlock(SourceLocation Loc,
|
|
|
|
Expr *FilterExpr,
|
|
|
|
Stmt *Block) {
|
|
|
|
assert(FilterExpr && Block);
|
|
|
|
|
|
|
|
if(!FilterExpr->getType()->isIntegerType()) {
|
2011-06-02 08:47:27 +08:00
|
|
|
return StmtError(Diag(FilterExpr->getExprLoc(),
|
|
|
|
diag::err_filter_expression_integral)
|
|
|
|
<< FilterExpr->getType());
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return SEHExceptStmt::Create(Context,Loc,FilterExpr,Block);
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
|
|
|
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
void Sema::ActOnStartSEHFinallyBlock() {
|
|
|
|
CurrentSEHFinally.push_back(CurScope);
|
|
|
|
}
|
|
|
|
|
2015-03-09 11:17:15 +08:00
|
|
|
void Sema::ActOnAbortSEHFinallyBlock() {
|
|
|
|
CurrentSEHFinally.pop_back();
|
|
|
|
}
|
|
|
|
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
StmtResult Sema::ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block) {
|
2011-04-28 09:08:34 +08:00
|
|
|
assert(Block);
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
CurrentSEHFinally.pop_back();
|
|
|
|
return SEHFinallyStmt::Create(Context, Loc, Block);
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
2011-10-25 09:33:02 +08:00
|
|
|
|
2014-07-07 06:32:59 +08:00
|
|
|
StmtResult
|
|
|
|
Sema::ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope) {
|
2014-07-07 06:53:19 +08:00
|
|
|
Scope *SEHTryParent = CurScope;
|
|
|
|
while (SEHTryParent && !SEHTryParent->isSEHTryScope())
|
|
|
|
SEHTryParent = SEHTryParent->getParent();
|
|
|
|
if (!SEHTryParent)
|
|
|
|
return StmtError(Diag(Loc, diag::err_ms___leave_not_in___try));
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
CheckJumpOutOfSEHFinally(*this, Loc, *SEHTryParent);
|
2014-07-07 06:53:19 +08:00
|
|
|
|
2014-07-07 08:12:30 +08:00
|
|
|
return new (Context) SEHLeaveStmt(Loc);
|
2014-07-07 06:32:59 +08:00
|
|
|
}
|
|
|
|
|
2011-10-25 09:33:02 +08:00
|
|
|
StmtResult Sema::BuildMSDependentExistsStmt(SourceLocation KeywordLoc,
|
|
|
|
bool IsIfExists,
|
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
|
|
|
DeclarationNameInfo NameInfo,
|
|
|
|
Stmt *Nested)
|
|
|
|
{
|
|
|
|
return new (Context) MSDependentExistsStmt(KeywordLoc, IsIfExists,
|
2012-08-11 01:56:09 +08:00
|
|
|
QualifierLoc, NameInfo,
|
2011-10-25 09:33:02 +08:00
|
|
|
cast<CompoundStmt>(Nested));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-11 01:56:09 +08:00
|
|
|
StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc,
|
2011-10-25 09:33:02 +08:00
|
|
|
bool IsIfExists,
|
2012-08-11 01:56:09 +08:00
|
|
|
CXXScopeSpec &SS,
|
2011-10-25 09:33:02 +08:00
|
|
|
UnqualifiedId &Name,
|
|
|
|
Stmt *Nested) {
|
2012-08-11 01:56:09 +08:00
|
|
|
return BuildMSDependentExistsStmt(KeywordLoc, IsIfExists,
|
2011-10-25 09:33:02 +08:00
|
|
|
SS.getWithLocInContext(Context),
|
|
|
|
GetNameFromUnqualifiedId(Name),
|
|
|
|
Nested);
|
|
|
|
}
|
2013-04-17 03:37:38 +08:00
|
|
|
|
|
|
|
RecordDecl*
|
2013-05-04 03:00:33 +08:00
|
|
|
Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc,
|
|
|
|
unsigned NumParams) {
|
2013-04-17 03:37:38 +08:00
|
|
|
DeclContext *DC = CurContext;
|
|
|
|
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
|
|
|
|
DC = DC->getParent();
|
|
|
|
|
2014-05-26 14:22:03 +08:00
|
|
|
RecordDecl *RD = nullptr;
|
2013-04-17 03:37:38 +08:00
|
|
|
if (getLangOpts().CPlusPlus)
|
2014-05-26 14:22:03 +08:00
|
|
|
RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc,
|
|
|
|
/*Id=*/nullptr);
|
2013-04-17 03:37:38 +08:00
|
|
|
else
|
2014-05-26 14:22:03 +08:00
|
|
|
RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/nullptr);
|
2013-04-17 03:37:38 +08:00
|
|
|
|
2014-10-29 20:21:55 +08:00
|
|
|
RD->setCapturedRecord();
|
2013-04-17 03:37:38 +08:00
|
|
|
DC->addDecl(RD);
|
|
|
|
RD->setImplicit();
|
|
|
|
RD->startDefinition();
|
|
|
|
|
2014-05-06 18:08:46 +08:00
|
|
|
assert(NumParams > 0 && "CapturedStmt requires context parameter");
|
2013-05-04 03:00:33 +08:00
|
|
|
CD = CapturedDecl::Create(Context, CurContext, NumParams);
|
2013-04-17 03:37:38 +08:00
|
|
|
DC->addDecl(CD);
|
|
|
|
return RD;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void buildCapturedStmtCaptureList(
|
|
|
|
SmallVectorImpl<CapturedStmt::Capture> &Captures,
|
|
|
|
SmallVectorImpl<Expr *> &CaptureInits,
|
|
|
|
ArrayRef<CapturingScopeInfo::Capture> Candidates) {
|
|
|
|
|
|
|
|
typedef ArrayRef<CapturingScopeInfo::Capture>::const_iterator CaptureIter;
|
|
|
|
for (CaptureIter Cap = Candidates.begin(); Cap != Candidates.end(); ++Cap) {
|
|
|
|
|
|
|
|
if (Cap->isThisCapture()) {
|
|
|
|
Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
|
|
|
|
CapturedStmt::VCK_This));
|
2013-05-16 14:20:58 +08:00
|
|
|
CaptureInits.push_back(Cap->getInitExpr());
|
2013-04-17 03:37:38 +08:00
|
|
|
continue;
|
2014-10-29 20:21:55 +08:00
|
|
|
} else if (Cap->isVLATypeCapture()) {
|
|
|
|
Captures.push_back(
|
|
|
|
CapturedStmt::Capture(Cap->getLocation(), CapturedStmt::VCK_VLAType));
|
|
|
|
CaptureInits.push_back(nullptr);
|
|
|
|
continue;
|
2013-04-17 03:37:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
|
2015-12-03 01:44:43 +08:00
|
|
|
Cap->isReferenceCapture()
|
|
|
|
? CapturedStmt::VCK_ByRef
|
|
|
|
: CapturedStmt::VCK_ByCopy,
|
2013-04-17 03:37:38 +08:00
|
|
|
Cap->getVariable()));
|
2013-05-16 14:20:58 +08:00
|
|
|
CaptureInits.push_back(Cap->getInitExpr());
|
2013-04-17 03:37:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
|
2013-05-04 11:59:06 +08:00
|
|
|
CapturedRegionKind Kind,
|
|
|
|
unsigned NumParams) {
|
2014-05-06 18:08:46 +08:00
|
|
|
CapturedDecl *CD = nullptr;
|
2013-05-04 03:00:33 +08:00
|
|
|
RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, NumParams);
|
2013-04-17 03:37:38 +08:00
|
|
|
|
2014-05-06 18:08:46 +08:00
|
|
|
// Build the context parameter
|
|
|
|
DeclContext *DC = CapturedDecl::castToDeclContext(CD);
|
|
|
|
IdentifierInfo *ParamName = &Context.Idents.get("__context");
|
|
|
|
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
|
2017-06-09 21:40:18 +08:00
|
|
|
auto *Param =
|
|
|
|
ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
|
|
|
|
ImplicitParamDecl::CapturedContext);
|
2014-05-06 18:08:46 +08:00
|
|
|
DC->addDecl(Param);
|
|
|
|
|
|
|
|
CD->setContextParam(0, Param);
|
|
|
|
|
|
|
|
// Enter the capturing scope for this captured region.
|
|
|
|
PushCapturedRegionScope(CurScope, CD, RD, Kind);
|
|
|
|
|
|
|
|
if (CurScope)
|
|
|
|
PushDeclContext(CurScope, CD);
|
|
|
|
else
|
|
|
|
CurContext = CD;
|
|
|
|
|
2017-04-02 05:30:49 +08:00
|
|
|
PushExpressionEvaluationContext(
|
|
|
|
ExpressionEvaluationContext::PotentiallyEvaluated);
|
2014-05-06 18:08:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
|
|
|
|
CapturedRegionKind Kind,
|
|
|
|
ArrayRef<CapturedParamNameType> Params) {
|
|
|
|
CapturedDecl *CD = nullptr;
|
|
|
|
RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, Params.size());
|
|
|
|
|
|
|
|
// Build the context parameter
|
|
|
|
DeclContext *DC = CapturedDecl::castToDeclContext(CD);
|
|
|
|
bool ContextIsFound = false;
|
|
|
|
unsigned ParamNum = 0;
|
|
|
|
for (ArrayRef<CapturedParamNameType>::iterator I = Params.begin(),
|
|
|
|
E = Params.end();
|
|
|
|
I != E; ++I, ++ParamNum) {
|
|
|
|
if (I->second.isNull()) {
|
|
|
|
assert(!ContextIsFound &&
|
|
|
|
"null type has been found already for '__context' parameter");
|
|
|
|
IdentifierInfo *ParamName = &Context.Idents.get("__context");
|
|
|
|
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
|
2017-06-09 21:40:18 +08:00
|
|
|
auto *Param =
|
|
|
|
ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
|
|
|
|
ImplicitParamDecl::CapturedContext);
|
2014-05-06 18:08:46 +08:00
|
|
|
DC->addDecl(Param);
|
|
|
|
CD->setContextParam(ParamNum, Param);
|
|
|
|
ContextIsFound = true;
|
|
|
|
} else {
|
|
|
|
IdentifierInfo *ParamName = &Context.Idents.get(I->first);
|
2017-06-09 21:40:18 +08:00
|
|
|
auto *Param =
|
|
|
|
ImplicitParamDecl::Create(Context, DC, Loc, ParamName, I->second,
|
|
|
|
ImplicitParamDecl::CapturedContext);
|
2014-05-06 18:08:46 +08:00
|
|
|
DC->addDecl(Param);
|
|
|
|
CD->setParam(ParamNum, Param);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(ContextIsFound && "no null type for '__context' parameter");
|
2014-05-14 18:40:54 +08:00
|
|
|
if (!ContextIsFound) {
|
|
|
|
// Add __context implicitly if it is not specified.
|
|
|
|
IdentifierInfo *ParamName = &Context.Idents.get("__context");
|
|
|
|
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
|
2017-06-09 21:40:18 +08:00
|
|
|
auto *Param =
|
|
|
|
ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
|
|
|
|
ImplicitParamDecl::CapturedContext);
|
2014-05-14 18:40:54 +08:00
|
|
|
DC->addDecl(Param);
|
|
|
|
CD->setContextParam(ParamNum, Param);
|
|
|
|
}
|
2013-04-17 03:37:38 +08:00
|
|
|
// Enter the capturing scope for this captured region.
|
|
|
|
PushCapturedRegionScope(CurScope, CD, RD, Kind);
|
|
|
|
|
|
|
|
if (CurScope)
|
|
|
|
PushDeclContext(CurScope, CD);
|
|
|
|
else
|
|
|
|
CurContext = CD;
|
|
|
|
|
2017-04-02 05:30:49 +08:00
|
|
|
PushExpressionEvaluationContext(
|
|
|
|
ExpressionEvaluationContext::PotentiallyEvaluated);
|
2013-04-17 03:37:38 +08:00
|
|
|
}
|
|
|
|
|
2013-05-04 11:59:06 +08:00
|
|
|
void Sema::ActOnCapturedRegionError() {
|
2013-04-17 03:37:38 +08:00
|
|
|
DiscardCleanupsInEvaluationContext();
|
|
|
|
PopExpressionEvaluationContext();
|
|
|
|
|
|
|
|
CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
|
|
|
|
RecordDecl *Record = RSI->TheRecordDecl;
|
|
|
|
Record->setInvalidDecl();
|
|
|
|
|
2014-03-10 21:43:55 +08:00
|
|
|
SmallVector<Decl*, 4> Fields(Record->fields());
|
2014-05-06 18:08:46 +08:00
|
|
|
ActOnFields(/*Scope=*/nullptr, Record->getLocation(), Record, Fields,
|
|
|
|
SourceLocation(), SourceLocation(), /*AttributeList=*/nullptr);
|
2013-04-17 03:37:38 +08:00
|
|
|
|
2013-05-04 11:59:06 +08:00
|
|
|
PopDeclContext();
|
2013-04-17 03:37:38 +08:00
|
|
|
PopFunctionScopeInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
|
|
|
|
CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
|
|
|
|
|
|
|
|
SmallVector<CapturedStmt::Capture, 4> Captures;
|
|
|
|
SmallVector<Expr *, 4> CaptureInits;
|
|
|
|
buildCapturedStmtCaptureList(Captures, CaptureInits, RSI->Captures);
|
|
|
|
|
|
|
|
CapturedDecl *CD = RSI->TheCapturedDecl;
|
|
|
|
RecordDecl *RD = RSI->TheRecordDecl;
|
|
|
|
|
2016-05-17 16:55:33 +08:00
|
|
|
CapturedStmt *Res = CapturedStmt::Create(
|
|
|
|
getASTContext(), S, static_cast<CapturedRegionKind>(RSI->CapRegionKind),
|
|
|
|
Captures, CaptureInits, CD, RD);
|
2013-04-17 03:37:38 +08:00
|
|
|
|
|
|
|
CD->setBody(Res->getCapturedStmt());
|
|
|
|
RD->completeDefinition();
|
|
|
|
|
2013-05-04 11:59:06 +08:00
|
|
|
DiscardCleanupsInEvaluationContext();
|
|
|
|
PopExpressionEvaluationContext();
|
|
|
|
|
2013-04-17 03:37:38 +08:00
|
|
|
PopDeclContext();
|
|
|
|
PopFunctionScopeInfo();
|
|
|
|
|
2014-05-29 22:05:12 +08:00
|
|
|
return Res;
|
2013-04-17 03:37:38 +08:00
|
|
|
}
|