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"
|
2010-08-24 16:50:51 +08:00
|
|
|
#include "clang/Sema/Scope.h"
|
2010-08-25 16:40:02 +08:00
|
|
|
#include "clang/Sema/ScopeInfo.h"
|
2010-08-13 04:07:10 +08:00
|
|
|
#include "clang/Sema/Initialization.h"
|
2011-04-15 06:09:26 +08:00
|
|
|
#include "clang/Sema/Lookup.h"
|
2007-08-23 13:46:52 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2011-11-11 11:57:31 +08:00
|
|
|
#include "clang/AST/CharUnits.h"
|
2008-08-11 13:35:13 +08:00
|
|
|
#include "clang/AST/DeclObjC.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"
|
2009-04-26 09:32:48 +08:00
|
|
|
#include "clang/AST/StmtObjC.h"
|
|
|
|
#include "clang/AST/StmtCXX.h"
|
2010-04-07 06:24:14 +08:00
|
|
|
#include "clang/AST/TypeLoc.h"
|
2009-11-23 21:46:08 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2007-11-25 08:25:21 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2011-02-22 05:40:33 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2009-07-30 01:15:45 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
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
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Sema::ActOnExprStmt(FullExprArg expr) {
|
2010-08-24 07:25:46 +08:00
|
|
|
Expr *E = expr.get();
|
2010-12-15 09:34:56 +08:00
|
|
|
if (!E) // FIXME: FullExprArg has no error state?
|
|
|
|
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.
|
2008-12-21 20:04:03 +08:00
|
|
|
return Owned(static_cast<Stmt*>(E));
|
2007-06-27 13:38:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-27 13:04:02 +08:00
|
|
|
StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc,
|
2011-09-02 05:53:45 +08:00
|
|
|
bool HasLeadingEmptyMacro) {
|
|
|
|
return Owned(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) {
|
2009-04-13 04:13:14 +08:00
|
|
|
DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
|
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
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
return Owned(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) {
|
|
|
|
DeclGroupRef DG = dg.getAsVal<DeclGroupRef>();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2009-11-20 06:12:37 +08:00
|
|
|
// If we have an invalid decl, just return.
|
|
|
|
if (DG.isNull() || !DG.isSingleDecl()) return;
|
2011-06-16 07:02:42 +08:00
|
|
|
VarDecl *var = cast<VarDecl>(DG.getSingleDecl());
|
|
|
|
|
2009-11-20 06:12:37 +08:00
|
|
|
// suppress any potential 'unused variable' warning.
|
2011-06-16 07:02:42 +08:00
|
|
|
var->setUsed();
|
|
|
|
|
2011-06-17 14:42:21 +08:00
|
|
|
// foreach variables are never actually initialized in the way that
|
|
|
|
// the parser came up with.
|
|
|
|
var->setInit(0);
|
|
|
|
|
|
|
|
// 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.
|
2011-06-16 07:02:42 +08:00
|
|
|
if (getLangOptions().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
|
|
|
}
|
|
|
|
|
2011-08-17 17:34:37 +08:00
|
|
|
/// \brief Diagnose unused '==' and '!=' as likely typos 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;
|
2011-08-17 16:38:11 +08:00
|
|
|
bool IsNotEqual, CanAssign;
|
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)) {
|
|
|
|
if (Op->getOpcode() != BO_EQ && Op->getOpcode() != BO_NE)
|
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
|
|
|
|
|
|
|
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)) {
|
|
|
|
if (Op->getOperator() != OO_EqualEqual &&
|
|
|
|
Op->getOperator() != OO_ExclaimEqual)
|
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
|
|
|
|
|
|
|
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.
|
|
|
|
if (Loc.isMacroID())
|
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)
|
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
|
|
|
<< (unsigned)IsNotEqual << E->getSourceRange();
|
|
|
|
|
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.
|
|
|
|
if (CanAssign) {
|
|
|
|
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;
|
|
|
|
|
|
|
|
SourceLocation Loc;
|
|
|
|
SourceRange R1, R2;
|
2009-11-04 07:25:48 +08:00
|
|
|
if (!E->isUnusedResultAWarning(Loc, R1, R2, Context))
|
2009-07-31 06:17:18 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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;
|
|
|
|
|
2010-12-04 11:47:34 +08:00
|
|
|
E = E->IgnoreParenImpCasts();
|
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
|
|
|
|
// a more specific message to make it clear what is happening.
|
2009-12-21 07:11:08 +08:00
|
|
|
if (const Decl *FD = CE->getCalleeDecl()) {
|
2009-10-13 12:53:48 +08:00
|
|
|
if (FD->getAttr<WarnUnusedResultAttr>()) {
|
2011-08-05 07:11:04 +08:00
|
|
|
Diag(Loc, diag::warn_unused_result) << R1 << R2;
|
2009-10-13 12:53:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (FD->getAttr<PureAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (FD->getAttr<ConstAttr>()) {
|
|
|
|
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const";
|
|
|
|
return;
|
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
}
|
2010-12-02 09:19:52 +08:00
|
|
|
} else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
|
2011-06-16 07:02:42 +08:00
|
|
|
if (getLangOptions().ObjCAutoRefCount && ME->isDelegateInitCall()) {
|
|
|
|
Diag(Loc, diag::err_arc_unused_init_message) << R1;
|
|
|
|
return;
|
|
|
|
}
|
2010-03-31 02:22:15 +08:00
|
|
|
const ObjCMethodDecl *MD = ME->getMethodDecl();
|
|
|
|
if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
|
2011-08-05 07:11:04 +08:00
|
|
|
Diag(Loc, diag::warn_unused_result) << R1 << R2;
|
2010-03-31 02:22:15 +08:00
|
|
|
return;
|
|
|
|
}
|
2011-11-06 17:01:30 +08:00
|
|
|
} else if (isa<PseudoObjectExpr>(E)) {
|
2010-12-02 09:19:52 +08:00
|
|
|
DiagID = diag::warn_unused_property_expr;
|
2010-04-17 06:09:46 +08:00
|
|
|
} else if (const CXXFunctionalCastExpr *FC
|
|
|
|
= dyn_cast<CXXFunctionalCastExpr>(E)) {
|
|
|
|
if (isa<CXXConstructExpr>(FC->getSubExpr()) ||
|
|
|
|
isa<CXXTemporaryObjectExpr>(FC->getSubExpr()))
|
|
|
|
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) {
|
|
|
|
PointerTypeLoc TL = cast<PointerTypeLoc>(TI->getTypeLoc());
|
|
|
|
|
|
|
|
Diag(Loc, diag::warn_unused_voidptr)
|
|
|
|
<< FixItHint::CreateRemoval(TL.getStarLoc());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-23 09:52:04 +08:00
|
|
|
DiagRuntimeBehavior(Loc, 0, PDiag(DiagID) << R1 << R2);
|
2009-07-31 06:17:18 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2007-09-16 22:56:35 +08:00
|
|
|
Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
|
2008-12-21 20:04:03 +08:00
|
|
|
MultiStmtArg elts, bool isStmtExpr) {
|
|
|
|
unsigned NumElts = elts.size();
|
|
|
|
Stmt **Elts = reinterpret_cast<Stmt**>(elts.release());
|
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.
|
|
|
|
if (!getLangOptions().C99 && !getLangOptions().CPlusPlus) {
|
|
|
|
// 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
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, 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) {
|
2010-08-24 07:25:46 +08:00
|
|
|
assert((LHSVal != 0) && "missing expression in case statement");
|
2008-12-29 00:13:43 +08:00
|
|
|
|
2007-05-09 05:09:37 +08:00
|
|
|
// C99 6.8.4.2p3: The expression shall be an integer constant.
|
2009-09-09 23:08:12 +08:00
|
|
|
// However, GCC allows any evaluatable integer expression.
|
|
|
|
if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
|
2009-05-16 07:57:33 +08:00
|
|
|
VerifyIntegerConstantExpression(LHSVal))
|
2009-03-04 12:23:07 +08:00
|
|
|
return StmtError();
|
2007-05-09 05:09:37 +08:00
|
|
|
|
2007-07-18 10:28:47 +08:00
|
|
|
// GCC extension: The expression shall be an integer constant.
|
2008-12-29 00:13:43 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
|
|
|
|
VerifyIntegerConstantExpression(RHSVal)) {
|
2007-08-23 13:46:52 +08:00
|
|
|
RHSVal = 0; // Recover by just forgetting about it.
|
2008-12-29 00:13:43 +08:00
|
|
|
}
|
|
|
|
|
2010-08-25 16:40:02 +08:00
|
|
|
if (getCurFunction()->SwitchStack.empty()) {
|
2007-07-24 01:05:23 +08:00
|
|
|
Diag(CaseLoc, diag::err_case_not_in_switch);
|
2009-03-04 12:23:07 +08:00
|
|
|
return StmtError();
|
2007-07-24 01:05:23 +08:00
|
|
|
}
|
2007-06-03 09:44:43 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
|
|
|
|
ColonLoc);
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->SwitchStack.back()->addSwitchCase(CS);
|
2008-12-29 00:13:43 +08:00
|
|
|
return Owned(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);
|
2008-12-29 00:13:43 +08:00
|
|
|
return Owned(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);
|
2008-12-29 00:13:43 +08:00
|
|
|
return Owned(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);
|
2009-01-11 08:38:46 +08:00
|
|
|
return Owned(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);
|
2011-03-04 02:24:14 +08:00
|
|
|
if (!TheDecl->isGnuLocal())
|
|
|
|
TheDecl->setLocation(IdentLoc);
|
2011-02-17 15:39:24 +08:00
|
|
|
return Owned(LS);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2010-08-21 17:40:31 +08:00
|
|
|
Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
|
2010-11-20 10:04:01 +08:00
|
|
|
Stmt *thenStmt, SourceLocation ElseLoc,
|
|
|
|
Stmt *elseStmt) {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult CondResult(CondVal.release());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-24 07:44:04 +08:00
|
|
|
VarDecl *ConditionVar = 0;
|
2010-08-21 17:40:31 +08:00
|
|
|
if (CondVar) {
|
|
|
|
ConditionVar = cast<VarDecl>(CondVar);
|
2010-05-07 01:25:47 +08:00
|
|
|
CondResult = CheckConditionVariable(ConditionVar, IfLoc, true);
|
2009-11-25 08:27:52 +08:00
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
2009-11-24 07:44:04 +08:00
|
|
|
}
|
2009-11-25 08:27:52 +08:00
|
|
|
Expr *ConditionExpr = CondResult.takeAs<Expr>();
|
|
|
|
if (!ConditionExpr)
|
|
|
|
return StmtError();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2009-07-31 06:39:03 +08:00
|
|
|
DiagnoseUnusedExprResult(thenStmt);
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2007-10-11 04:50:11 +08:00
|
|
|
// Warn if the if block has a null body without an else value.
|
|
|
|
// this helps prevent bugs due to typos, such as
|
|
|
|
// if (condition);
|
|
|
|
// do_stuff();
|
2010-09-16 08:37:05 +08:00
|
|
|
//
|
2010-08-24 07:25:46 +08:00
|
|
|
if (!elseStmt) {
|
2007-10-11 04:50:11 +08:00
|
|
|
if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt))
|
2010-11-20 04:54:25 +08:00
|
|
|
// But do not warn if the body is a macro that expands to nothing, e.g:
|
|
|
|
//
|
|
|
|
// #define CALL(x)
|
|
|
|
// if (condition)
|
|
|
|
// CALL(0);
|
|
|
|
//
|
2010-11-20 10:04:01 +08:00
|
|
|
if (!stmt->hasLeadingEmptyMacro())
|
2010-09-16 08:37:05 +08:00
|
|
|
Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
|
2007-10-11 04:50:11 +08:00
|
|
|
}
|
|
|
|
|
2009-07-31 06:39:03 +08:00
|
|
|
DiagnoseUnusedExprResult(elseStmt);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-01-27 15:10:08 +08:00
|
|
|
return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr,
|
2010-11-20 10:04:01 +08:00
|
|
|
thenStmt, ElseLoc, elseStmt));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
|
|
|
|
/// the specified width and sign. If an overflow occurs, detect it and emit
|
|
|
|
/// the specified diagnostic.
|
|
|
|
void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
|
|
|
|
unsigned NewWidth, bool NewSign,
|
2009-09-09 23:08:12 +08:00
|
|
|
SourceLocation Loc,
|
2007-08-23 13:46:52 +08:00
|
|
|
unsigned DiagID) {
|
|
|
|
// Perform a conversion to the promoted condition type if needed.
|
|
|
|
if (NewWidth > Val.getBitWidth()) {
|
|
|
|
// If this is an extension, just do it.
|
2010-12-07 16:25:34 +08:00
|
|
|
Val = Val.extend(NewWidth);
|
2007-08-23 13:46:52 +08:00
|
|
|
Val.setIsSigned(NewSign);
|
2010-03-01 09:04:55 +08:00
|
|
|
|
|
|
|
// If the input was signed and negative and the output is
|
|
|
|
// unsigned, don't bother to warn: this is implementation-defined
|
|
|
|
// behavior.
|
|
|
|
// FIXME: Introduce a second, default-ignored warning for this case?
|
2007-08-23 13:46:52 +08:00
|
|
|
} else if (NewWidth < Val.getBitWidth()) {
|
|
|
|
// If this is a truncation, check for overflow.
|
|
|
|
llvm::APSInt ConvVal(Val);
|
2010-12-07 16:25:34 +08:00
|
|
|
ConvVal = ConvVal.trunc(NewWidth);
|
2007-08-24 06:08:35 +08:00
|
|
|
ConvVal.setIsSigned(NewSign);
|
2010-12-07 16:25:34 +08:00
|
|
|
ConvVal = ConvVal.extend(Val.getBitWidth());
|
2007-08-24 06:08:35 +08:00
|
|
|
ConvVal.setIsSigned(Val.isSigned());
|
2007-08-23 13:46:52 +08:00
|
|
|
if (ConvVal != Val)
|
2008-11-20 14:06:08 +08:00
|
|
|
Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// Regardless of whether a diagnostic was emitted, really do the
|
|
|
|
// truncation.
|
2010-12-07 16:25:34 +08:00
|
|
|
Val = Val.trunc(NewWidth);
|
2007-08-24 06:08:35 +08:00
|
|
|
Val.setIsSigned(NewSign);
|
2007-08-23 13:46:52 +08:00
|
|
|
} else if (NewSign != Val.isSigned()) {
|
|
|
|
// Convert the sign to match the sign of the condition. This can cause
|
|
|
|
// overflow as well: unsigned(INTMIN)
|
2011-01-27 15:10:08 +08:00
|
|
|
// We don't diagnose this overflow, because it is implementation-defined
|
2010-02-18 08:56:01 +08:00
|
|
|
// behavior.
|
|
|
|
// FIXME: Introduce a second, default-ignored warning for this case?
|
2007-08-23 13:46:52 +08:00
|
|
|
llvm::APSInt OldVal(Val);
|
|
|
|
Val.setIsSigned(NewSign);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
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.
|
2011-08-06 15:30:58 +08:00
|
|
|
static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) {
|
|
|
|
if (ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(expr))
|
|
|
|
expr = cleanups->getSubExpr();
|
|
|
|
while (ImplicitCastExpr *impcast = dyn_cast<ImplicitCastExpr>(expr)) {
|
|
|
|
if (impcast->getCastKind() != CK_IntegralCast) break;
|
|
|
|
expr = impcast->getSubExpr();
|
2009-10-17 00:45:22 +08:00
|
|
|
}
|
|
|
|
return expr->getType();
|
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2011-01-27 15:10:08 +08:00
|
|
|
Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *CondVar) {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult CondResult;
|
2010-08-24 07:25:46 +08:00
|
|
|
|
2010-05-07 01:25:47 +08:00
|
|
|
VarDecl *ConditionVar = 0;
|
2010-08-21 17:40:31 +08:00
|
|
|
if (CondVar) {
|
|
|
|
ConditionVar = cast<VarDecl>(CondVar);
|
2010-08-24 07:25:46 +08:00
|
|
|
CondResult = CheckConditionVariable(ConditionVar, SourceLocation(), false);
|
|
|
|
if (CondResult.isInvalid())
|
2010-05-07 01:25:47 +08:00
|
|
|
return StmtError();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
Cond = CondResult.release();
|
2010-05-07 01:25:47 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
if (!Cond)
|
2010-05-07 01:25:47 +08:00
|
|
|
return StmtError();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-10-26 01:37:35 +08:00
|
|
|
CondResult = CheckPlaceholderExpr(Cond);
|
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
CondResult
|
2011-10-28 04:06:32 +08:00
|
|
|
= ConvertToIntegralOrEnumerationType(SwitchLoc, CondResult.take(),
|
2010-06-30 07:17:37 +08:00
|
|
|
PDiag(diag::err_typecheck_statement_requires_integer),
|
|
|
|
PDiag(diag::err_switch_incomplete_class_type)
|
2010-08-24 07:25:46 +08:00
|
|
|
<< Cond->getSourceRange(),
|
2010-06-30 07:17:37 +08:00
|
|
|
PDiag(diag::err_switch_explicit_conversion),
|
|
|
|
PDiag(diag::note_switch_conversion),
|
|
|
|
PDiag(diag::err_switch_multiple_conversions),
|
2010-06-30 08:20:43 +08:00
|
|
|
PDiag(diag::note_switch_conversion),
|
|
|
|
PDiag(0));
|
2010-08-24 07:25:46 +08:00
|
|
|
if (CondResult.isInvalid()) return StmtError();
|
|
|
|
Cond = CondResult.take();
|
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.
|
|
|
|
CondResult = UsualUnaryConversions(Cond);
|
|
|
|
if (CondResult.isInvalid()) return StmtError();
|
|
|
|
Cond = CondResult.take();
|
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
if (!CondVar) {
|
2010-10-08 10:01:28 +08:00
|
|
|
CheckImplicitConversions(Cond, SwitchLoc);
|
2010-12-06 16:20:24 +08:00
|
|
|
CondResult = MaybeCreateExprWithCleanups(Cond);
|
2010-08-24 07:25:46 +08:00
|
|
|
if (CondResult.isInvalid())
|
2010-05-07 01:25:47 +08:00
|
|
|
return StmtError();
|
2010-08-24 07:25:46 +08:00
|
|
|
Cond = CondResult.take();
|
2010-05-07 01:25:47 +08:00
|
|
|
}
|
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
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond);
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->SwitchStack.push_back(SS);
|
2010-05-07 01:25:47 +08:00
|
|
|
return Owned(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) {
|
|
|
|
if (Val.getBitWidth() < BitWidth)
|
2010-12-07 16:25:34 +08:00
|
|
|
Val = Val.extend(BitWidth);
|
2010-10-02 06:05:14 +08:00
|
|
|
else if (Val.getBitWidth() > BitWidth)
|
2010-12-07 16:25:34 +08:00
|
|
|
Val = Val.trunc(BitWidth);
|
2010-10-02 06:05:14 +08:00
|
|
|
Val.setIsSigned(IsSigned);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2007-09-02 05:08:38 +08:00
|
|
|
SS->setBody(BodyStmt, SwitchLoc);
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->SwitchStack.pop_back();
|
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
|
|
|
|
|
|
|
Expr *CondExprBeforePromotion = CondExpr;
|
|
|
|
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
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// Get the bitwidth of the switched-on value before promotions. We must
|
|
|
|
// 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();
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned CondWidth
|
2011-02-24 15:31:28 +08:00
|
|
|
= HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
|
2011-05-21 00:38:50 +08:00
|
|
|
bool CondIsSigned
|
|
|
|
= 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
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
DefaultStmt *TheDefaultStmt = 0;
|
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
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// We already verified that the expression has a i-c-e value (C99
|
|
|
|
// 6.8.4.2p3) - get that value now.
|
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
|
|
|
|
2011-10-11 02:28:20 +08:00
|
|
|
llvm::APSInt LoVal = Lo->EvaluateKnownConstInt(Context);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-23 13:46:52 +08:00
|
|
|
// Convert the value to the same width/sign as the condition.
|
|
|
|
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
|
2010-10-02 06:05:14 +08:00
|
|
|
Lo->getLocStart(),
|
2007-08-23 13:46:52 +08:00
|
|
|
diag::warn_case_value_overflow);
|
2007-07-18 10:28:47 +08:00
|
|
|
|
2008-01-17 03:17:22 +08:00
|
|
|
// If the LHS is not the same type as the condition, insert an implicit
|
|
|
|
// cast.
|
2011-10-28 06:11:44 +08:00
|
|
|
// FIXME: In C++11, the value is a converted constant expression of the
|
|
|
|
// promoted type of the switch condition.
|
|
|
|
Lo = DefaultLvalueConversion(Lo).take();
|
2011-04-09 02:41:53 +08:00
|
|
|
Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
|
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) {
|
2011-10-29 08:50:52 +08:00
|
|
|
HasConstantCond
|
2011-12-29 03:48:30 +08:00
|
|
|
= CondExprBeforePromotion->EvaluateAsInt(ConstantCondValue, Context,
|
|
|
|
Expr::SE_AllowSideEffects);
|
|
|
|
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.
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(CaseVals[i].second->getLHS()->getLocStart(),
|
2010-05-18 11:19:21 +08:00
|
|
|
diag::err_duplicate_case) << CaseVals[i].first.toString(10);
|
|
|
|
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();
|
2011-10-11 02:28:20 +08:00
|
|
|
llvm::APSInt HiVal = Hi->EvaluateKnownConstInt(Context);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-16 07:57:33 +08:00
|
|
|
// Convert the value to the same width/sign as the condition.
|
|
|
|
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
|
2010-10-02 06:05:14 +08:00
|
|
|
Hi->getLocStart(),
|
2009-05-16 07:57:33 +08:00
|
|
|
diag::warn_case_value_overflow);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-28 06:11:44 +08:00
|
|
|
// If the RHS is not the same type as the condition, insert an implicit
|
2009-05-16 07:57:33 +08:00
|
|
|
// cast.
|
2011-10-28 06:11:44 +08:00
|
|
|
// FIXME: In C++11, the value is a converted constant expression of the
|
|
|
|
// promoted type of the switch condition.
|
|
|
|
Hi = DefaultLvalueConversion(Hi).take();
|
2011-04-09 02:41:53 +08:00
|
|
|
Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
|
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);
|
|
|
|
--i, --e;
|
|
|
|
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.
|
|
|
|
CaseStmt *OverlapStmt = 0;
|
|
|
|
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.
|
2010-09-09 08:05:53 +08:00
|
|
|
if (!CaseListIsErroneous && !HasConstantCond && ET) {
|
2010-02-09 06:24:16 +08:00
|
|
|
const EnumDecl *ED = ET->getDecl();
|
2011-07-23 18:55:15 +08:00
|
|
|
typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
|
2011-06-02 08:47:27 +08:00
|
|
|
EnumValsTy;
|
2010-02-09 06:24:16 +08:00
|
|
|
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.
|
|
|
|
for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
|
2010-10-02 06:05:14 +08:00
|
|
|
EDI != ED->enumerator_end(); ++EDI) {
|
|
|
|
llvm::APSInt Val = EDI->getInitVal();
|
|
|
|
AdjustAPSInt(Val, CondWidth, CondIsSigned);
|
|
|
|
EnumVals.push_back(std::make_pair(Val, *EDI));
|
2010-02-09 06:24:16 +08:00
|
|
|
}
|
|
|
|
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
|
2010-05-18 11:19:21 +08:00
|
|
|
EnumValsTy::iterator EIend =
|
|
|
|
std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
|
2010-09-09 08:05:53 +08:00
|
|
|
|
|
|
|
// See which case values aren't in enum.
|
|
|
|
// TODO: we might want to check whether case values are out of the
|
|
|
|
// enum even if we don't want to check whether all cases are handled.
|
|
|
|
if (!TheDefaultStmt) {
|
2010-09-09 14:53:59 +08:00
|
|
|
EnumValsTy::const_iterator EI = EnumVals.begin();
|
|
|
|
for (CaseValsTy::const_iterator CI = CaseVals.begin();
|
2010-05-18 11:19:21 +08:00
|
|
|
CI != CaseVals.end(); CI++) {
|
2010-09-09 14:53:59 +08:00
|
|
|
while (EI != EIend && EI->first < CI->first)
|
|
|
|
EI++;
|
|
|
|
if (EI == EIend || EI->first > CI->first)
|
2010-05-18 11:19:21 +08:00
|
|
|
Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
|
|
|
|
<< ED->getDeclName();
|
2010-09-09 14:53:59 +08:00
|
|
|
}
|
|
|
|
// See which of case ranges aren't in enum
|
|
|
|
EI = EnumVals.begin();
|
|
|
|
for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
|
2010-05-18 11:19:21 +08:00
|
|
|
RI != CaseRanges.end() && EI != EIend; RI++) {
|
2010-09-09 14:53:59 +08:00
|
|
|
while (EI != EIend && EI->first < RI->first)
|
|
|
|
EI++;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-09-09 14:53:59 +08:00
|
|
|
if (EI == EIend || EI->first != RI->first) {
|
|
|
|
Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
|
|
|
|
<< ED->getDeclName();
|
|
|
|
}
|
2010-09-09 10:57:51 +08:00
|
|
|
|
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-09-09 14:53:59 +08:00
|
|
|
while (EI != EIend && EI->first < Hi)
|
|
|
|
EI++;
|
|
|
|
if (EI == EIend || EI->first != Hi)
|
|
|
|
Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum)
|
|
|
|
<< ED->getDeclName();
|
|
|
|
}
|
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
|
2010-02-09 06:24:16 +08:00
|
|
|
CaseValsTy::const_iterator CI = CaseVals.begin();
|
|
|
|
CaseRangesTy::const_iterator 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
|
|
|
|
2010-09-09 08:05:53 +08:00
|
|
|
for (EnumValsTy::const_iterator 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
|
|
|
llvm::APSInt CIVal;
|
|
|
|
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;
|
|
|
|
if (!TheDefaultStmt)
|
2010-09-17 01:09:42 +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
|
|
|
|
2010-09-17 01:09:42 +08:00
|
|
|
// Produce a nice diagnostic if multiple values aren't handled.
|
|
|
|
switch (UnhandledNames.size()) {
|
|
|
|
case 0: break;
|
|
|
|
case 1:
|
|
|
|
Diag(CondExpr->getExprLoc(), diag::warn_missing_case1)
|
|
|
|
<< UnhandledNames[0];
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Diag(CondExpr->getExprLoc(), diag::warn_missing_case2)
|
|
|
|
<< UnhandledNames[0] << UnhandledNames[1];
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
Diag(CondExpr->getExprLoc(), diag::warn_missing_case3)
|
|
|
|
<< UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Diag(CondExpr->getExprLoc(), diag::warn_missing_cases)
|
|
|
|
<< (unsigned)UnhandledNames.size()
|
|
|
|
<< UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2];
|
|
|
|
break;
|
|
|
|
}
|
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
|
|
|
|
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();
|
|
|
|
|
|
|
|
return Owned(SS);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2011-01-27 15:10:08 +08:00
|
|
|
Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
|
2010-08-24 07:25:46 +08:00
|
|
|
Decl *CondVar, Stmt *Body) {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult CondResult(Cond.release());
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2009-11-25 05:15:44 +08:00
|
|
|
VarDecl *ConditionVar = 0;
|
2010-08-21 17:40:31 +08:00
|
|
|
if (CondVar) {
|
|
|
|
ConditionVar = cast<VarDecl>(CondVar);
|
2010-05-07 01:25:47 +08:00
|
|
|
CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true);
|
2009-11-25 08:27:52 +08:00
|
|
|
if (CondResult.isInvalid())
|
|
|
|
return StmtError();
|
2009-11-25 05:15:44 +08:00
|
|
|
}
|
2010-08-24 07:25:46 +08:00
|
|
|
Expr *ConditionExpr = CondResult.take();
|
2009-11-25 08:27:52 +08:00
|
|
|
if (!ConditionExpr)
|
|
|
|
return StmtError();
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
DiagnoseUnusedExprResult(Body);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-06-22 07:44:13 +08:00
|
|
|
return Owned(new (Context) WhileStmt(Context, ConditionVar, ConditionExpr,
|
2010-08-24 07:25:46 +08:00
|
|
|
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
|
|
|
|
2011-04-09 02:41:53 +08:00
|
|
|
ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc);
|
|
|
|
if (CondResult.isInvalid() || CondResult.isInvalid())
|
2009-10-13 05:59:07 +08:00
|
|
|
return StmtError();
|
2011-04-09 02:41:53 +08:00
|
|
|
Cond = CondResult.take();
|
2007-05-29 10:14:17 +08:00
|
|
|
|
2010-10-08 10:01:28 +08:00
|
|
|
CheckImplicitConversions(Cond, DoLoc);
|
2011-04-09 02:41:53 +08:00
|
|
|
CondResult = MaybeCreateExprWithCleanups(Cond);
|
2010-08-24 07:25:46 +08:00
|
|
|
if (CondResult.isInvalid())
|
2010-05-07 01:25:47 +08:00
|
|
|
return StmtError();
|
2010-08-24 07:25:46 +08:00
|
|
|
Cond = CondResult.take();
|
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
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
return Owned(new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen));
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2009-01-17 07:28:06 +08:00
|
|
|
Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
|
2010-08-24 07:25:46 +08:00
|
|
|
Stmt *First, FullExprArg second, Decl *secondVar,
|
2009-11-25 08:27:52 +08:00
|
|
|
FullExprArg third,
|
2010-08-24 07:25:46 +08:00
|
|
|
SourceLocation RParenLoc, Stmt *Body) {
|
2008-09-10 10:17:11 +08:00
|
|
|
if (!getLangOptions().CPlusPlus) {
|
|
|
|
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'.
|
2008-09-10 10:17:11 +08:00
|
|
|
for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
|
|
|
|
DI!=DE; ++DI) {
|
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(*DI);
|
2010-10-15 12:57:14 +08:00
|
|
|
if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage())
|
2008-09-10 10:17:11 +08:00
|
|
|
VD = 0;
|
|
|
|
if (VD == 0)
|
|
|
|
Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for);
|
|
|
|
// FIXME: mark decl erroneous!
|
|
|
|
}
|
2007-08-28 13:03:08 +08:00
|
|
|
}
|
2007-05-29 10:14:17 +08:00
|
|
|
}
|
2009-11-25 08:27:52 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult SecondResult(second.release());
|
2009-11-25 08:27:52 +08:00
|
|
|
VarDecl *ConditionVar = 0;
|
2010-08-21 17:40:31 +08:00
|
|
|
if (secondVar) {
|
|
|
|
ConditionVar = cast<VarDecl>(secondVar);
|
2010-05-07 01:25:47 +08:00
|
|
|
SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true);
|
2009-11-25 08:27:52 +08:00
|
|
|
if (SecondResult.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2009-11-25 08:27:52 +08:00
|
|
|
Expr *Third = third.release().takeAs<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);
|
|
|
|
|
2011-01-27 15:10:08 +08:00
|
|
|
return Owned(new (Context) ForStmt(Context, First,
|
|
|
|
SecondResult.take(), ConditionVar,
|
|
|
|
Third, Body, ForLoc, LParenLoc,
|
2010-06-22 07:44:13 +08:00
|
|
|
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) {
|
|
|
|
CheckImplicitConversions(E);
|
2010-12-06 16:20:24 +08:00
|
|
|
ExprResult Result = MaybeCreateExprWithCleanups(E);
|
2010-12-04 11:47:34 +08:00
|
|
|
if (Result.isInvalid()) return StmtError();
|
|
|
|
return Owned(static_cast<Stmt*>(Result.get()));
|
|
|
|
}
|
|
|
|
|
2011-07-27 09:07:15 +08:00
|
|
|
ExprResult
|
|
|
|
Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
|
|
|
|
assert(collection);
|
|
|
|
|
|
|
|
// Bail out early if we've got a type-dependent expression.
|
|
|
|
if (collection->isTypeDependent()) return Owned(collection);
|
|
|
|
|
|
|
|
// Perform normal l-value conversion.
|
|
|
|
ExprResult result = DefaultFunctionArrayLvalueConversion(collection);
|
|
|
|
if (result.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
collection = result.take();
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
if (iface &&
|
|
|
|
RequireCompleteType(forLoc, QualType(objectType, 0),
|
|
|
|
getLangOptions().ObjCAutoRefCount
|
|
|
|
? PDiag(diag::err_arc_collection_forward)
|
|
|
|
<< collection->getSourceRange()
|
|
|
|
: PDiag(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]);
|
|
|
|
|
|
|
|
ObjCMethodDecl *method = 0;
|
|
|
|
|
|
|
|
// If there's an interface, look in both the public and private APIs.
|
|
|
|
if (iface) {
|
|
|
|
method = iface->lookupInstanceMethod(selector);
|
|
|
|
if (!method) method = LookupPrivateInstanceMethod(selector, iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
return Owned(MaybeCreateExprWithCleanups(collection));
|
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2009-01-17 07:28:06 +08:00
|
|
|
Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
|
|
|
|
SourceLocation LParenLoc,
|
2010-08-24 07:25:46 +08:00
|
|
|
Stmt *First, Expr *Second,
|
|
|
|
SourceLocation RParenLoc, Stmt *Body) {
|
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));
|
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
VarDecl *D = cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
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(),
|
2009-01-17 07:28:06 +08:00
|
|
|
diag::err_non_variable_decl_in_for));
|
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();
|
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())
|
2008-11-19 13:27:50 +08:00
|
|
|
Diag(ForLoc, diag::err_selector_element_type)
|
2008-11-24 14:25:27 +08:00
|
|
|
<< FirstType << First->getSourceRange();
|
2008-01-04 01:55:25 +08:00
|
|
|
}
|
2011-07-27 09:07:15 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body,
|
|
|
|
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
|
|
|
namespace {
|
|
|
|
|
|
|
|
enum BeginEndFunction {
|
|
|
|
BEF_begin,
|
|
|
|
BEF_end
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Build a variable declaration for a for-range statement.
|
|
|
|
static 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,
|
|
|
|
TInfo, SC_Auto, SC_None);
|
2011-04-18 23:49:25 +08:00
|
|
|
Decl->setImplicit();
|
2011-04-15 06:09:26 +08:00
|
|
|
return Decl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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,
|
|
|
|
SourceLocation Loc, int diag) {
|
|
|
|
// Deduce the type for the iterator variable now rather than leaving it to
|
|
|
|
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
|
|
|
|
TypeSourceInfo *InitTSI = 0;
|
|
|
|
if (Init->getType()->isVoidType() ||
|
|
|
|
!SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI))
|
|
|
|
SemaRef.Diag(Loc, diag) << Init->getType();
|
|
|
|
if (!InitTSI) {
|
|
|
|
Decl->setInvalidDecl();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Decl->setTypeSourceInfo(InitTSI);
|
|
|
|
Decl->setType(InitTSI->getType());
|
|
|
|
|
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.
|
|
|
|
if (SemaRef.getLangOptions().ObjCAutoRefCount &&
|
|
|
|
SemaRef.inferObjCARCLifetime(Decl))
|
|
|
|
Decl->setInvalidDecl();
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false,
|
|
|
|
/*TypeMayContainAuto=*/false);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Produce a note indicating which begin/end function was implicitly called
|
|
|
|
/// by a C++0x for-range statement. This is often not obvious from the code,
|
|
|
|
/// nor from the diagnostics produced when analysing the implicit expressions
|
|
|
|
/// required in a for-range statement.
|
|
|
|
void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
|
|
|
|
BeginEndFunction BEF) {
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Build a call to 'begin' or 'end' for a C++0x for-range statement. If the
|
|
|
|
/// given LookupResult is non-empty, it is assumed to describe a member which
|
|
|
|
/// will be invoked. Otherwise, the function will be found via argument
|
|
|
|
/// dependent lookup.
|
|
|
|
static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S,
|
|
|
|
SourceLocation Loc,
|
|
|
|
VarDecl *Decl,
|
|
|
|
BeginEndFunction BEF,
|
|
|
|
const DeclarationNameInfo &NameInfo,
|
|
|
|
LookupResult &MemberLookup,
|
|
|
|
Expr *Range) {
|
|
|
|
ExprResult CallExpr;
|
|
|
|
if (!MemberLookup.empty()) {
|
|
|
|
ExprResult MemberRef =
|
|
|
|
SemaRef.BuildMemberReferenceExpr(Range, Range->getType(), Loc,
|
|
|
|
/*IsPtr=*/false, CXXScopeSpec(),
|
|
|
|
/*Qualifier=*/0, MemberLookup,
|
|
|
|
/*TemplateArgs=*/0);
|
|
|
|
if (MemberRef.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
CallExpr = SemaRef.ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(),
|
|
|
|
Loc, 0);
|
|
|
|
if (CallExpr.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
} else {
|
|
|
|
UnresolvedSet<0> FoundNames;
|
|
|
|
// C++0x [stmt.ranged]p1: For the purposes of this name lookup, namespace
|
|
|
|
// std is an associated namespace.
|
|
|
|
UnresolvedLookupExpr *Fn =
|
|
|
|
UnresolvedLookupExpr::Create(SemaRef.Context, /*NamingClass=*/0,
|
|
|
|
NestedNameSpecifierLoc(), NameInfo,
|
|
|
|
/*NeedsADL=*/true, /*Overloaded=*/false,
|
|
|
|
FoundNames.begin(), FoundNames.end(),
|
|
|
|
/*LookInStdNamespace=*/true);
|
|
|
|
CallExpr = SemaRef.BuildOverloadedCallExpr(S, Fn, Fn, Loc, &Range, 1, Loc,
|
|
|
|
0);
|
|
|
|
if (CallExpr.isInvalid()) {
|
|
|
|
SemaRef.Diag(Range->getLocStart(), diag::note_for_range_type)
|
|
|
|
<< Range->getType();
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (FinishForRangeVarDecl(SemaRef, Decl, CallExpr.get(), Loc,
|
|
|
|
diag::err_for_range_iter_deduction_failure)) {
|
|
|
|
NoteForRangeBeginEndFunction(SemaRef, CallExpr.get(), BEF);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
return CallExpr;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ActOnCXXForRangeStmt - Check and build a C++0x for-range statement.
|
|
|
|
///
|
|
|
|
/// C++0x [stmt.ranged]:
|
|
|
|
/// 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.
|
|
|
|
StmtResult
|
|
|
|
Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
|
|
|
|
Stmt *First, SourceLocation ColonLoc, Expr *Range,
|
|
|
|
SourceLocation RParenLoc) {
|
|
|
|
if (!First || !Range)
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
if (DS->getSingleDecl()->isInvalidDecl())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
if (DiagnoseUnexpandedParameterPack(Range, UPPC_Expression))
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
// Build auto && __range = range-init
|
|
|
|
SourceLocation RangeLoc = Range->getLocStart();
|
|
|
|
VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
|
|
|
|
Context.getAutoRRefDeductType(),
|
|
|
|
"__range");
|
|
|
|
if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
|
|
|
|
diag::err_for_range_deduction_failure))
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
// Claim the type doesn't contain auto: we've already done the checking.
|
|
|
|
DeclGroupPtrTy RangeGroup =
|
|
|
|
BuildDeclaratorGroup((Decl**)&RangeVar, 1, /*TypeMayContainAuto=*/false);
|
|
|
|
StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
|
|
|
|
if (RangeDecl.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
|
|
|
|
/*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS,
|
|
|
|
RParenLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// BuildCXXForRangeStmt - Build or instantiate a C++0x for-range statement.
|
|
|
|
StmtResult
|
|
|
|
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
|
|
|
|
Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
|
|
|
|
Expr *Inc, Stmt *LoopVarDecl,
|
|
|
|
SourceLocation RParenLoc) {
|
|
|
|
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());
|
|
|
|
|
|
|
|
StmtResult BeginEndDecl = BeginEnd;
|
|
|
|
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
|
|
|
|
|
|
|
|
if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) {
|
|
|
|
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,
|
|
|
|
PDiag(diag::err_for_range_incomplete_type)))
|
|
|
|
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;
|
|
|
|
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))
|
|
|
|
BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(),
|
2011-05-03 07:00:27 +08:00
|
|
|
Context.getPointerDiffType(),
|
|
|
|
RangeLoc));
|
2011-04-15 06:09:26 +08:00
|
|
|
else if (const VariableArrayType *VAT =
|
|
|
|
dyn_cast<VariableArrayType>(UnqAT))
|
|
|
|
BoundExpr = VAT->getSizeExpr();
|
|
|
|
else {
|
|
|
|
// 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 {
|
|
|
|
DeclarationNameInfo BeginNameInfo(&PP.getIdentifierTable().get("begin"),
|
|
|
|
ColonLoc);
|
|
|
|
DeclarationNameInfo EndNameInfo(&PP.getIdentifierTable().get("end"),
|
|
|
|
ColonLoc);
|
|
|
|
|
|
|
|
LookupResult BeginMemberLookup(*this, BeginNameInfo, LookupMemberName);
|
|
|
|
LookupResult EndMemberLookup(*this, EndNameInfo, 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;
|
|
|
|
LookupQualifiedName(BeginMemberLookup, D);
|
|
|
|
LookupQualifiedName(EndMemberLookup, D);
|
|
|
|
|
|
|
|
if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
|
|
|
|
Diag(ColonLoc, diag::err_for_range_member_begin_end_mismatch)
|
|
|
|
<< RangeType << BeginMemberLookup.empty();
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
} 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.
|
|
|
|
}
|
|
|
|
|
|
|
|
BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar,
|
|
|
|
BEF_begin, BeginNameInfo,
|
2011-10-11 06:36:28 +08:00
|
|
|
BeginMemberLookup,
|
|
|
|
BeginRangeRef.get());
|
2011-04-15 06:09:26 +08:00
|
|
|
if (BeginExpr.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar,
|
|
|
|
BEF_end, EndNameInfo,
|
2011-10-11 06:36:28 +08:00
|
|
|
EndMemberLookup, EndRangeRef.get());
|
2011-04-15 06:09:26 +08:00
|
|
|
if (EndExpr.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++0x [decl.spec.auto]p6: BeginType and EndType must be the same.
|
|
|
|
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
|
|
|
|
if (!Context.hasSameType(BeginType, EndType)) {
|
|
|
|
Diag(RangeLoc, diag::err_for_range_begin_end_types_differ)
|
|
|
|
<< BeginType << EndType;
|
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
|
|
|
|
}
|
|
|
|
|
|
|
|
Decl *BeginEndDecls[] = { BeginVar, EndVar };
|
|
|
|
// Claim the type doesn't contain auto: we've already done the checking.
|
|
|
|
DeclGroupPtrTy BeginEndGroup =
|
|
|
|
BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false);
|
|
|
|
BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
|
|
|
|
|
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());
|
|
|
|
NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get());
|
|
|
|
NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get());
|
|
|
|
if (NotEqExpr.isInvalid()) {
|
|
|
|
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());
|
|
|
|
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
|
|
|
|
if (IncrExpr.isInvalid()) {
|
|
|
|
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()) {
|
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attach *__begin as initializer for VD.
|
|
|
|
if (!LoopVar->isInvalidDecl()) {
|
|
|
|
AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false,
|
|
|
|
/*TypeMayContainAuto=*/true);
|
|
|
|
if (LoopVar->isInvalidDecl())
|
|
|
|
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
|
|
|
|
}
|
2011-06-22 07:07:19 +08:00
|
|
|
} else {
|
|
|
|
// The range is implicitly used as a placeholder when it is dependent.
|
|
|
|
RangeVar->setUsed();
|
2011-04-15 06:09:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return Owned(new (Context) CXXForRangeStmt(RangeDS,
|
|
|
|
cast_or_null<DeclStmt>(BeginEndDecl.get()),
|
|
|
|
NotEqExpr.take(), IncrExpr.take(),
|
|
|
|
LoopVarDS, /*Body=*/0, ForLoc,
|
|
|
|
ColonLoc, RParenLoc));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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();
|
|
|
|
|
|
|
|
cast<CXXForRangeStmt>(S)->setBody(B);
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2011-02-18 04:34:02 +08:00
|
|
|
StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
|
|
|
|
SourceLocation LabelLoc,
|
|
|
|
LabelDecl *TheDecl) {
|
|
|
|
getCurFunction()->setHasBranchIntoScope();
|
2011-02-17 15:39:24 +08:00
|
|
|
TheDecl->setUsed();
|
|
|
|
return Owned(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());
|
2011-04-09 02:41:53 +08:00
|
|
|
ExprResult ExprRes = Owned(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();
|
|
|
|
E = ExprRes.take();
|
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
|
|
|
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->setHasIndirectGoto();
|
2010-08-01 08:26:45 +08:00
|
|
|
|
2009-05-16 08:20:29 +08:00
|
|
|
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
|
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::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
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(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
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(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
|
|
|
///
|
2011-05-20 23:00:53 +08:00
|
|
|
/// \param AllowFunctionParameter Whether we allow function parameters to
|
|
|
|
/// be considered NRVO candidates. C++ prohibits this 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.
|
2011-01-22 02:05:27 +08:00
|
|
|
const VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
|
|
|
|
Expr *E,
|
|
|
|
bool AllowFunctionParameter) {
|
|
|
|
QualType ExprType = E->getType();
|
2010-05-15 08:13:29 +08:00
|
|
|
// - in a return statement in a function with ...
|
|
|
|
// ... a class return type ...
|
2011-01-22 02:05:27 +08:00
|
|
|
if (!ReturnType.isNull()) {
|
|
|
|
if (!ReturnType->isRecordType())
|
|
|
|
return 0;
|
|
|
|
// ... the same cv-unqualified type as the function return type ...
|
|
|
|
if (!Context.hasSameUnqualifiedType(ReturnType, ExprType))
|
|
|
|
return 0;
|
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
|
|
|
// ... the expression is the name of a non-volatile automatic object
|
2011-01-22 02:05:27 +08:00
|
|
|
// (other than a function or catch-clause parameter)) ...
|
|
|
|
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens());
|
2010-05-15 08:13:29 +08:00
|
|
|
if (!DR)
|
2010-05-15 14:01:05 +08:00
|
|
|
return 0;
|
2010-05-15 08:13:29 +08:00
|
|
|
const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
|
|
|
|
if (!VD)
|
2010-05-15 14:01:05 +08:00
|
|
|
return 0;
|
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 &&
|
|
|
|
!(AllowFunctionParameter && VD->getKind() == Decl::ParmVar))
|
|
|
|
return 0;
|
|
|
|
if (VD->isExceptionVariable()) return 0;
|
|
|
|
|
|
|
|
// ...automatic...
|
|
|
|
if (!VD->hasLocalStorage()) return 0;
|
|
|
|
|
|
|
|
// ...non-volatile...
|
|
|
|
if (VD->getType().isVolatileQualified()) return 0;
|
|
|
|
if (VD->getType()->isReferenceType()) return 0;
|
|
|
|
|
|
|
|
// __block variables can't be allocated in a way that permits NRVO.
|
|
|
|
if (VD->hasAttr<BlocksAttr>()) return 0;
|
|
|
|
|
|
|
|
// Variables with higher required alignment than their type's ABI
|
|
|
|
// alignment cannot use NRVO.
|
|
|
|
if (VD->hasAttr<AlignedAttr>() &&
|
|
|
|
Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VD->getType()))
|
|
|
|
return 0;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2011-11-11 11:57:31 +08:00
|
|
|
return VD;
|
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
|
|
|
///
|
|
|
|
/// This routine implements C++0x [class.copy]p33, which attempts to treat
|
|
|
|
/// 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) {
|
2011-01-22 03:38:21 +08:00
|
|
|
// C++0x [class.copy]p33:
|
2011-01-27 15:10:08 +08:00
|
|
|
// When the criteria for elision of a copy operation are met or would
|
|
|
|
// be met save for the fact that the source object is a function
|
|
|
|
// parameter, and the object to be copied is designated by an lvalue,
|
2011-01-22 03:38:21 +08:00
|
|
|
// overload resolution to select the constructor for the copy is first
|
|
|
|
// performed as if the object were designated by an rvalue.
|
|
|
|
ExprResult Res = ExprError();
|
2011-07-07 06:04:06 +08:00
|
|
|
if (AllowNRVO &&
|
|
|
|
(NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) {
|
2011-01-27 15:10:08 +08:00
|
|
|
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack,
|
2011-01-22 05:08:57 +08:00
|
|
|
Value->getType(), CK_LValueToRValue,
|
|
|
|
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
|
|
|
InitializationKind Kind
|
2011-01-22 05:08:57 +08:00
|
|
|
= InitializationKind::CreateCopy(Value->getLocStart(),
|
|
|
|
Value->getLocStart());
|
|
|
|
InitializationSequence Seq(*this, Entity, Kind, &InitExpr, 1);
|
2011-01-27 15:10:08 +08:00
|
|
|
|
|
|
|
// [...] If overload resolution fails, or if the type of the first
|
2011-01-22 03:38:21 +08:00
|
|
|
// parameter of the selected constructor is not an rvalue reference
|
2011-01-27 15:09:49 +08:00
|
|
|
// to the object's type (possibly cv-qualified), overload resolution
|
2011-01-22 03:38:21 +08:00
|
|
|
// is performed again, considering the object as an lvalue.
|
2011-06-05 20:23:28 +08:00
|
|
|
if (Seq) {
|
2011-01-22 03:38:21 +08:00
|
|
|
for (InitializationSequence::step_iterator Step = Seq.step_begin(),
|
|
|
|
StepEnd = Seq.step_end();
|
|
|
|
Step != StepEnd; ++Step) {
|
2011-06-05 20:23:28 +08:00
|
|
|
if (Step->Kind != InitializationSequence::SK_ConstructorInitialization)
|
2011-01-22 03:38:21 +08:00
|
|
|
continue;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
|
|
|
CXXConstructorDecl *Constructor
|
2011-01-22 03:38:21 +08:00
|
|
|
= 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
|
|
|
|
2011-01-22 03:38:21 +08:00
|
|
|
// If we don't meet the criteria, break out now.
|
2011-01-27 15:10:08 +08:00
|
|
|
if (!RRefType ||
|
2011-01-22 05:08:57 +08:00
|
|
|
!Context.hasSameUnqualifiedType(RRefType->getPointeeType(),
|
|
|
|
Context.getTypeDeclType(Constructor->getParent())))
|
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.
|
2011-01-22 05:08:57 +08:00
|
|
|
Value = ImplicitCastExpr::Create(Context, Value->getType(),
|
2011-01-27 15:10:08 +08:00
|
|
|
CK_LValueToRValue, Value, 0,
|
2011-01-22 05:08:57 +08:00
|
|
|
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.
|
2011-01-22 05:08:57 +08:00
|
|
|
Res = Seq.Perform(*this, Entity, Kind, MultiExprArg(&Value, 1));
|
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;
|
|
|
|
}
|
|
|
|
|
2008-10-29 08:13:59 +08:00
|
|
|
/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
|
2008-09-04 02:15:37 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2008-09-04 02:15:37 +08:00
|
|
|
Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
|
|
|
// If this is the first return we've seen in the block, infer the type of
|
|
|
|
// the block from it.
|
Keep an explicit stack of function and block scopes, each element of
which has the label map, switch statement stack, etc. Previously, we
had a single set of maps in Sema (for the function) along with a stack
of block scopes. However, this lead to funky behavior with nested
functions, e.g., in the member functions of local classes.
The explicit-stack approach is far cleaner, and we retain a 1-element
cache so that we're not malloc/free'ing every time we enter a
function. Fixes PR6382.
Also, tweaked the unused-variable warning suppression logic to look at
errors within a given Scope rather than within a given function. The
prior code wasn't looking at the right number-of-errors count when
dealing with blocks, since the block's count would be deallocated
before we got to ActOnPopScope. This approach works with nested
blocks/functions, and gives tighter error recovery.
llvm-svn: 97518
2010-03-02 07:15:13 +08:00
|
|
|
BlockScopeInfo *CurBlock = getCurBlock();
|
2011-12-04 07:53:56 +08:00
|
|
|
if (CurBlock->TheDecl->blockMissingReturnType()) {
|
|
|
|
QualType BlockReturnT;
|
2008-09-17 06:25:10 +08:00
|
|
|
if (RetValExp) {
|
2008-09-25 06:26:48 +08:00
|
|
|
// Don't call UsualUnaryConversions(), since we don't want to do
|
|
|
|
// integer promotions here.
|
2011-04-09 02:41:53 +08:00
|
|
|
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
|
|
|
|
if (Result.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
RetValExp = Result.take();
|
2011-06-05 13:04:23 +08:00
|
|
|
|
|
|
|
if (!RetValExp->isTypeDependent()) {
|
2011-12-04 07:53:56 +08:00
|
|
|
BlockReturnT = RetValExp->getType();
|
2011-06-05 13:04:23 +08:00
|
|
|
if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
|
|
|
|
// We have to remove a 'const' added to copied-in variable which was
|
|
|
|
// part of the implementation spec. and not the actual qualifier for
|
|
|
|
// the variable.
|
|
|
|
if (CDRE->isConstQualAdded())
|
|
|
|
CurBlock->ReturnType.removeLocalConst(); // FIXME: local???
|
|
|
|
}
|
|
|
|
} else
|
2011-12-04 07:53:56 +08:00
|
|
|
BlockReturnT = Context.DependentTy;
|
2008-09-17 06:25:10 +08:00
|
|
|
} else
|
2011-12-04 07:53:56 +08:00
|
|
|
BlockReturnT = Context.VoidTy;
|
|
|
|
if (!CurBlock->ReturnType.isNull() && !CurBlock->ReturnType->isDependentType()
|
|
|
|
&& !BlockReturnT->isDependentType()
|
|
|
|
// when block's return type is not specified, all return types
|
|
|
|
// must strictly match.
|
|
|
|
&& !Context.hasSameType(BlockReturnT, CurBlock->ReturnType)) {
|
|
|
|
Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
|
|
|
|
<< BlockReturnT << CurBlock->ReturnType;
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
CurBlock->ReturnType = BlockReturnT;
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
2009-06-20 07:37:08 +08:00
|
|
|
QualType FnRetType = CurBlock->ReturnType;
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2011-01-05 20:14:39 +08:00
|
|
|
if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
|
2009-04-30 05:40:37 +08:00
|
|
|
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
|
|
|
|
<< getCurFunctionOrMethodDecl()->getDeclName();
|
|
|
|
return StmtError();
|
|
|
|
}
|
|
|
|
|
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.
|
2011-08-18 05:34:14 +08:00
|
|
|
const VarDecl *NRVOCandidate = 0;
|
2011-08-18 06:09:46 +08:00
|
|
|
if (FnRetType->isDependentType()) {
|
|
|
|
// Delay processing for now. TODO: there are lots of dependent
|
|
|
|
// types we can conclusively prove aren't void.
|
|
|
|
} else if (FnRetType->isVoidType()) {
|
|
|
|
if (RetValExp &&
|
|
|
|
!(getLangOptions().CPlusPlus &&
|
|
|
|
(RetValExp->isTypeDependent() ||
|
|
|
|
RetValExp->getType()->isVoidType()))) {
|
2008-09-04 02:15:37 +08:00
|
|
|
Diag(ReturnLoc, diag::err_return_block_has_expr);
|
|
|
|
RetValExp = 0;
|
|
|
|
}
|
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,
|
2011-12-04 01:47:53 +08:00
|
|
|
NRVOCandidate != 0);
|
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
|
|
|
}
|
2011-08-18 06:09:46 +08:00
|
|
|
RetValExp = Res.take();
|
|
|
|
CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
|
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) {
|
|
|
|
CheckImplicitConversions(RetValExp, ReturnLoc);
|
|
|
|
RetValExp = MaybeCreateExprWithCleanups(RetValExp);
|
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
|
|
|
|
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.
|
2011-06-05 13:04:23 +08:00
|
|
|
if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
|
2010-05-15 14:01:05 +08:00
|
|
|
!CurContext->isDependentContext())
|
|
|
|
FunctionScopes.back()->Returns.push_back(Result);
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-05-15 14:01:05 +08:00
|
|
|
return Owned(Result);
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
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::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
|
2011-05-20 23:32:55 +08:00
|
|
|
// Check for unexpanded parameter packs.
|
|
|
|
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
|
|
|
|
return StmtError();
|
|
|
|
|
Keep an explicit stack of function and block scopes, each element of
which has the label map, switch statement stack, etc. Previously, we
had a single set of maps in Sema (for the function) along with a stack
of block scopes. However, this lead to funky behavior with nested
functions, e.g., in the member functions of local classes.
The explicit-stack approach is far cleaner, and we retain a 1-element
cache so that we're not malloc/free'ing every time we enter a
function. Fixes PR6382.
Also, tweaked the unused-variable warning suppression logic to look at
errors within a given Scope rather than within a given function. The
prior code wasn't looking at the right number-of-errors count when
dealing with blocks, since the block's count would be deallocated
before we got to ActOnPopScope. This approach works with nested
blocks/functions, and gives tighter error recovery.
llvm-svn: 97518
2010-03-02 07:15:13 +08:00
|
|
|
if (getCurBlock())
|
2008-09-04 02:15:37 +08:00
|
|
|
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2008-12-05 07:50:19 +08:00
|
|
|
QualType FnRetType;
|
2011-06-11 09:09:30 +08:00
|
|
|
QualType DeclaredRetType;
|
2009-04-29 08:43:21 +08:00
|
|
|
if (const FunctionDecl *FD = getCurFunctionDecl()) {
|
2008-12-05 07:50:19 +08:00
|
|
|
FnRetType = FD->getResultType();
|
2011-06-11 09:09:30 +08:00
|
|
|
DeclaredRetType = FnRetType;
|
2010-02-06 05:31:56 +08:00
|
|
|
if (FD->hasAttr<NoReturnAttr>() ||
|
|
|
|
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
|
2009-06-01 03:32:13 +08:00
|
|
|
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
|
2009-04-29 08:43:21 +08:00
|
|
|
<< getCurFunctionOrMethodDecl()->getDeclName();
|
2011-06-11 09:09:30 +08:00
|
|
|
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
|
|
|
|
DeclaredRetType = MD->getResultType();
|
|
|
|
if (MD->hasRelatedResultType() && MD->getClassInterface()) {
|
|
|
|
// In the implementation of a method with a related return type, the
|
|
|
|
// type used to type-check the validity of return statements within the
|
|
|
|
// method body is a pointer to the type of the class being implemented.
|
|
|
|
FnRetType = Context.getObjCInterfaceType(MD->getClassInterface());
|
|
|
|
FnRetType = Context.getObjCObjectPointerType(FnRetType);
|
|
|
|
} else {
|
|
|
|
FnRetType = DeclaredRetType;
|
|
|
|
}
|
|
|
|
} 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
|
|
|
|
2010-05-15 14:01:05 +08:00
|
|
|
ReturnStmt *Result = 0;
|
2008-01-05 02:04:52 +08:00
|
|
|
if (FnRetType->isVoidType()) {
|
2011-06-01 15:44:31 +08:00
|
|
|
if (RetValExp) {
|
|
|
|
if (!RetValExp->isTypeDependent()) {
|
|
|
|
// C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
|
|
unsigned D = diag::ext_return_has_expr;
|
|
|
|
if (RetValExp->getType()->isVoidType())
|
|
|
|
D = diag::ext_return_has_void_expr;
|
|
|
|
else {
|
|
|
|
ExprResult Result = Owned(RetValExp);
|
|
|
|
Result = IgnoredValueConversions(Result.take());
|
|
|
|
if (Result.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
RetValExp = Result.take();
|
|
|
|
RetValExp = ImpCastExprToType(RetValExp,
|
|
|
|
Context.VoidTy, CK_ToVoid).take();
|
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2011-06-01 15:44:31 +08:00
|
|
|
// return (some void expression); is legal in C++.
|
|
|
|
if (D != diag::ext_return_has_void_expr ||
|
|
|
|
!getLangOptions().CPlusPlus) {
|
|
|
|
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
|
|
|
|
2010-10-08 10:01:28 +08:00
|
|
|
CheckImplicitConversions(RetValExp, ReturnLoc);
|
2010-12-06 16:20:24 +08:00
|
|
|
RetValExp = MaybeCreateExprWithCleanups(RetValExp);
|
2007-05-29 22:23:36 +08:00
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-05-15 14:01:05 +08:00
|
|
|
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
|
|
|
|
} else if (!RetValExp && !FnRetType->isDependentType()) {
|
2008-11-19 16:23:25 +08:00
|
|
|
unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4
|
|
|
|
// C99 6.8.6.4p1 (ext_ since GCC warns)
|
|
|
|
if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr;
|
|
|
|
|
|
|
|
if (FunctionDecl *FD = getCurFunctionDecl())
|
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*/;
|
2010-05-15 14:01:05 +08:00
|
|
|
Result = new (Context) ReturnStmt(ReturnLoc);
|
|
|
|
} else {
|
|
|
|
const VarDecl *NRVOCandidate = 0;
|
|
|
|
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
|
|
|
|
// we have a non-void function 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.
|
|
|
|
|
2011-06-17 07:24:51 +08:00
|
|
|
// In C++ the return statement is handled via a copy initialization,
|
2010-05-15 14:01:05 +08:00
|
|
|
// the C version of which boils down to CheckSingleAssignmentConstraints.
|
2011-01-22 02:05:27 +08:00
|
|
|
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
|
2011-01-27 15:10:08 +08:00
|
|
|
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
|
2011-01-22 05:08:57 +08:00
|
|
|
FnRetType,
|
2011-06-02 08:47:27 +08:00
|
|
|
NRVOCandidate != 0);
|
2011-01-27 15:10:08 +08:00
|
|
|
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
|
2011-01-22 05:08:57 +08:00
|
|
|
FnRetType, RetValExp);
|
2010-05-15 14:01:05 +08:00
|
|
|
if (Res.isInvalid()) {
|
|
|
|
// FIXME: Cleanup temporaries here, anyway?
|
|
|
|
return StmtError();
|
|
|
|
}
|
2009-01-18 21:19:59 +08:00
|
|
|
|
2010-05-15 14:01:05 +08:00
|
|
|
RetValExp = Res.takeAs<Expr>();
|
2011-01-27 15:10:08 +08:00
|
|
|
if (RetValExp)
|
2010-05-15 14:01:05 +08:00
|
|
|
CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
|
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) {
|
2011-06-11 09:09:30 +08:00
|
|
|
// If we type-checked an Objective-C method's return type based
|
|
|
|
// on a related return type, we may need to adjust the return
|
|
|
|
// type again. Do so now.
|
|
|
|
if (DeclaredRetType != FnRetType) {
|
|
|
|
ExprResult result = PerformImplicitConversion(RetValExp,
|
|
|
|
DeclaredRetType,
|
|
|
|
AA_Returning);
|
|
|
|
if (result.isInvalid()) return StmtError();
|
|
|
|
RetValExp = result.take();
|
|
|
|
}
|
|
|
|
|
2010-10-08 10:01:28 +08:00
|
|
|
CheckImplicitConversions(RetValExp, ReturnLoc);
|
2010-12-06 16:20:24 +08:00
|
|
|
RetValExp = MaybeCreateExprWithCleanups(RetValExp);
|
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.
|
|
|
|
if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
|
|
|
|
!CurContext->isDependentContext())
|
|
|
|
FunctionScopes.back()->Returns.push_back(Result);
|
2011-06-16 07:02:42 +08:00
|
|
|
|
2010-05-15 14:01:05 +08:00
|
|
|
return Owned(Result);
|
2006-11-10 13:07:45 +08:00
|
|
|
}
|
|
|
|
|
2009-03-14 01:38:01 +08:00
|
|
|
/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
|
|
|
|
/// ignore "noop" casts in places where an lvalue is required by an inline asm.
|
|
|
|
/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
|
|
|
|
/// provide a strong guidance to not use it.
|
|
|
|
///
|
|
|
|
/// This method checks to see if the argument is an acceptable l-value and
|
|
|
|
/// returns false if it is a case we can handle.
|
|
|
|
static bool CheckAsmLValue(const Expr *E, Sema &S) {
|
2010-01-24 13:50:09 +08:00
|
|
|
// Type dependent expressions will be checked during instantiation.
|
|
|
|
if (E->isTypeDependent())
|
|
|
|
return false;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-11-24 13:12:34 +08:00
|
|
|
if (E->isLValue())
|
2009-03-14 01:38:01 +08:00
|
|
|
return false; // Cool, this is an lvalue.
|
|
|
|
|
|
|
|
// Okay, this is not an lvalue, but perhaps it is the result of a cast that we
|
|
|
|
// are supposed to allow.
|
|
|
|
const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
|
2010-11-24 13:12:34 +08:00
|
|
|
if (E != E2 && E2->isLValue()) {
|
2009-03-14 01:38:01 +08:00
|
|
|
if (!S.getLangOptions().HeinousExtensions)
|
|
|
|
S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
|
|
|
|
<< E->getSourceRange();
|
|
|
|
else
|
|
|
|
S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
|
|
|
|
<< E->getSourceRange();
|
|
|
|
// Accept, even if we emitted an error diagnostic.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// None of the above, just randomly invalid non-lvalue.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-22 05:40:33 +08:00
|
|
|
/// isOperandMentioned - Return true if the specified operand # is mentioned
|
|
|
|
/// anywhere in the decomposed asm string.
|
|
|
|
static bool isOperandMentioned(unsigned OpNo,
|
2011-07-24 01:14:25 +08:00
|
|
|
ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
|
2011-02-22 05:40:33 +08:00
|
|
|
for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
|
|
|
|
const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
|
|
|
|
if (!Piece.isOperand()) continue;
|
|
|
|
|
|
|
|
// If this is a reference to the input and if the input was the smaller
|
|
|
|
// one, then we have to reject this asm.
|
|
|
|
if (Piece.getOperandNo() == OpNo)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2009-03-14 01:38:01 +08:00
|
|
|
|
2011-02-22 05:40:33 +08:00
|
|
|
StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
|
|
|
|
bool IsVolatile, unsigned NumOutputs,
|
|
|
|
unsigned NumInputs, IdentifierInfo **Names,
|
|
|
|
MultiExprArg constraints, MultiExprArg exprs,
|
|
|
|
Expr *asmString, MultiExprArg clobbers,
|
|
|
|
SourceLocation RParenLoc, bool MSAsm) {
|
2009-01-19 00:53:17 +08:00
|
|
|
unsigned NumClobbers = clobbers.size();
|
|
|
|
StringLiteral **Constraints =
|
|
|
|
reinterpret_cast<StringLiteral**>(constraints.get());
|
2010-08-24 07:25:46 +08:00
|
|
|
Expr **Exprs = exprs.get();
|
|
|
|
StringLiteral *AsmString = cast<StringLiteral>(asmString);
|
2009-01-19 00:53:17 +08:00
|
|
|
StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-19 03:55:17 +08:00
|
|
|
// The parser verifies that there is a string literal here.
|
2011-07-27 13:40:30 +08:00
|
|
|
if (!AsmString->isAscii())
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< AsmString->getSourceRange());
|
|
|
|
|
2008-08-19 03:55:17 +08:00
|
|
|
for (unsigned i = 0; i != NumOutputs; i++) {
|
|
|
|
StringLiteral *Literal = Constraints[i];
|
2011-07-27 13:40:30 +08:00
|
|
|
if (!Literal->isAscii())
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef OutputName;
|
2010-01-31 06:25:16 +08:00
|
|
|
if (Names[i])
|
|
|
|
OutputName = Names[i]->getName();
|
|
|
|
|
|
|
|
TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
|
2011-09-02 08:18:52 +08:00
|
|
|
if (!Context.getTargetInfo().validateOutputConstraint(Info))
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-04-27 01:19:08 +08:00
|
|
|
diag::err_asm_invalid_output_constraint)
|
|
|
|
<< Info.getConstraintStr());
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2007-11-27 12:11:28 +08:00
|
|
|
// Check that the output exprs are valid lvalues.
|
2009-05-03 15:49:42 +08:00
|
|
|
Expr *OutputExpr = Exprs[i];
|
2009-03-14 01:38:01 +08:00
|
|
|
if (CheckAsmLValue(OutputExpr, *this)) {
|
2009-05-03 15:49:42 +08:00
|
|
|
return StmtError(Diag(OutputExpr->getLocStart(),
|
2008-11-19 13:27:50 +08:00
|
|
|
diag::err_asm_invalid_lvalue_in_output)
|
2009-05-03 15:49:42 +08:00
|
|
|
<< OutputExpr->getSourceRange());
|
2007-11-24 03:43:50 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-26 15:16:29 +08:00
|
|
|
OutputConstraintInfos.push_back(Info);
|
2007-11-24 03:43:50 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
|
2009-05-03 13:55:43 +08:00
|
|
|
|
2007-11-24 03:43:50 +08:00
|
|
|
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
|
2008-08-19 03:55:17 +08:00
|
|
|
StringLiteral *Literal = Constraints[i];
|
2011-07-27 13:40:30 +08:00
|
|
|
if (!Literal->isAscii())
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef InputName;
|
2010-01-31 06:25:16 +08:00
|
|
|
if (Names[i])
|
|
|
|
InputName = Names[i]->getName();
|
|
|
|
|
|
|
|
TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
|
2011-09-02 08:18:52 +08:00
|
|
|
if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
|
2009-04-27 01:57:12 +08:00
|
|
|
NumOutputs, Info)) {
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-04-27 01:19:08 +08:00
|
|
|
diag::err_asm_invalid_input_constraint)
|
|
|
|
<< Info.getConstraintStr());
|
2007-11-27 12:11:28 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2009-05-03 15:49:42 +08:00
|
|
|
Expr *InputExpr = Exprs[i];
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2009-01-21 04:49:22 +08:00
|
|
|
// Only allow void types for memory constraints.
|
2009-04-26 15:16:29 +08:00
|
|
|
if (Info.allowsMemory() && !Info.allowsRegister()) {
|
2009-03-14 01:38:01 +08:00
|
|
|
if (CheckAsmLValue(InputExpr, *this))
|
2009-05-03 15:49:42 +08:00
|
|
|
return StmtError(Diag(InputExpr->getLocStart(),
|
2009-01-21 04:49:22 +08:00
|
|
|
diag::err_asm_invalid_lvalue_in_input)
|
2009-04-27 01:19:08 +08:00
|
|
|
<< Info.getConstraintStr()
|
2009-05-03 15:49:42 +08:00
|
|
|
<< InputExpr->getSourceRange());
|
2007-11-24 03:43:50 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2009-04-26 15:16:29 +08:00
|
|
|
if (Info.allowsRegister()) {
|
2009-01-21 04:49:22 +08:00
|
|
|
if (InputExpr->getType()->isVoidType()) {
|
2009-05-03 15:49:42 +08:00
|
|
|
return StmtError(Diag(InputExpr->getLocStart(),
|
2009-01-21 04:49:22 +08:00
|
|
|
diag::err_asm_invalid_type_in_input)
|
2009-09-09 23:08:12 +08:00
|
|
|
<< InputExpr->getType() << Info.getConstraintStr()
|
2009-05-03 15:49:42 +08:00
|
|
|
<< InputExpr->getSourceRange());
|
2009-01-21 04:49:22 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-04-09 02:41:53 +08:00
|
|
|
ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
|
|
|
|
if (Result.isInvalid())
|
|
|
|
return StmtError();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-04-09 02:41:53 +08:00
|
|
|
Exprs[i] = Result.take();
|
2009-05-03 13:55:43 +08:00
|
|
|
InputConstraintInfos.push_back(Info);
|
2007-11-24 03:43:50 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2007-11-25 08:25:21 +08:00
|
|
|
// Check that the clobbers are valid.
|
2008-08-19 03:55:17 +08:00
|
|
|
for (unsigned i = 0; i != NumClobbers; i++) {
|
|
|
|
StringLiteral *Literal = Clobbers[i];
|
2011-07-27 13:40:30 +08:00
|
|
|
if (!Literal->isAscii())
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
|
|
|
|
<< Literal->getSourceRange());
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef Clobber = Literal->getString();
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2011-09-02 08:18:52 +08:00
|
|
|
if (!Context.getTargetInfo().isValidClobber(Clobber))
|
2009-01-19 00:53:17 +08:00
|
|
|
return StmtError(Diag(Literal->getLocStart(),
|
2009-08-20 04:04:03 +08:00
|
|
|
diag::err_asm_unknown_register_name) << Clobber);
|
2007-11-25 08:25:21 +08:00
|
|
|
}
|
2009-01-19 00:53:17 +08:00
|
|
|
|
2009-03-11 07:41:04 +08:00
|
|
|
AsmStmt *NS =
|
2011-01-27 15:10:08 +08:00
|
|
|
new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm,
|
|
|
|
NumOutputs, NumInputs, Names, Constraints, Exprs,
|
2010-01-31 07:19:41 +08:00
|
|
|
AsmString, NumClobbers, Clobbers, RParenLoc);
|
2009-03-11 07:41:04 +08:00
|
|
|
// Validate the asm string, ensuring it makes sense given the operands we
|
|
|
|
// have.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
|
2009-03-11 07:41:04 +08:00
|
|
|
unsigned DiagOffs;
|
|
|
|
if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
|
2009-03-11 07:57:07 +08:00
|
|
|
Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
|
|
|
|
<< AsmString->getSourceRange();
|
2009-03-11 07:41:04 +08:00
|
|
|
return StmtError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 13:55:43 +08:00
|
|
|
// Validate tied input operands for type mismatches.
|
|
|
|
for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
|
|
|
|
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 13:55:43 +08:00
|
|
|
// If this is a tied constraint, verify that the output and input have
|
|
|
|
// either exactly the same type, or that they are int/ptr operands with the
|
|
|
|
// same size (int/long, int*/long, are ok etc).
|
|
|
|
if (!Info.hasTiedOperand()) continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-03 13:55:43 +08:00
|
|
|
unsigned TiedTo = Info.getTiedOperand();
|
2011-02-22 06:09:29 +08:00
|
|
|
unsigned InputOpNo = i+NumOutputs;
|
2009-05-03 15:04:21 +08:00
|
|
|
Expr *OutputExpr = Exprs[TiedTo];
|
2011-02-22 06:09:29 +08:00
|
|
|
Expr *InputExpr = Exprs[InputOpNo];
|
2011-09-15 03:20:00 +08:00
|
|
|
|
|
|
|
if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
|
|
|
|
continue;
|
|
|
|
|
2009-05-03 13:59:17 +08:00
|
|
|
QualType InTy = InputExpr->getType();
|
|
|
|
QualType OutTy = OutputExpr->getType();
|
|
|
|
if (Context.hasSameType(InTy, OutTy))
|
2009-05-03 13:55:43 +08:00
|
|
|
continue; // All types can be tied to themselves.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-04-24 01:27:29 +08:00
|
|
|
// Decide if the input and output are in the same domain (integer/ptr or
|
|
|
|
// floating point.
|
|
|
|
enum AsmDomain {
|
|
|
|
AD_Int, AD_FP, AD_Other
|
|
|
|
} InputDomain, OutputDomain;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-04-24 01:27:29 +08:00
|
|
|
if (InTy->isIntegerType() || InTy->isPointerType())
|
|
|
|
InputDomain = AD_Int;
|
2010-06-23 07:07:26 +08:00
|
|
|
else if (InTy->isRealFloatingType())
|
2010-04-24 01:27:29 +08:00
|
|
|
InputDomain = AD_FP;
|
|
|
|
else
|
|
|
|
InputDomain = AD_Other;
|
2009-05-03 16:32:32 +08:00
|
|
|
|
2010-04-24 01:27:29 +08:00
|
|
|
if (OutTy->isIntegerType() || OutTy->isPointerType())
|
|
|
|
OutputDomain = AD_Int;
|
2010-06-23 07:07:26 +08:00
|
|
|
else if (OutTy->isRealFloatingType())
|
2010-04-24 01:27:29 +08:00
|
|
|
OutputDomain = AD_FP;
|
|
|
|
else
|
|
|
|
OutputDomain = AD_Other;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-04-24 01:27:29 +08:00
|
|
|
// They are ok if they are the same size and in the same domain. This
|
|
|
|
// allows tying things like:
|
|
|
|
// void* to int*
|
|
|
|
// void* to int if they are the same size.
|
|
|
|
// double to long double if they are the same size.
|
2011-01-27 15:10:08 +08:00
|
|
|
//
|
2010-04-24 01:27:29 +08:00
|
|
|
uint64_t OutSize = Context.getTypeSize(OutTy);
|
|
|
|
uint64_t InSize = Context.getTypeSize(InTy);
|
|
|
|
if (OutSize == InSize && InputDomain == OutputDomain &&
|
|
|
|
InputDomain != AD_Other)
|
|
|
|
continue;
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-04-24 01:27:29 +08:00
|
|
|
// If the smaller input/output operand is not mentioned in the asm string,
|
2011-02-22 05:50:25 +08:00
|
|
|
// then we can promote the smaller one to a larger input and the asm string
|
|
|
|
// won't notice.
|
2010-04-24 01:27:29 +08:00
|
|
|
bool SmallerValueMentioned = false;
|
2011-02-22 05:40:33 +08:00
|
|
|
|
|
|
|
// If this is a reference to the input and if the input was the smaller
|
|
|
|
// one, then we have to reject this asm.
|
2011-02-22 06:09:29 +08:00
|
|
|
if (isOperandMentioned(InputOpNo, Pieces)) {
|
2011-02-22 05:40:33 +08:00
|
|
|
// This is a use in the asm string of the smaller operand. Since we
|
|
|
|
// codegen this by promoting to a wider value, the asm will get printed
|
|
|
|
// "wrong".
|
2011-02-22 05:50:25 +08:00
|
|
|
SmallerValueMentioned |= InSize < OutSize;
|
2011-02-22 05:40:33 +08:00
|
|
|
}
|
2011-02-22 05:50:25 +08:00
|
|
|
if (isOperandMentioned(TiedTo, Pieces)) {
|
2011-02-22 05:40:33 +08:00
|
|
|
// If this is a reference to the output, and if the output is the larger
|
|
|
|
// value, then it's ok because we'll promote the input to the larger type.
|
2011-02-22 05:50:25 +08:00
|
|
|
SmallerValueMentioned |= OutSize < InSize;
|
2009-05-03 13:55:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-04-24 01:27:29 +08:00
|
|
|
// If the smaller value wasn't mentioned in the asm string, and if the
|
|
|
|
// output was a register, just extend the shorter one to the size of the
|
|
|
|
// larger one.
|
|
|
|
if (!SmallerValueMentioned && InputDomain != AD_Other &&
|
|
|
|
OutputConstraintInfos[TiedTo].allowsRegister())
|
|
|
|
continue;
|
2011-02-22 05:50:25 +08:00
|
|
|
|
2011-02-22 06:09:29 +08:00
|
|
|
// Either both of the operands were mentioned or the smaller one was
|
|
|
|
// mentioned. One more special case that we'll allow: if the tied input is
|
|
|
|
// integer, unmentioned, and is a constant, then we'll allow truncating it
|
|
|
|
// down to the size of the destination.
|
|
|
|
if (InputDomain == AD_Int && OutputDomain == AD_Int &&
|
|
|
|
!isOperandMentioned(InputOpNo, Pieces) &&
|
|
|
|
InputExpr->isEvaluatable(Context)) {
|
2011-05-11 07:39:47 +08:00
|
|
|
CastKind castKind =
|
|
|
|
(OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
|
|
|
|
InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
|
2011-02-22 06:09:29 +08:00
|
|
|
Exprs[InputOpNo] = InputExpr;
|
|
|
|
NS->setInputExpr(i, InputExpr);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-05-03 14:50:40 +08:00
|
|
|
Diag(InputExpr->getLocStart(),
|
2009-05-03 13:55:43 +08:00
|
|
|
diag::err_asm_tying_incompatible_types)
|
2009-05-03 13:59:17 +08:00
|
|
|
<< InTy << OutTy << OutputExpr->getSourceRange()
|
2009-05-03 13:55:43 +08:00
|
|
|
<< InputExpr->getSourceRange();
|
|
|
|
return StmtError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 07:41:04 +08:00
|
|
|
return Owned(NS);
|
2007-10-29 12:04:16 +08:00
|
|
|
}
|
2007-11-02 07:59:59 +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
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
return Owned(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) {
|
|
|
|
return Owned(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) {
|
2011-02-20 07:53:54 +08:00
|
|
|
if (!getLangOptions().ObjCExceptions)
|
|
|
|
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();
|
2010-08-24 07:25:46 +08:00
|
|
|
return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try,
|
|
|
|
CatchStmts.release(),
|
2010-04-24 06:50:49 +08:00
|
|
|
NumCatchStmts,
|
2010-08-24 07:25:46 +08:00
|
|
|
Finally));
|
2007-11-02 23:39:31 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
|
2010-08-24 07:25:46 +08:00
|
|
|
Expr *Throw) {
|
2010-04-23 05:44:01 +08:00
|
|
|
if (Throw) {
|
2011-07-21 07:39:56 +08:00
|
|
|
Throw = MaybeCreateExprWithCleanups(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
|
|
|
|
2011-04-09 02:41:53 +08:00
|
|
|
Throw = Result.take();
|
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())
|
|
|
|
return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
|
|
|
|
<< Throw->getType() << Throw->getSourceRange());
|
|
|
|
}
|
|
|
|
}
|
2011-01-27 15:10:08 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
return Owned(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) {
|
2011-02-20 07:53:54 +08:00
|
|
|
if (!getLangOptions().ObjCExceptions)
|
|
|
|
Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@throw";
|
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
if (!Throw) {
|
2009-02-12 04:05:44 +08:00
|
|
|
// @throw without an expression designates a rethrow (which much occur
|
|
|
|
// in the context of an @catch clause).
|
|
|
|
Scope *AtCatchParent = CurScope;
|
|
|
|
while (AtCatchParent && !AtCatchParent->isAtCatchScope())
|
|
|
|
AtCatchParent = AtCatchParent->getParent();
|
|
|
|
if (!AtCatchParent)
|
2009-02-13 02:09:32 +08:00
|
|
|
return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
|
2011-01-27 15:10:08 +08:00
|
|
|
}
|
2011-07-21 07:39:56 +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();
|
|
|
|
operand = result.take();
|
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>();
|
|
|
|
if (!pointerType || !pointerType->getPointeeType()->isVoidType())
|
|
|
|
return Diag(atLoc, diag::error_objc_synchronized_expects_object)
|
|
|
|
<< 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.
|
|
|
|
return MaybeCreateExprWithCleanups(operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult
|
|
|
|
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr,
|
|
|
|
Stmt *SyncBody) {
|
|
|
|
// We can't jump into or indirect-jump out of a @synchronized block.
|
|
|
|
getCurFunction()->setHasBranchProtectedScope();
|
2010-08-24 07:25:46 +08:00
|
|
|
return Owned(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.
|
2009-02-07 09:47:29 +08:00
|
|
|
return Owned(new (Context) CXXCatchStmt(CatchLoc,
|
2010-08-21 17:40:31 +08:00
|
|
|
cast_or_null<VarDecl>(ExDecl),
|
2010-08-24 07:25:46 +08:00
|
|
|
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();
|
|
|
|
return Owned(new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body));
|
|
|
|
}
|
|
|
|
|
2010-07-27 05:25:24 +08:00
|
|
|
namespace {
|
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
class TypeWithHandler {
|
|
|
|
QualType t;
|
|
|
|
CXXCatchStmt *stmt;
|
|
|
|
public:
|
|
|
|
TypeWithHandler(const QualType &type, CXXCatchStmt *statement)
|
|
|
|
: t(type), stmt(statement) {}
|
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// An arbitrary order is fine as long as it places identical
|
|
|
|
// types next to each other.
|
2009-07-30 01:15:45 +08:00
|
|
|
bool operator<(const TypeWithHandler &y) const {
|
2009-09-25 03:53:00 +08:00
|
|
|
if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr())
|
2009-07-30 01:15:45 +08:00
|
|
|
return true;
|
2009-09-25 03:53:00 +08:00
|
|
|
if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr())
|
2009-07-30 01:15:45 +08:00
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return getTypeSpecStartLoc() < y.getTypeSpecStartLoc();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
bool operator==(const TypeWithHandler& other) const {
|
2009-09-25 03:53:00 +08:00
|
|
|
return t == other.t;
|
2009-07-30 01:15:45 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
CXXCatchStmt *getCatchStmt() const { return stmt; }
|
|
|
|
SourceLocation getTypeSpecStartLoc() const {
|
|
|
|
return stmt->getExceptionDecl()->getTypeSpecStartLoc();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
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.
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2010-08-24 07:25:46 +08:00
|
|
|
Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
|
2008-12-23 05:35:02 +08:00
|
|
|
MultiStmtArg RawHandlers) {
|
2011-02-23 11:46:46 +08:00
|
|
|
// Don't report an error if 'try' is used in system headers.
|
2011-02-28 10:27:16 +08:00
|
|
|
if (!getLangOptions().CXXExceptions &&
|
2011-02-23 11:46:46 +08:00
|
|
|
!getSourceManager().isInSystemHeader(TryLoc))
|
|
|
|
Diag(TryLoc, diag::err_exceptions_disabled) << "try";
|
2011-02-20 03:26:44 +08:00
|
|
|
|
2008-12-23 05:35:02 +08:00
|
|
|
unsigned NumHandlers = RawHandlers.size();
|
|
|
|
assert(NumHandlers > 0 &&
|
|
|
|
"The parser shouldn't call this if there are no handlers.");
|
2010-08-24 07:25:46 +08:00
|
|
|
Stmt **Handlers = RawHandlers.get();
|
2008-12-23 05:35:02 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<TypeWithHandler, 8> TypesWithHandlers;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumHandlers; ++i) {
|
2011-07-23 18:55:15 +08:00
|
|
|
CXXCatchStmt *Handler = cast<CXXCatchStmt>(Handlers[i]);
|
2009-07-30 01:15:45 +08:00
|
|
|
if (!Handler->getExceptionDecl()) {
|
|
|
|
if (i < NumHandlers - 1)
|
|
|
|
return StmtError(Diag(Handler->getLocStart(),
|
|
|
|
diag::err_early_catch_all));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
const QualType CaughtType = Handler->getCaughtType();
|
|
|
|
const QualType CanonicalCaughtType = Context.getCanonicalType(CaughtType);
|
|
|
|
TypesWithHandlers.push_back(TypeWithHandler(CanonicalCaughtType, Handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Detect handlers for the same type as an earlier one.
|
|
|
|
if (NumHandlers > 1) {
|
|
|
|
llvm::array_pod_sort(TypesWithHandlers.begin(), TypesWithHandlers.end());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
TypeWithHandler prev = TypesWithHandlers[0];
|
|
|
|
for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) {
|
|
|
|
TypeWithHandler curr = TypesWithHandlers[i];
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
if (curr == prev) {
|
|
|
|
Diag(curr.getTypeSpecStartLoc(),
|
|
|
|
diag::warn_exception_caught_by_earlier_handler)
|
|
|
|
<< curr.getCatchStmt()->getCaughtType().getAsString();
|
|
|
|
Diag(prev.getTypeSpecStartLoc(),
|
|
|
|
diag::note_previous_exception_handler)
|
|
|
|
<< prev.getCatchStmt()->getCaughtType().getAsString();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 01:15:45 +08:00
|
|
|
prev = curr;
|
|
|
|
}
|
2008-12-23 05:35:02 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-25 16:40:02 +08:00
|
|
|
getCurFunction()->setHasBranchProtectedScope();
|
2010-08-01 08:26:45 +08:00
|
|
|
|
2008-12-23 05:35:02 +08:00
|
|
|
// FIXME: We should detect handlers that cannot catch anything because an
|
|
|
|
// earlier handler catches a superclass. Need to find a method that is not
|
|
|
|
// quadratic for this.
|
|
|
|
// Neither of these are explicitly forbidden, but every compiler detects them
|
|
|
|
// and warns.
|
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock,
|
2010-02-03 11:56:39 +08:00
|
|
|
Handlers, NumHandlers));
|
2008-12-23 05:35:02 +08:00
|
|
|
}
|
2011-04-28 09:08:34 +08:00
|
|
|
|
|
|
|
StmtResult
|
|
|
|
Sema::ActOnSEHTryBlock(bool IsCXXTry,
|
|
|
|
SourceLocation TryLoc,
|
|
|
|
Stmt *TryBlock,
|
|
|
|
Stmt *Handler) {
|
|
|
|
assert(TryBlock && Handler);
|
|
|
|
|
|
|
|
getCurFunction()->setHasBranchProtectedScope();
|
|
|
|
|
|
|
|
return Owned(SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block));
|
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult
|
|
|
|
Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
|
|
|
|
Stmt *Block) {
|
|
|
|
assert(Block);
|
|
|
|
return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
|
|
|
|
}
|
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,
|
|
|
|
QualifierLoc, NameInfo,
|
|
|
|
cast<CompoundStmt>(Nested));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc,
|
|
|
|
bool IsIfExists,
|
|
|
|
CXXScopeSpec &SS,
|
|
|
|
UnqualifiedId &Name,
|
|
|
|
Stmt *Nested) {
|
|
|
|
return BuildMSDependentExistsStmt(KeywordLoc, IsIfExists,
|
|
|
|
SS.getWithLocInContext(Context),
|
|
|
|
GetNameFromUnqualifiedId(Name),
|
|
|
|
Nested);
|
|
|
|
}
|