2017-11-18 02:09:48 +08:00
|
|
|
//===--- Expr.cpp - Expression AST Node Implementation --------------------===//
|
2006-08-23 14:42:10 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2006-08-23 14:42:10 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Expr class and subclasses.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
Implement __builtin_LINE() et. al. to support source location capture.
Summary:
This patch implements the source location builtins `__builtin_LINE(), `__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These builtins are needed to implement [`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, and Clangs behavior is intended to match as closely as possible.
Reviewers: rsmith, joerg, aaron.ballman, bogner, majnemer, shafik, martong
Reviewed By: rsmith
Subscribers: rnkovacs, loskutov, riccibruno, mgorny, kunitoki, alexr, majnemer, hfinkel, cfe-commits
Differential Revision: https://reviews.llvm.org/D37035
llvm-svn: 360937
2019-05-17 05:04:15 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
|
|
|
#include "clang/AST/APValue.h"
|
2007-07-16 07:32:58 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2012-12-01 23:09:41 +08:00
|
|
|
#include "clang/AST/Attr.h"
|
2008-10-22 07:43:52 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2012-12-01 23:09:41 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-02-05 03:02:06 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2012-02-23 15:33:15 +08:00
|
|
|
#include "clang/AST/EvaluatedExprVisitor.h"
|
2012-12-01 23:09:41 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2013-11-07 07:31:56 +08:00
|
|
|
#include "clang/AST/Mangle.h"
|
2017-11-18 02:09:48 +08:00
|
|
|
#include "clang/AST/RecordLayout.h"
|
|
|
|
#include "clang/AST/StmtVisitor.h"
|
2009-06-14 09:54:56 +08:00
|
|
|
#include "clang/Basic/Builtins.h"
|
2013-02-09 06:30:41 +08:00
|
|
|
#include "clang/Basic/CharInfo.h"
|
2010-11-17 15:37:15 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2007-11-28 02:22:04 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2012-12-01 23:09:41 +08:00
|
|
|
#include "clang/Lex/Lexer.h"
|
|
|
|
#include "clang/Lex/LiteralSupport.h"
|
2009-11-02 04:32:48 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2009-09-09 02:24:21 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2009-04-15 14:41:24 +08:00
|
|
|
#include <algorithm>
|
2011-11-01 10:23:42 +08:00
|
|
|
#include <cstring>
|
2006-08-23 14:42:10 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2016-11-04 02:55:18 +08:00
|
|
|
const Expr *Expr::getBestDynamicClassTypeExpr() const {
|
|
|
|
const Expr *E = this;
|
|
|
|
while (true) {
|
|
|
|
E = E->ignoreParenBaseCasts();
|
|
|
|
|
|
|
|
// Follow the RHS of a comma operator.
|
|
|
|
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
|
|
|
|
if (BO->getOpcode() == BO_Comma) {
|
|
|
|
E = BO->getRHS();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Step into initializer for materialized temporaries.
|
|
|
|
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
|
2019-11-17 18:41:55 +08:00
|
|
|
E = MTE->getSubExpr();
|
2016-11-04 02:55:18 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2012-06-27 01:45:31 +08:00
|
|
|
|
2016-11-04 02:55:18 +08:00
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
|
|
|
const CXXRecordDecl *Expr::getBestDynamicClassType() const {
|
|
|
|
const Expr *E = getBestDynamicClassTypeExpr();
|
2012-06-27 01:45:31 +08:00
|
|
|
QualType DerivedType = E->getType();
|
|
|
|
if (const PointerType *PTy = DerivedType->getAs<PointerType>())
|
|
|
|
DerivedType = PTy->getPointeeType();
|
|
|
|
|
2012-07-18 04:24:05 +08:00
|
|
|
if (DerivedType->isDependentType())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2012-07-18 04:24:05 +08:00
|
|
|
|
2012-06-27 01:45:31 +08:00
|
|
|
const RecordType *Ty = DerivedType->castAs<RecordType>();
|
|
|
|
Decl *D = Ty->getDecl();
|
|
|
|
return cast<CXXRecordDecl>(D);
|
|
|
|
}
|
|
|
|
|
2013-06-03 08:17:11 +08:00
|
|
|
const Expr *Expr::skipRValueSubobjectAdjustments(
|
|
|
|
SmallVectorImpl<const Expr *> &CommaLHSs,
|
|
|
|
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
|
2012-10-27 09:03:43 +08:00
|
|
|
const Expr *E = this;
|
|
|
|
while (true) {
|
|
|
|
E = E->IgnoreParens();
|
|
|
|
|
|
|
|
if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
|
|
|
|
if ((CE->getCastKind() == CK_DerivedToBase ||
|
|
|
|
CE->getCastKind() == CK_UncheckedDerivedToBase) &&
|
|
|
|
E->getType()->isRecordType()) {
|
|
|
|
E = CE->getSubExpr();
|
2019-10-03 19:22:48 +08:00
|
|
|
auto *Derived =
|
|
|
|
cast<CXXRecordDecl>(E->getType()->castAs<RecordType>()->getDecl());
|
2012-10-27 09:03:43 +08:00
|
|
|
Adjustments.push_back(SubobjectAdjustment(CE, Derived));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CE->getCastKind() == CK_NoOp) {
|
|
|
|
E = CE->getSubExpr();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
|
2013-06-15 08:30:29 +08:00
|
|
|
if (!ME->isArrow()) {
|
2012-10-27 09:03:43 +08:00
|
|
|
assert(ME->getBase()->getType()->isRecordType());
|
|
|
|
if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
|
2013-06-15 08:30:29 +08:00
|
|
|
if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
|
2013-06-03 15:13:35 +08:00
|
|
|
E = ME->getBase();
|
|
|
|
Adjustments.push_back(SubobjectAdjustment(Field));
|
|
|
|
continue;
|
|
|
|
}
|
2012-10-27 09:03:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
|
2018-07-25 05:18:30 +08:00
|
|
|
if (BO->getOpcode() == BO_PtrMemD) {
|
2012-11-01 22:32:20 +08:00
|
|
|
assert(BO->getRHS()->isRValue());
|
2012-10-27 09:03:43 +08:00
|
|
|
E = BO->getLHS();
|
|
|
|
const MemberPointerType *MPT =
|
|
|
|
BO->getRHS()->getType()->getAs<MemberPointerType>();
|
|
|
|
Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS()));
|
2013-06-03 08:17:11 +08:00
|
|
|
continue;
|
|
|
|
} else if (BO->getOpcode() == BO_Comma) {
|
|
|
|
CommaLHSs.push_back(BO->getLHS());
|
|
|
|
E = BO->getRHS();
|
|
|
|
continue;
|
2012-10-27 09:03:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing changed.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2019-11-21 07:39:22 +08:00
|
|
|
bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
|
2011-04-15 08:35:48 +08:00
|
|
|
const Expr *E = IgnoreParens();
|
|
|
|
|
2010-04-17 07:34:13 +08:00
|
|
|
// If this value has _Bool type, it is obvious 0/1.
|
2011-04-15 08:35:48 +08:00
|
|
|
if (E->getType()->isBooleanType()) return true;
|
2018-07-31 03:24:48 +08:00
|
|
|
// If this is a non-scalar-integer type, we don't care enough to try.
|
2011-04-15 08:35:48 +08:00
|
|
|
if (!E->getType()->isIntegralOrEnumerationType()) return false;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-04-15 08:35:48 +08:00
|
|
|
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
|
2010-04-17 07:34:13 +08:00
|
|
|
switch (UO->getOpcode()) {
|
2010-08-25 19:45:40 +08:00
|
|
|
case UO_Plus:
|
2019-11-21 07:39:22 +08:00
|
|
|
return UO->getSubExpr()->isKnownToHaveBooleanValue(Semantic);
|
2014-04-04 12:13:47 +08:00
|
|
|
case UO_LNot:
|
|
|
|
return true;
|
2010-04-17 07:34:13 +08:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-06-12 09:56:02 +08:00
|
|
|
// Only look through implicit casts. If the user writes
|
|
|
|
// '(int) (a && b)' treat it as an arbitrary int.
|
2019-11-21 07:39:22 +08:00
|
|
|
// FIXME: Should we look through any cast expression in !Semantic mode?
|
2011-04-15 08:35:48 +08:00
|
|
|
if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
|
2019-11-21 07:39:22 +08:00
|
|
|
return CE->getSubExpr()->isKnownToHaveBooleanValue(Semantic);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-04-15 08:35:48 +08:00
|
|
|
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
|
2010-04-17 07:34:13 +08:00
|
|
|
switch (BO->getOpcode()) {
|
|
|
|
default: return false;
|
2010-08-25 19:45:40 +08:00
|
|
|
case BO_LT: // Relational operators.
|
|
|
|
case BO_GT:
|
|
|
|
case BO_LE:
|
|
|
|
case BO_GE:
|
|
|
|
case BO_EQ: // Equality operators.
|
|
|
|
case BO_NE:
|
|
|
|
case BO_LAnd: // AND operator.
|
|
|
|
case BO_LOr: // Logical OR operator.
|
2010-04-17 07:34:13 +08:00
|
|
|
return true;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-08-25 19:45:40 +08:00
|
|
|
case BO_And: // Bitwise AND operator.
|
|
|
|
case BO_Xor: // Bitwise XOR operator.
|
|
|
|
case BO_Or: // Bitwise OR operator.
|
2010-04-17 07:34:13 +08:00
|
|
|
// Handle things like (x==2)|(y==12).
|
2019-11-21 07:39:22 +08:00
|
|
|
return BO->getLHS()->isKnownToHaveBooleanValue(Semantic) &&
|
|
|
|
BO->getRHS()->isKnownToHaveBooleanValue(Semantic);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-08-25 19:45:40 +08:00
|
|
|
case BO_Comma:
|
|
|
|
case BO_Assign:
|
2019-11-21 07:39:22 +08:00
|
|
|
return BO->getRHS()->isKnownToHaveBooleanValue(Semantic);
|
2010-04-17 07:34:13 +08:00
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-04-15 08:35:48 +08:00
|
|
|
if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
|
2019-11-21 07:39:22 +08:00
|
|
|
return CO->getTrueExpr()->isKnownToHaveBooleanValue(Semantic) &&
|
|
|
|
CO->getFalseExpr()->isKnownToHaveBooleanValue(Semantic);
|
2019-09-18 05:11:51 +08:00
|
|
|
|
|
|
|
if (isa<ObjCBoolLiteralExpr>(E))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
|
2019-11-21 07:39:22 +08:00
|
|
|
return OVE->getSourceExpr()->isKnownToHaveBooleanValue(Semantic);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2019-11-19 02:56:05 +08:00
|
|
|
if (const FieldDecl *FD = E->getSourceBitField())
|
2019-11-21 07:39:22 +08:00
|
|
|
if (!Semantic && FD->getType()->isUnsignedIntegerType() &&
|
2019-11-19 02:56:05 +08:00
|
|
|
!FD->getBitWidth()->isValueDependent() &&
|
|
|
|
FD->getBitWidthValue(FD->getASTContext()) == 1)
|
|
|
|
return true;
|
|
|
|
|
2010-04-17 07:34:13 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-02-09 16:16:59 +08:00
|
|
|
// Amusing macro metaprogramming hack: check whether a class provides
|
|
|
|
// a more specific implementation of getExprLoc().
|
2012-03-09 23:39:19 +08:00
|
|
|
//
|
2018-08-10 05:09:38 +08:00
|
|
|
// See also Stmt.cpp:{getBeginLoc(),getEndLoc()}.
|
2017-11-18 02:09:48 +08:00
|
|
|
namespace {
|
|
|
|
/// This implementation is used when a class provides a custom
|
|
|
|
/// implementation of getExprLoc.
|
|
|
|
template <class E, class T>
|
|
|
|
SourceLocation getExprLocImpl(const Expr *expr,
|
|
|
|
SourceLocation (T::*v)() const) {
|
|
|
|
return static_cast<const E*>(expr)->getExprLoc();
|
|
|
|
}
|
2011-02-09 16:16:59 +08:00
|
|
|
|
2017-11-18 02:09:48 +08:00
|
|
|
/// This implementation is used when a class doesn't provide
|
|
|
|
/// a custom implementation of getExprLoc. Overload resolution
|
|
|
|
/// should pick it over the implementation above because it's
|
|
|
|
/// more specialized according to function template partial ordering.
|
|
|
|
template <class E>
|
|
|
|
SourceLocation getExprLocImpl(const Expr *expr,
|
|
|
|
SourceLocation (Expr::*v)() const) {
|
2018-08-10 05:08:08 +08:00
|
|
|
return static_cast<const E *>(expr)->getBeginLoc();
|
2017-11-18 02:09:48 +08:00
|
|
|
}
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2011-02-09 16:16:59 +08:00
|
|
|
|
|
|
|
SourceLocation Expr::getExprLoc() const {
|
|
|
|
switch (getStmtClass()) {
|
|
|
|
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
|
|
|
|
#define ABSTRACT_STMT(type)
|
|
|
|
#define STMT(type, base) \
|
2014-07-26 08:47:13 +08:00
|
|
|
case Stmt::type##Class: break;
|
2011-02-09 16:16:59 +08:00
|
|
|
#define EXPR(type, base) \
|
|
|
|
case Stmt::type##Class: return getExprLocImpl<type>(this, &type::getExprLoc);
|
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
}
|
2014-07-26 08:47:13 +08:00
|
|
|
llvm_unreachable("unknown expression kind");
|
2011-02-09 16:16:59 +08:00
|
|
|
}
|
|
|
|
|
2006-08-24 12:56:27 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Primary Expressions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
static void AssertResultStorageKind(ConstantExpr::ResultStorageKind Kind) {
|
|
|
|
assert((Kind == ConstantExpr::RSK_APValue ||
|
|
|
|
Kind == ConstantExpr::RSK_Int64 || Kind == ConstantExpr::RSK_None) &&
|
|
|
|
"Invalid StorageKind Value");
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstantExpr::ResultStorageKind
|
|
|
|
ConstantExpr::getStorageKind(const APValue &Value) {
|
|
|
|
switch (Value.getKind()) {
|
|
|
|
case APValue::None:
|
2019-06-21 16:26:21 +08:00
|
|
|
case APValue::Indeterminate:
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
return ConstantExpr::RSK_None;
|
|
|
|
case APValue::Int:
|
|
|
|
if (!Value.getInt().needsCleanup())
|
|
|
|
return ConstantExpr::RSK_Int64;
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
default:
|
|
|
|
return ConstantExpr::RSK_APValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-21 16:26:21 +08:00
|
|
|
ConstantExpr::ResultStorageKind
|
|
|
|
ConstantExpr::getStorageKind(const Type *T, const ASTContext &Context) {
|
|
|
|
if (T->isIntegralOrEnumerationType() && Context.getTypeInfo(T).Width <= 64)
|
|
|
|
return ConstantExpr::RSK_Int64;
|
|
|
|
return ConstantExpr::RSK_APValue;
|
|
|
|
}
|
|
|
|
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) {
|
|
|
|
ConstantExprBits.ResultKind = StorageKind;
|
2019-06-21 16:26:21 +08:00
|
|
|
ConstantExprBits.APValueKind = APValue::None;
|
|
|
|
ConstantExprBits.HasCleanup = false;
|
|
|
|
if (StorageKind == ConstantExpr::RSK_APValue)
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
::new (getTrailingObjects<APValue>()) APValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstantExpr::ConstantExpr(Expr *subexpr, ResultStorageKind StorageKind)
|
|
|
|
: FullExpr(ConstantExprClass, subexpr) {
|
|
|
|
DefaultInit(StorageKind);
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E,
|
2020-02-05 02:23:33 +08:00
|
|
|
ResultStorageKind StorageKind,
|
|
|
|
bool IsImmediateInvocation) {
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
assert(!isa<ConstantExpr>(E));
|
|
|
|
AssertResultStorageKind(StorageKind);
|
|
|
|
unsigned Size = totalSizeToAlloc<APValue, uint64_t>(
|
|
|
|
StorageKind == ConstantExpr::RSK_APValue,
|
|
|
|
StorageKind == ConstantExpr::RSK_Int64);
|
|
|
|
void *Mem = Context.Allocate(Size, alignof(ConstantExpr));
|
|
|
|
ConstantExpr *Self = new (Mem) ConstantExpr(E, StorageKind);
|
2020-02-05 02:23:33 +08:00
|
|
|
Self->ConstantExprBits.IsImmediateInvocation =
|
|
|
|
IsImmediateInvocation;
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
return Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E,
|
|
|
|
const APValue &Result) {
|
|
|
|
ResultStorageKind StorageKind = getStorageKind(Result);
|
|
|
|
ConstantExpr *Self = Create(Context, E, StorageKind);
|
2019-06-21 16:26:21 +08:00
|
|
|
Self->SetResult(Result, Context);
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
return Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstantExpr::ConstantExpr(ResultStorageKind StorageKind, EmptyShell Empty)
|
|
|
|
: FullExpr(ConstantExprClass, Empty) {
|
|
|
|
DefaultInit(StorageKind);
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstantExpr *ConstantExpr::CreateEmpty(const ASTContext &Context,
|
|
|
|
ResultStorageKind StorageKind,
|
|
|
|
EmptyShell Empty) {
|
|
|
|
AssertResultStorageKind(StorageKind);
|
|
|
|
unsigned Size = totalSizeToAlloc<APValue, uint64_t>(
|
|
|
|
StorageKind == ConstantExpr::RSK_APValue,
|
|
|
|
StorageKind == ConstantExpr::RSK_Int64);
|
|
|
|
void *Mem = Context.Allocate(Size, alignof(ConstantExpr));
|
|
|
|
ConstantExpr *Self = new (Mem) ConstantExpr(StorageKind, Empty);
|
|
|
|
return Self;
|
|
|
|
}
|
|
|
|
|
2019-06-21 16:26:21 +08:00
|
|
|
void ConstantExpr::MoveIntoResult(APValue &Value, const ASTContext &Context) {
|
2020-02-05 18:49:43 +08:00
|
|
|
assert((unsigned)getStorageKind(Value) <= ConstantExprBits.ResultKind &&
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
"Invalid storage for this value kind");
|
2019-06-21 16:26:21 +08:00
|
|
|
ConstantExprBits.APValueKind = Value.getKind();
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
switch (ConstantExprBits.ResultKind) {
|
|
|
|
case RSK_None:
|
|
|
|
return;
|
|
|
|
case RSK_Int64:
|
|
|
|
Int64Result() = *Value.getInt().getRawData();
|
|
|
|
ConstantExprBits.BitWidth = Value.getInt().getBitWidth();
|
|
|
|
ConstantExprBits.IsUnsigned = Value.getInt().isUnsigned();
|
|
|
|
return;
|
|
|
|
case RSK_APValue:
|
2019-06-21 16:26:21 +08:00
|
|
|
if (!ConstantExprBits.HasCleanup && Value.needsCleanup()) {
|
|
|
|
ConstantExprBits.HasCleanup = true;
|
|
|
|
Context.addDestruction(&APValueResult());
|
|
|
|
}
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
APValueResult() = std::move(Value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Invalid ResultKind Bits");
|
|
|
|
}
|
|
|
|
|
2019-06-21 16:26:21 +08:00
|
|
|
llvm::APSInt ConstantExpr::getResultAsAPSInt() const {
|
|
|
|
switch (ConstantExprBits.ResultKind) {
|
|
|
|
case ConstantExpr::RSK_APValue:
|
|
|
|
return APValueResult().getInt();
|
|
|
|
case ConstantExpr::RSK_Int64:
|
|
|
|
return llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()),
|
|
|
|
ConstantExprBits.IsUnsigned);
|
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid Accessor");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
APValue ConstantExpr::getAPValueResult() const {
|
|
|
|
switch (ConstantExprBits.ResultKind) {
|
|
|
|
case ConstantExpr::RSK_APValue:
|
|
|
|
return APValueResult();
|
|
|
|
case ConstantExpr::RSK_Int64:
|
|
|
|
return APValue(
|
|
|
|
llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()),
|
|
|
|
ConstantExprBits.IsUnsigned));
|
|
|
|
case ConstantExpr::RSK_None:
|
|
|
|
return APValue();
|
|
|
|
}
|
|
|
|
llvm_unreachable("invalid ResultKind");
|
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
/// Compute the type-, value-, and instantiation-dependence of a
|
2011-07-01 09:22:09 +08:00
|
|
|
/// declaration reference
|
2011-01-20 05:52:31 +08:00
|
|
|
/// based on the declaration being referenced.
|
2013-08-22 12:58:56 +08:00
|
|
|
static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D,
|
|
|
|
QualType T, bool &TypeDependent,
|
2011-07-01 09:22:09 +08:00
|
|
|
bool &ValueDependent,
|
|
|
|
bool &InstantiationDependent) {
|
2011-01-20 05:52:31 +08:00
|
|
|
TypeDependent = false;
|
|
|
|
ValueDependent = false;
|
2011-07-01 09:22:09 +08:00
|
|
|
InstantiationDependent = false;
|
2009-11-23 19:41:28 +08:00
|
|
|
|
|
|
|
// (TD) C++ [temp.dep.expr]p3:
|
|
|
|
// An id-expression is type-dependent if it contains:
|
|
|
|
//
|
2014-10-17 10:46:42 +08:00
|
|
|
// and
|
2009-11-23 19:41:28 +08:00
|
|
|
//
|
|
|
|
// (VD) C++ [temp.dep.constexpr]p2:
|
|
|
|
// An identifier is value-dependent if it is:
|
2014-10-17 10:46:42 +08:00
|
|
|
|
2009-11-23 19:41:28 +08:00
|
|
|
// (TD) - an identifier that was declared with dependent type
|
|
|
|
// (VD) - a name declared with a dependent type,
|
2011-01-20 05:52:31 +08:00
|
|
|
if (T->isDependentType()) {
|
|
|
|
TypeDependent = true;
|
|
|
|
ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
InstantiationDependent = true;
|
2011-01-20 05:52:31 +08:00
|
|
|
return;
|
2011-07-01 09:22:09 +08:00
|
|
|
} else if (T->isInstantiationDependentType()) {
|
|
|
|
InstantiationDependent = true;
|
2009-11-23 19:41:28 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-11-23 19:41:28 +08:00
|
|
|
// (TD) - a conversion-function-id that specifies a dependent type
|
2018-07-31 03:24:48 +08:00
|
|
|
if (D->getDeclName().getNameKind()
|
2011-07-01 09:22:09 +08:00
|
|
|
== DeclarationName::CXXConversionFunctionName) {
|
|
|
|
QualType T = D->getDeclName().getCXXNameType();
|
|
|
|
if (T->isDependentType()) {
|
|
|
|
TypeDependent = true;
|
|
|
|
ValueDependent = true;
|
|
|
|
InstantiationDependent = true;
|
|
|
|
return;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-07-01 09:22:09 +08:00
|
|
|
if (T->isInstantiationDependentType())
|
|
|
|
InstantiationDependent = true;
|
2009-11-23 19:41:28 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-11-23 19:41:28 +08:00
|
|
|
// (VD) - the name of a non-type template parameter,
|
2011-01-20 05:52:31 +08:00
|
|
|
if (isa<NonTypeTemplateParmDecl>(D)) {
|
|
|
|
ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
InstantiationDependent = true;
|
2011-01-20 05:52:31 +08:00
|
|
|
return;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-11-23 19:41:28 +08:00
|
|
|
// (VD) - a constant with integral or enumeration type and is
|
|
|
|
// initialized with an expression that is value-dependent.
|
2011-11-08 09:31:09 +08:00
|
|
|
// (VD) - a constant with literal type and is initialized with an
|
|
|
|
// expression that is value-dependent [C++11].
|
|
|
|
// (VD) - FIXME: Missing from the standard:
|
|
|
|
// - an entity with reference type and is initialized with an
|
|
|
|
// expression that is value-dependent [C++11]
|
2011-01-20 05:52:31 +08:00
|
|
|
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
2013-01-02 19:42:31 +08:00
|
|
|
if ((Ctx.getLangOpts().CPlusPlus11 ?
|
2013-04-22 23:31:51 +08:00
|
|
|
Var->getType()->isLiteralType(Ctx) :
|
2011-11-08 09:31:09 +08:00
|
|
|
Var->getType()->isIntegralOrEnumerationType()) &&
|
2012-08-10 08:55:35 +08:00
|
|
|
(Var->getType().isConstQualified() ||
|
2011-11-08 09:31:09 +08:00
|
|
|
Var->getType()->isReferenceType())) {
|
2010-02-02 04:16:42 +08:00
|
|
|
if (const Expr *Init = Var->getAnyInitializer())
|
2011-07-01 09:22:09 +08:00
|
|
|
if (Init->isValueDependent()) {
|
2011-01-20 05:52:31 +08:00
|
|
|
ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
InstantiationDependent = true;
|
|
|
|
}
|
2011-11-08 09:31:09 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
// (VD) - FIXME: Missing from the standard:
|
|
|
|
// - a member function or a static data member of the current
|
2010-05-11 16:41:30 +08:00
|
|
|
// instantiation
|
2018-07-31 03:24:48 +08:00
|
|
|
if (Var->isStaticDataMember() &&
|
2011-11-08 09:31:09 +08:00
|
|
|
Var->getDeclContext()->isDependentContext()) {
|
2011-01-20 05:52:31 +08:00
|
|
|
ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
InstantiationDependent = true;
|
2013-11-15 06:40:45 +08:00
|
|
|
TypeSourceInfo *TInfo = Var->getFirstDecl()->getTypeSourceInfo();
|
|
|
|
if (TInfo->getType()->isIncompleteArrayType())
|
|
|
|
TypeDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-01-20 05:52:31 +08:00
|
|
|
return;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
// (VD) - FIXME: Missing from the standard:
|
|
|
|
// - a member function or a static data member of the current
|
2010-05-11 16:41:30 +08:00
|
|
|
// instantiation
|
2011-01-20 05:52:31 +08:00
|
|
|
if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext()) {
|
|
|
|
ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
InstantiationDependent = true;
|
2011-11-08 09:31:09 +08:00
|
|
|
}
|
2011-01-20 05:52:31 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 12:58:56 +08:00
|
|
|
void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
|
2011-01-20 05:52:31 +08:00
|
|
|
bool TypeDependent = false;
|
|
|
|
bool ValueDependent = false;
|
2011-07-01 09:22:09 +08:00
|
|
|
bool InstantiationDependent = false;
|
2012-03-09 09:51:51 +08:00
|
|
|
computeDeclRefDependence(Ctx, getDecl(), getType(), TypeDependent,
|
|
|
|
ValueDependent, InstantiationDependent);
|
2014-10-17 10:46:42 +08:00
|
|
|
|
|
|
|
ExprBits.TypeDependent |= TypeDependent;
|
|
|
|
ExprBits.ValueDependent |= ValueDependent;
|
|
|
|
ExprBits.InstantiationDependent |= InstantiationDependent;
|
|
|
|
|
2010-12-24 07:51:58 +08:00
|
|
|
// Is the declaration a parameter pack?
|
2011-01-20 05:52:31 +08:00
|
|
|
if (getDecl()->isParameterPack())
|
2011-01-06 05:11:38 +08:00
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
2009-11-23 19:41:28 +08:00
|
|
|
}
|
|
|
|
|
2018-12-21 22:10:18 +08:00
|
|
|
DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
|
|
|
|
bool RefersToEnclosingVariableOrCapture, QualType T,
|
|
|
|
ExprValueKind VK, SourceLocation L,
|
2019-06-12 01:50:32 +08:00
|
|
|
const DeclarationNameLoc &LocInfo,
|
|
|
|
NonOdrUseReason NOUR)
|
2018-12-21 22:10:18 +08:00
|
|
|
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
|
|
|
|
D(D), DNLoc(LocInfo) {
|
|
|
|
DeclRefExprBits.HasQualifier = false;
|
|
|
|
DeclRefExprBits.HasTemplateKWAndArgsInfo = false;
|
|
|
|
DeclRefExprBits.HasFoundDecl = false;
|
|
|
|
DeclRefExprBits.HadMultipleCandidates = false;
|
|
|
|
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
|
|
|
|
RefersToEnclosingVariableOrCapture;
|
2019-06-12 01:50:32 +08:00
|
|
|
DeclRefExprBits.NonOdrUseReason = NOUR;
|
2018-12-21 22:10:18 +08:00
|
|
|
DeclRefExprBits.Loc = L;
|
|
|
|
computeDependence(Ctx);
|
|
|
|
}
|
|
|
|
|
2013-08-22 12:58:56 +08:00
|
|
|
DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
|
2012-03-09 09:51:51 +08:00
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
2018-12-21 22:10:18 +08:00
|
|
|
SourceLocation TemplateKWLoc, ValueDecl *D,
|
|
|
|
bool RefersToEnclosingVariableOrCapture,
|
|
|
|
const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
|
2010-08-12 06:01:17 +08:00
|
|
|
const TemplateArgumentListInfo *TemplateArgs,
|
2019-06-12 01:50:32 +08:00
|
|
|
QualType T, ExprValueKind VK, NonOdrUseReason NOUR)
|
2018-12-21 22:10:18 +08:00
|
|
|
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
|
|
|
|
D(D), DNLoc(NameInfo.getInfo()) {
|
2018-11-14 01:56:44 +08:00
|
|
|
DeclRefExprBits.Loc = NameInfo.getLoc();
|
2011-05-02 05:29:53 +08:00
|
|
|
DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0;
|
2014-10-17 10:46:42 +08:00
|
|
|
if (QualifierLoc) {
|
2015-12-30 02:15:14 +08:00
|
|
|
new (getTrailingObjects<NestedNameSpecifierLoc>())
|
|
|
|
NestedNameSpecifierLoc(QualifierLoc);
|
2014-10-17 10:46:42 +08:00
|
|
|
auto *NNS = QualifierLoc.getNestedNameSpecifier();
|
|
|
|
if (NNS->isInstantiationDependent())
|
|
|
|
ExprBits.InstantiationDependent = true;
|
|
|
|
if (NNS->containsUnexpandedParameterPack())
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
|
|
|
}
|
Add an optional field attached to a DeclRefExpr which points back to the
Decl actually found via name lookup & overload resolution when that Decl
is different from the ValueDecl which is actually referenced by the
expression.
This can be used by AST consumers to correctly attribute references to
the spelling location of a using declaration, and otherwise gain insight
into the name resolution performed by Clang.
The public interface to DRE is kept as narrow as possible: we provide
a getFoundDecl() which always returns a NamedDecl, either the ValueDecl
referenced or the new, more precise NamedDecl if present. This way AST
clients can code against getFoundDecl without know when exactly the AST
has a split representation.
For an example of the data this provides consider:
% cat x.cc
namespace N1 {
struct S {};
void f(const S&);
}
void test(N1::S s) {
f(s);
using N1::f;
f(s);
}
% ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc
[...]
void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1>
(CallExpr 0x5b01df0 <line:6:3, col:6> 'void'
(ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)'))
(ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))
(DeclStmt 0x5b01ee0 <line:7:3, col:14>
0x5b01e40 "UsingN1::;")
(CallExpr 0x5b01fc8 <line:8:3, col:6> 'void'
(ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f')))
(ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))))
Now we can tell that the second call is 'using' (no pun intended) the using
declaration, and *which* using declaration it sees. Without this, we can
mistake calls that go through using declarations for ADL calls, and have no way
to attribute names looked up with using declarations to the appropriate
UsingDecl.
llvm-svn: 130670
2011-05-02 07:48:14 +08:00
|
|
|
DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0;
|
|
|
|
if (FoundD)
|
2015-12-30 02:15:14 +08:00
|
|
|
*getTrailingObjects<NamedDecl *>() = FoundD;
|
2012-01-27 17:46:47 +08:00
|
|
|
DeclRefExprBits.HasTemplateKWAndArgsInfo
|
|
|
|
= (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
|
2015-01-12 18:17:46 +08:00
|
|
|
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
|
|
|
|
RefersToEnclosingVariableOrCapture;
|
2019-06-12 01:50:32 +08:00
|
|
|
DeclRefExprBits.NonOdrUseReason = NOUR;
|
2011-07-01 09:22:09 +08:00
|
|
|
if (TemplateArgs) {
|
|
|
|
bool Dependent = false;
|
|
|
|
bool InstantiationDependent = false;
|
|
|
|
bool ContainsUnexpandedParameterPack = false;
|
2015-12-30 02:15:14 +08:00
|
|
|
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
|
|
|
|
TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
|
|
|
|
Dependent, InstantiationDependent, ContainsUnexpandedParameterPack);
|
2014-10-17 10:46:42 +08:00
|
|
|
assert(!Dependent && "built a DeclRefExpr with dependent template args");
|
|
|
|
ExprBits.InstantiationDependent |= InstantiationDependent;
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
|
2012-01-27 17:46:47 +08:00
|
|
|
} else if (TemplateKWLoc.isValid()) {
|
2015-12-30 02:15:14 +08:00
|
|
|
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
|
|
|
|
TemplateKWLoc);
|
2011-07-01 09:22:09 +08:00
|
|
|
}
|
2011-10-10 20:54:05 +08:00
|
|
|
DeclRefExprBits.HadMultipleCandidates = 0;
|
|
|
|
|
2012-03-09 09:51:51 +08:00
|
|
|
computeDependence(Ctx);
|
2010-08-12 06:01:17 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 12:58:56 +08:00
|
|
|
DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
|
2011-03-01 05:54:11 +08:00
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
2019-06-12 01:50:32 +08:00
|
|
|
SourceLocation TemplateKWLoc, ValueDecl *D,
|
2015-01-12 18:17:46 +08:00
|
|
|
bool RefersToEnclosingVariableOrCapture,
|
2019-06-12 01:50:32 +08:00
|
|
|
SourceLocation NameLoc, QualType T,
|
|
|
|
ExprValueKind VK, NamedDecl *FoundD,
|
|
|
|
const TemplateArgumentListInfo *TemplateArgs,
|
|
|
|
NonOdrUseReason NOUR) {
|
2012-01-27 17:46:47 +08:00
|
|
|
return Create(Context, QualifierLoc, TemplateKWLoc, D,
|
2015-01-12 18:17:46 +08:00
|
|
|
RefersToEnclosingVariableOrCapture,
|
2010-08-12 06:01:17 +08:00
|
|
|
DeclarationNameInfo(D->getDeclName(), NameLoc),
|
2019-06-12 01:50:32 +08:00
|
|
|
T, VK, FoundD, TemplateArgs, NOUR);
|
2010-08-12 06:01:17 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 12:58:56 +08:00
|
|
|
DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
|
2011-03-01 05:54:11 +08:00
|
|
|
NestedNameSpecifierLoc QualifierLoc,
|
2019-06-12 01:50:32 +08:00
|
|
|
SourceLocation TemplateKWLoc, ValueDecl *D,
|
2015-01-12 18:17:46 +08:00
|
|
|
bool RefersToEnclosingVariableOrCapture,
|
2010-08-12 06:01:17 +08:00
|
|
|
const DeclarationNameInfo &NameInfo,
|
2019-06-12 01:50:32 +08:00
|
|
|
QualType T, ExprValueKind VK,
|
Add an optional field attached to a DeclRefExpr which points back to the
Decl actually found via name lookup & overload resolution when that Decl
is different from the ValueDecl which is actually referenced by the
expression.
This can be used by AST consumers to correctly attribute references to
the spelling location of a using declaration, and otherwise gain insight
into the name resolution performed by Clang.
The public interface to DRE is kept as narrow as possible: we provide
a getFoundDecl() which always returns a NamedDecl, either the ValueDecl
referenced or the new, more precise NamedDecl if present. This way AST
clients can code against getFoundDecl without know when exactly the AST
has a split representation.
For an example of the data this provides consider:
% cat x.cc
namespace N1 {
struct S {};
void f(const S&);
}
void test(N1::S s) {
f(s);
using N1::f;
f(s);
}
% ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc
[...]
void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1>
(CallExpr 0x5b01df0 <line:6:3, col:6> 'void'
(ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)'))
(ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))
(DeclStmt 0x5b01ee0 <line:7:3, col:14>
0x5b01e40 "UsingN1::;")
(CallExpr 0x5b01fc8 <line:8:3, col:6> 'void'
(ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f')))
(ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))))
Now we can tell that the second call is 'using' (no pun intended) the using
declaration, and *which* using declaration it sees. Without this, we can
mistake calls that go through using declarations for ADL calls, and have no way
to attribute names looked up with using declarations to the appropriate
UsingDecl.
llvm-svn: 130670
2011-05-02 07:48:14 +08:00
|
|
|
NamedDecl *FoundD,
|
2019-06-12 01:50:32 +08:00
|
|
|
const TemplateArgumentListInfo *TemplateArgs,
|
|
|
|
NonOdrUseReason NOUR) {
|
Add an optional field attached to a DeclRefExpr which points back to the
Decl actually found via name lookup & overload resolution when that Decl
is different from the ValueDecl which is actually referenced by the
expression.
This can be used by AST consumers to correctly attribute references to
the spelling location of a using declaration, and otherwise gain insight
into the name resolution performed by Clang.
The public interface to DRE is kept as narrow as possible: we provide
a getFoundDecl() which always returns a NamedDecl, either the ValueDecl
referenced or the new, more precise NamedDecl if present. This way AST
clients can code against getFoundDecl without know when exactly the AST
has a split representation.
For an example of the data this provides consider:
% cat x.cc
namespace N1 {
struct S {};
void f(const S&);
}
void test(N1::S s) {
f(s);
using N1::f;
f(s);
}
% ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc
[...]
void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1>
(CallExpr 0x5b01df0 <line:6:3, col:6> 'void'
(ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)'))
(ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))
(DeclStmt 0x5b01ee0 <line:7:3, col:14>
0x5b01e40 "UsingN1::;")
(CallExpr 0x5b01fc8 <line:8:3, col:6> 'void'
(ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f')))
(ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))))
Now we can tell that the second call is 'using' (no pun intended) the using
declaration, and *which* using declaration it sees. Without this, we can
mistake calls that go through using declarations for ADL calls, and have no way
to attribute names looked up with using declarations to the appropriate
UsingDecl.
llvm-svn: 130670
2011-05-02 07:48:14 +08:00
|
|
|
// Filter out cases where the found Decl is the same as the value refenenced.
|
|
|
|
if (D == FoundD)
|
2014-05-12 13:36:57 +08:00
|
|
|
FoundD = nullptr;
|
Add an optional field attached to a DeclRefExpr which points back to the
Decl actually found via name lookup & overload resolution when that Decl
is different from the ValueDecl which is actually referenced by the
expression.
This can be used by AST consumers to correctly attribute references to
the spelling location of a using declaration, and otherwise gain insight
into the name resolution performed by Clang.
The public interface to DRE is kept as narrow as possible: we provide
a getFoundDecl() which always returns a NamedDecl, either the ValueDecl
referenced or the new, more precise NamedDecl if present. This way AST
clients can code against getFoundDecl without know when exactly the AST
has a split representation.
For an example of the data this provides consider:
% cat x.cc
namespace N1 {
struct S {};
void f(const S&);
}
void test(N1::S s) {
f(s);
using N1::f;
f(s);
}
% ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc
[...]
void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1>
(CallExpr 0x5b01df0 <line:6:3, col:6> 'void'
(ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)'))
(ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))
(DeclStmt 0x5b01ee0 <line:7:3, col:14>
0x5b01e40 "UsingN1::;")
(CallExpr 0x5b01fc8 <line:8:3, col:6> 'void'
(ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f')))
(ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))))
Now we can tell that the second call is 'using' (no pun intended) the using
declaration, and *which* using declaration it sees. Without this, we can
mistake calls that go through using declarations for ADL calls, and have no way
to attribute names looked up with using declarations to the appropriate
UsingDecl.
llvm-svn: 130670
2011-05-02 07:48:14 +08:00
|
|
|
|
2015-12-30 02:15:14 +08:00
|
|
|
bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
|
|
|
|
std::size_t Size =
|
|
|
|
totalSizeToAlloc<NestedNameSpecifierLoc, NamedDecl *,
|
|
|
|
ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
|
|
|
|
QualifierLoc ? 1 : 0, FoundD ? 1 : 0,
|
|
|
|
HasTemplateKWAndArgsInfo ? 1 : 0,
|
|
|
|
TemplateArgs ? TemplateArgs->size() : 0);
|
Add an optional field attached to a DeclRefExpr which points back to the
Decl actually found via name lookup & overload resolution when that Decl
is different from the ValueDecl which is actually referenced by the
expression.
This can be used by AST consumers to correctly attribute references to
the spelling location of a using declaration, and otherwise gain insight
into the name resolution performed by Clang.
The public interface to DRE is kept as narrow as possible: we provide
a getFoundDecl() which always returns a NamedDecl, either the ValueDecl
referenced or the new, more precise NamedDecl if present. This way AST
clients can code against getFoundDecl without know when exactly the AST
has a split representation.
For an example of the data this provides consider:
% cat x.cc
namespace N1 {
struct S {};
void f(const S&);
}
void test(N1::S s) {
f(s);
using N1::f;
f(s);
}
% ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc
[...]
void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1>
(CallExpr 0x5b01df0 <line:6:3, col:6> 'void'
(ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)'))
(ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))
(DeclStmt 0x5b01ee0 <line:7:3, col:14>
0x5b01e40 "UsingN1::;")
(CallExpr 0x5b01fc8 <line:8:3, col:6> 'void'
(ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f')))
(ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))))
Now we can tell that the second call is 'using' (no pun intended) the using
declaration, and *which* using declaration it sees. Without this, we can
mistake calls that go through using declarations for ADL calls, and have no way
to attribute names looked up with using declarations to the appropriate
UsingDecl.
llvm-svn: 130670
2011-05-02 07:48:14 +08:00
|
|
|
|
2016-10-20 22:27:22 +08:00
|
|
|
void *Mem = Context.Allocate(Size, alignof(DeclRefExpr));
|
2012-03-09 09:51:51 +08:00
|
|
|
return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
|
2019-06-12 01:50:32 +08:00
|
|
|
RefersToEnclosingVariableOrCapture, NameInfo,
|
|
|
|
FoundD, TemplateArgs, T, VK, NOUR);
|
2009-10-24 02:54:35 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 12:58:56 +08:00
|
|
|
DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context,
|
2011-02-04 20:01:24 +08:00
|
|
|
bool HasQualifier,
|
Add an optional field attached to a DeclRefExpr which points back to the
Decl actually found via name lookup & overload resolution when that Decl
is different from the ValueDecl which is actually referenced by the
expression.
This can be used by AST consumers to correctly attribute references to
the spelling location of a using declaration, and otherwise gain insight
into the name resolution performed by Clang.
The public interface to DRE is kept as narrow as possible: we provide
a getFoundDecl() which always returns a NamedDecl, either the ValueDecl
referenced or the new, more precise NamedDecl if present. This way AST
clients can code against getFoundDecl without know when exactly the AST
has a split representation.
For an example of the data this provides consider:
% cat x.cc
namespace N1 {
struct S {};
void f(const S&);
}
void test(N1::S s) {
f(s);
using N1::f;
f(s);
}
% ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc
[...]
void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1>
(CallExpr 0x5b01df0 <line:6:3, col:6> 'void'
(ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)'))
(ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))
(DeclStmt 0x5b01ee0 <line:7:3, col:14>
0x5b01e40 "UsingN1::;")
(CallExpr 0x5b01fc8 <line:8:3, col:6> 'void'
(ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
(DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f')))
(ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp>
(DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))))
Now we can tell that the second call is 'using' (no pun intended) the using
declaration, and *which* using declaration it sees. Without this, we can
mistake calls that go through using declarations for ADL calls, and have no way
to attribute names looked up with using declarations to the appropriate
UsingDecl.
llvm-svn: 130670
2011-05-02 07:48:14 +08:00
|
|
|
bool HasFoundDecl,
|
2012-01-27 17:46:47 +08:00
|
|
|
bool HasTemplateKWAndArgsInfo,
|
2010-07-08 21:09:47 +08:00
|
|
|
unsigned NumTemplateArgs) {
|
2015-12-30 02:15:14 +08:00
|
|
|
assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
|
|
|
|
std::size_t Size =
|
|
|
|
totalSizeToAlloc<NestedNameSpecifierLoc, NamedDecl *,
|
|
|
|
ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
|
|
|
|
HasQualifier ? 1 : 0, HasFoundDecl ? 1 : 0, HasTemplateKWAndArgsInfo,
|
|
|
|
NumTemplateArgs);
|
2016-10-20 22:27:22 +08:00
|
|
|
void *Mem = Context.Allocate(Size, alignof(DeclRefExpr));
|
2010-07-08 21:09:47 +08:00
|
|
|
return new (Mem) DeclRefExpr(EmptyShell());
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:03 +08:00
|
|
|
SourceLocation DeclRefExpr::getBeginLoc() const {
|
2012-03-09 23:39:15 +08:00
|
|
|
if (hasQualifier())
|
|
|
|
return getQualifierLoc().getBeginLoc();
|
2018-08-10 05:08:08 +08:00
|
|
|
return getNameInfo().getBeginLoc();
|
2012-03-09 23:39:15 +08:00
|
|
|
}
|
2018-08-10 04:05:47 +08:00
|
|
|
SourceLocation DeclRefExpr::getEndLoc() const {
|
2012-03-09 23:39:15 +08:00
|
|
|
if (hasExplicitTemplateArgs())
|
|
|
|
return getRAngleLoc();
|
2018-08-10 05:09:38 +08:00
|
|
|
return getNameInfo().getEndLoc();
|
2012-03-09 23:39:15 +08:00
|
|
|
}
|
2009-10-24 02:54:35 +08:00
|
|
|
|
2018-10-28 03:21:19 +08:00
|
|
|
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
|
2014-10-09 16:45:04 +08:00
|
|
|
StringLiteral *SL)
|
|
|
|
: Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary,
|
|
|
|
FNTy->isDependentType(), FNTy->isDependentType(),
|
|
|
|
FNTy->isInstantiationDependentType(),
|
2018-10-28 03:21:19 +08:00
|
|
|
/*ContainsUnexpandedParameterPack=*/false) {
|
|
|
|
PredefinedExprBits.Kind = IK;
|
|
|
|
assert((getIdentKind() == IK) &&
|
|
|
|
"IdentKind do not fit in PredefinedExprBitfields!");
|
|
|
|
bool HasFunctionName = SL != nullptr;
|
|
|
|
PredefinedExprBits.HasFunctionName = HasFunctionName;
|
|
|
|
PredefinedExprBits.Loc = L;
|
|
|
|
if (HasFunctionName)
|
|
|
|
setFunctionName(SL);
|
|
|
|
}
|
|
|
|
|
|
|
|
PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName)
|
|
|
|
: Expr(PredefinedExprClass, Empty) {
|
|
|
|
PredefinedExprBits.HasFunctionName = HasFunctionName;
|
|
|
|
}
|
|
|
|
|
|
|
|
PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
|
|
|
|
QualType FNTy, IdentKind IK,
|
|
|
|
StringLiteral *SL) {
|
|
|
|
bool HasFunctionName = SL != nullptr;
|
|
|
|
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
|
|
|
|
alignof(PredefinedExpr));
|
|
|
|
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
|
|
|
|
}
|
2014-10-09 16:45:04 +08:00
|
|
|
|
2018-10-28 03:21:19 +08:00
|
|
|
PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx,
|
|
|
|
bool HasFunctionName) {
|
|
|
|
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
|
|
|
|
alignof(PredefinedExpr));
|
|
|
|
return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName);
|
2014-10-09 16:45:04 +08:00
|
|
|
}
|
|
|
|
|
2018-10-28 03:21:19 +08:00
|
|
|
StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) {
|
|
|
|
switch (IK) {
|
2014-10-09 16:45:04 +08:00
|
|
|
case Func:
|
|
|
|
return "__func__";
|
|
|
|
case Function:
|
|
|
|
return "__FUNCTION__";
|
|
|
|
case FuncDName:
|
|
|
|
return "__FUNCDNAME__";
|
|
|
|
case LFunction:
|
|
|
|
return "L__FUNCTION__";
|
|
|
|
case PrettyFunction:
|
|
|
|
return "__PRETTY_FUNCTION__";
|
|
|
|
case FuncSig:
|
|
|
|
return "__FUNCSIG__";
|
2018-07-27 07:18:44 +08:00
|
|
|
case LFuncSig:
|
|
|
|
return "L__FUNCSIG__";
|
2014-10-09 16:45:04 +08:00
|
|
|
case PrettyFunctionNoVirtual:
|
|
|
|
break;
|
|
|
|
}
|
2018-10-28 03:21:19 +08:00
|
|
|
llvm_unreachable("Unknown ident kind for PredefinedExpr");
|
2014-10-09 16:45:04 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 02:24:21 +08:00
|
|
|
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
|
|
|
|
// expr" policy instead.
|
2018-10-28 03:21:19 +08:00
|
|
|
std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {
|
2010-02-12 02:20:28 +08:00
|
|
|
ASTContext &Context = CurrentDecl->getASTContext();
|
|
|
|
|
2018-10-28 03:21:19 +08:00
|
|
|
if (IK == PredefinedExpr::FuncDName) {
|
2013-11-07 07:31:56 +08:00
|
|
|
if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) {
|
2014-03-08 04:03:18 +08:00
|
|
|
std::unique_ptr<MangleContext> MC;
|
2013-11-07 07:31:56 +08:00
|
|
|
MC.reset(Context.createMangleContext());
|
|
|
|
|
|
|
|
if (MC->shouldMangleDeclName(ND)) {
|
|
|
|
SmallString<256> Buffer;
|
|
|
|
llvm::raw_svector_ostream Out(Buffer);
|
|
|
|
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND))
|
|
|
|
MC->mangleCXXCtor(CD, Ctor_Base, Out);
|
|
|
|
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(ND))
|
|
|
|
MC->mangleCXXDtor(DD, Dtor_Base, Out);
|
|
|
|
else
|
|
|
|
MC->mangleName(ND, Out);
|
|
|
|
|
|
|
|
if (!Buffer.empty() && Buffer.front() == '\01')
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(Buffer.substr(1));
|
|
|
|
return std::string(Buffer.str());
|
2013-11-07 07:31:56 +08:00
|
|
|
} else
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(ND->getIdentifier()->getName());
|
2013-11-07 07:31:56 +08:00
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
2016-11-16 15:07:28 +08:00
|
|
|
if (isa<BlockDecl>(CurrentDecl)) {
|
|
|
|
// For blocks we only emit something if it is enclosed in a function
|
|
|
|
// For top-level block we'd like to include the name of variable, but we
|
|
|
|
// don't have it at this point.
|
2016-11-16 06:19:50 +08:00
|
|
|
auto DC = CurrentDecl->getDeclContext();
|
|
|
|
if (DC->isFileContext())
|
2016-11-16 15:07:28 +08:00
|
|
|
return "";
|
|
|
|
|
|
|
|
SmallString<256> Buffer;
|
|
|
|
llvm::raw_svector_ostream Out(Buffer);
|
|
|
|
if (auto *DCBlock = dyn_cast<BlockDecl>(DC))
|
|
|
|
// For nested blocks, propagate up to the parent.
|
2018-10-28 03:21:19 +08:00
|
|
|
Out << ComputeName(IK, DCBlock);
|
2016-11-16 15:07:28 +08:00
|
|
|
else if (auto *DCDecl = dyn_cast<Decl>(DC))
|
2018-10-28 03:21:19 +08:00
|
|
|
Out << ComputeName(IK, DCDecl) << "_block_invoke";
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(Out.str());
|
2014-10-09 16:45:04 +08:00
|
|
|
}
|
2009-09-09 02:24:21 +08:00
|
|
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
|
2018-10-28 03:21:19 +08:00
|
|
|
if (IK != PrettyFunction && IK != PrettyFunctionNoVirtual &&
|
|
|
|
IK != FuncSig && IK != LFuncSig)
|
2009-09-09 02:24:21 +08:00
|
|
|
return FD->getNameAsString();
|
|
|
|
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<256> Name;
|
2009-09-09 02:24:21 +08:00
|
|
|
llvm::raw_svector_ostream Out(Name);
|
|
|
|
|
|
|
|
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
|
2018-10-28 03:21:19 +08:00
|
|
|
if (MD->isVirtual() && IK != PrettyFunctionNoVirtual)
|
2009-09-09 02:24:21 +08:00
|
|
|
Out << "virtual ";
|
2009-12-27 09:38:20 +08:00
|
|
|
if (MD->isStatic())
|
|
|
|
Out << "static ";
|
2009-09-09 02:24:21 +08:00
|
|
|
}
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
PrintingPolicy Policy(Context.getLangOpts());
|
2013-02-23 21:53:57 +08:00
|
|
|
std::string Proto;
|
2012-04-11 04:14:15 +08:00
|
|
|
llvm::raw_string_ostream POut(Proto);
|
2009-09-09 02:24:21 +08:00
|
|
|
|
2012-04-11 04:14:15 +08:00
|
|
|
const FunctionDecl *Decl = FD;
|
|
|
|
if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
|
|
|
|
Decl = Pattern;
|
|
|
|
const FunctionType *AFT = Decl->getType()->getAs<FunctionType>();
|
2014-05-12 13:36:57 +08:00
|
|
|
const FunctionProtoType *FT = nullptr;
|
2009-09-09 02:24:21 +08:00
|
|
|
if (FD->hasWrittenPrototype())
|
|
|
|
FT = dyn_cast<FunctionProtoType>(AFT);
|
|
|
|
|
2018-10-28 03:21:19 +08:00
|
|
|
if (IK == FuncSig || IK == LFuncSig) {
|
2017-01-10 05:40:40 +08:00
|
|
|
switch (AFT->getCallConv()) {
|
2014-04-09 02:13:24 +08:00
|
|
|
case CC_C: POut << "__cdecl "; break;
|
|
|
|
case CC_X86StdCall: POut << "__stdcall "; break;
|
|
|
|
case CC_X86FastCall: POut << "__fastcall "; break;
|
|
|
|
case CC_X86ThisCall: POut << "__thiscall "; break;
|
2014-10-25 01:42:17 +08:00
|
|
|
case CC_X86VectorCall: POut << "__vectorcall "; break;
|
2016-11-03 02:29:35 +08:00
|
|
|
case CC_X86RegCall: POut << "__regcall "; break;
|
2014-04-09 02:13:24 +08:00
|
|
|
// Only bother printing the conventions that MSVC knows about.
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FD->printQualifiedName(POut, Policy);
|
|
|
|
|
2012-04-11 04:14:15 +08:00
|
|
|
POut << "(";
|
2009-09-09 02:24:21 +08:00
|
|
|
if (FT) {
|
2012-04-11 04:14:15 +08:00
|
|
|
for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {
|
2009-09-09 02:24:21 +08:00
|
|
|
if (i) POut << ", ";
|
2012-05-05 12:20:37 +08:00
|
|
|
POut << Decl->getParamDecl(i)->getType().stream(Policy);
|
2009-09-09 02:24:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (FT->isVariadic()) {
|
|
|
|
if (FD->getNumParams()) POut << ", ";
|
|
|
|
POut << "...";
|
2018-10-28 03:21:19 +08:00
|
|
|
} else if ((IK == FuncSig || IK == LFuncSig ||
|
2018-07-27 07:18:44 +08:00
|
|
|
!Context.getLangOpts().CPlusPlus) &&
|
2017-01-10 06:16:16 +08:00
|
|
|
!Decl->getNumParams()) {
|
|
|
|
POut << "void";
|
2009-09-09 02:24:21 +08:00
|
|
|
}
|
|
|
|
}
|
2012-04-11 04:14:15 +08:00
|
|
|
POut << ")";
|
2009-09-09 02:24:21 +08:00
|
|
|
|
2009-12-27 09:38:20 +08:00
|
|
|
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
|
2017-01-10 05:40:40 +08:00
|
|
|
assert(FT && "We must have a written prototype in this case.");
|
2012-08-10 08:55:35 +08:00
|
|
|
if (FT->isConst())
|
2012-04-11 04:14:15 +08:00
|
|
|
POut << " const";
|
2012-08-10 08:55:35 +08:00
|
|
|
if (FT->isVolatile())
|
2012-04-11 04:14:15 +08:00
|
|
|
POut << " volatile";
|
|
|
|
RefQualifierKind Ref = MD->getRefQualifier();
|
|
|
|
if (Ref == RQ_LValue)
|
|
|
|
POut << " &";
|
|
|
|
else if (Ref == RQ_RValue)
|
|
|
|
POut << " &&";
|
|
|
|
}
|
|
|
|
|
2017-11-18 02:09:48 +08:00
|
|
|
typedef SmallVector<const ClassTemplateSpecializationDecl *, 8> SpecsTy;
|
2012-04-11 04:14:15 +08:00
|
|
|
SpecsTy Specs;
|
|
|
|
const DeclContext *Ctx = FD->getDeclContext();
|
|
|
|
while (Ctx && isa<NamedDecl>(Ctx)) {
|
|
|
|
const ClassTemplateSpecializationDecl *Spec
|
|
|
|
= dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
|
|
|
|
if (Spec && !Spec->isExplicitSpecialization())
|
|
|
|
Specs.push_back(Spec);
|
|
|
|
Ctx = Ctx->getParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string TemplateParams;
|
|
|
|
llvm::raw_string_ostream TOut(TemplateParams);
|
|
|
|
for (SpecsTy::reverse_iterator I = Specs.rbegin(), E = Specs.rend();
|
|
|
|
I != E; ++I) {
|
2018-07-31 03:24:48 +08:00
|
|
|
const TemplateParameterList *Params
|
2012-04-11 04:14:15 +08:00
|
|
|
= (*I)->getSpecializedTemplate()->getTemplateParameters();
|
|
|
|
const TemplateArgumentList &Args = (*I)->getTemplateArgs();
|
|
|
|
assert(Params->size() == Args.size());
|
|
|
|
for (unsigned i = 0, numParams = Params->size(); i != numParams; ++i) {
|
|
|
|
StringRef Param = Params->getParam(i)->getName();
|
|
|
|
if (Param.empty()) continue;
|
|
|
|
TOut << Param << " = ";
|
|
|
|
Args.get(i).print(Policy, TOut);
|
|
|
|
TOut << ", ";
|
|
|
|
}
|
2009-12-27 09:38:20 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
FunctionTemplateSpecializationInfo *FSI
|
2012-04-11 04:14:15 +08:00
|
|
|
= FD->getTemplateSpecializationInfo();
|
|
|
|
if (FSI && !FSI->isExplicitSpecialization()) {
|
2018-07-31 03:24:48 +08:00
|
|
|
const TemplateParameterList* Params
|
2012-04-11 04:14:15 +08:00
|
|
|
= FSI->getTemplate()->getTemplateParameters();
|
|
|
|
const TemplateArgumentList* Args = FSI->TemplateArguments;
|
|
|
|
assert(Params->size() == Args->size());
|
|
|
|
for (unsigned i = 0, e = Params->size(); i != e; ++i) {
|
|
|
|
StringRef Param = Params->getParam(i)->getName();
|
|
|
|
if (Param.empty()) continue;
|
|
|
|
TOut << Param << " = ";
|
|
|
|
Args->get(i).print(Policy, TOut);
|
|
|
|
TOut << ", ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TOut.flush();
|
|
|
|
if (!TemplateParams.empty()) {
|
|
|
|
// remove the trailing comma and space
|
|
|
|
TemplateParams.resize(TemplateParams.size() - 2);
|
|
|
|
POut << " [" << TemplateParams << "]";
|
|
|
|
}
|
|
|
|
|
|
|
|
POut.flush();
|
|
|
|
|
2013-08-21 19:45:27 +08:00
|
|
|
// Print "auto" for all deduced return types. This includes C++1y return
|
|
|
|
// type deduction and lambdas. For trailing return types resolve the
|
|
|
|
// decltype expression. Otherwise print the real type when this is
|
|
|
|
// not a constructor or destructor.
|
2014-10-09 16:45:04 +08:00
|
|
|
if (isa<CXXMethodDecl>(FD) &&
|
|
|
|
cast<CXXMethodDecl>(FD)->getParent()->isLambda())
|
2013-08-21 19:45:27 +08:00
|
|
|
Proto = "auto " + Proto;
|
2014-01-26 00:55:45 +08:00
|
|
|
else if (FT && FT->getReturnType()->getAs<DecltypeType>())
|
|
|
|
FT->getReturnType()
|
|
|
|
->getAs<DecltypeType>()
|
|
|
|
->getUnderlyingType()
|
2013-08-21 19:45:27 +08:00
|
|
|
.getAsStringInternal(Proto, Policy);
|
|
|
|
else if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
|
2014-01-26 00:55:45 +08:00
|
|
|
AFT->getReturnType().getAsStringInternal(Proto, Policy);
|
2009-09-09 02:24:21 +08:00
|
|
|
|
|
|
|
Out << Proto;
|
|
|
|
|
2020-01-30 13:27:46 +08:00
|
|
|
return std::string(Name);
|
2009-09-09 02:24:21 +08:00
|
|
|
}
|
2013-08-26 22:27:34 +08:00
|
|
|
if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(CurrentDecl)) {
|
|
|
|
for (const DeclContext *DC = CD->getParent(); DC; DC = DC->getParent())
|
|
|
|
// Skip to its enclosing function or method, but not its enclosing
|
|
|
|
// CapturedDecl.
|
|
|
|
if (DC->isFunctionOrMethod() && (DC->getDeclKind() != Decl::Captured)) {
|
|
|
|
const Decl *D = Decl::castFromDeclContext(DC);
|
2018-10-28 03:21:19 +08:00
|
|
|
return ComputeName(IK, D);
|
2013-08-26 22:27:34 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("CapturedDecl not inside a function or method");
|
|
|
|
}
|
2009-09-09 02:24:21 +08:00
|
|
|
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) {
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<256> Name;
|
2009-09-09 02:24:21 +08:00
|
|
|
llvm::raw_svector_ostream Out(Name);
|
|
|
|
Out << (MD->isInstanceMethod() ? '-' : '+');
|
|
|
|
Out << '[';
|
2010-03-19 05:23:08 +08:00
|
|
|
|
|
|
|
// For incorrect code, there might not be an ObjCInterfaceDecl. Do
|
|
|
|
// a null check to avoid a crash.
|
|
|
|
if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
|
2011-10-15 02:45:37 +08:00
|
|
|
Out << *ID;
|
2010-03-19 05:23:08 +08:00
|
|
|
|
2009-09-09 02:24:21 +08:00
|
|
|
if (const ObjCCategoryImplDecl *CID =
|
2010-04-17 17:33:03 +08:00
|
|
|
dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext()))
|
2012-02-07 19:57:45 +08:00
|
|
|
Out << '(' << *CID << ')';
|
2010-04-17 17:33:03 +08:00
|
|
|
|
2009-09-09 02:24:21 +08:00
|
|
|
Out << ' ';
|
2014-01-04 01:59:55 +08:00
|
|
|
MD->getSelector().print(Out);
|
2009-09-09 02:24:21 +08:00
|
|
|
Out << ']';
|
|
|
|
|
2020-01-30 13:27:46 +08:00
|
|
|
return std::string(Name);
|
2009-09-09 02:24:21 +08:00
|
|
|
}
|
2018-10-28 03:21:19 +08:00
|
|
|
if (isa<TranslationUnitDecl>(CurrentDecl) && IK == PrettyFunction) {
|
2009-09-09 02:24:21 +08:00
|
|
|
// __PRETTY_FUNCTION__ -> "top level", the others produce an empty string.
|
|
|
|
return "top level";
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
void APNumericStorage::setIntValue(const ASTContext &C,
|
|
|
|
const llvm::APInt &Val) {
|
2010-08-28 17:06:06 +08:00
|
|
|
if (hasAllocation())
|
|
|
|
C.Deallocate(pVal);
|
|
|
|
|
|
|
|
BitWidth = Val.getBitWidth();
|
|
|
|
unsigned NumWords = Val.getNumWords();
|
|
|
|
const uint64_t* Words = Val.getRawData();
|
|
|
|
if (NumWords > 1) {
|
|
|
|
pVal = new (C) uint64_t[NumWords];
|
|
|
|
std::copy(Words, Words + NumWords, pVal);
|
|
|
|
} else if (NumWords == 1)
|
|
|
|
VAL = Words[0];
|
|
|
|
else
|
|
|
|
VAL = 0;
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
IntegerLiteral::IntegerLiteral(const ASTContext &C, const llvm::APInt &V,
|
2012-07-05 01:04:04 +08:00
|
|
|
QualType type, SourceLocation l)
|
|
|
|
: Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
|
|
|
|
false, false),
|
|
|
|
Loc(l) {
|
|
|
|
assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
|
|
|
|
assert(V.getBitWidth() == C.getIntWidth(type) &&
|
|
|
|
"Integer type is not the correct size for constant.");
|
|
|
|
setValue(C, V);
|
|
|
|
}
|
|
|
|
|
2010-08-28 17:06:06 +08:00
|
|
|
IntegerLiteral *
|
2013-08-18 18:09:15 +08:00
|
|
|
IntegerLiteral::Create(const ASTContext &C, const llvm::APInt &V,
|
2010-08-28 17:06:06 +08:00
|
|
|
QualType type, SourceLocation l) {
|
|
|
|
return new (C) IntegerLiteral(C, V, type, l);
|
|
|
|
}
|
|
|
|
|
|
|
|
IntegerLiteral *
|
2013-08-18 18:09:15 +08:00
|
|
|
IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) {
|
2010-08-28 17:06:06 +08:00
|
|
|
return new (C) IntegerLiteral(Empty);
|
|
|
|
}
|
|
|
|
|
2018-06-21 01:19:40 +08:00
|
|
|
FixedPointLiteral::FixedPointLiteral(const ASTContext &C, const llvm::APInt &V,
|
|
|
|
QualType type, SourceLocation l,
|
|
|
|
unsigned Scale)
|
|
|
|
: Expr(FixedPointLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
|
|
|
|
false, false),
|
|
|
|
Loc(l), Scale(Scale) {
|
|
|
|
assert(type->isFixedPointType() && "Illegal type in FixedPointLiteral");
|
|
|
|
assert(V.getBitWidth() == C.getTypeInfo(type).Width &&
|
|
|
|
"Fixed point type is not the correct size for constant.");
|
|
|
|
setValue(C, V);
|
|
|
|
}
|
|
|
|
|
|
|
|
FixedPointLiteral *FixedPointLiteral::CreateFromRawInt(const ASTContext &C,
|
|
|
|
const llvm::APInt &V,
|
|
|
|
QualType type,
|
|
|
|
SourceLocation l,
|
|
|
|
unsigned Scale) {
|
|
|
|
return new (C) FixedPointLiteral(C, V, type, l, Scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string FixedPointLiteral::getValueAsString(unsigned Radix) const {
|
|
|
|
// Currently the longest decimal number that can be printed is the max for an
|
|
|
|
// unsigned long _Accum: 4294967295.99999999976716935634613037109375
|
|
|
|
// which is 43 characters.
|
|
|
|
SmallString<64> S;
|
|
|
|
FixedPointValueToString(
|
2018-08-07 00:05:08 +08:00
|
|
|
S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale);
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(S.str());
|
2018-06-21 01:19:40 +08:00
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V,
|
2012-07-05 01:04:04 +08:00
|
|
|
bool isexact, QualType Type, SourceLocation L)
|
|
|
|
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
|
|
|
|
false, false), Loc(L) {
|
2013-01-22 17:46:51 +08:00
|
|
|
setSemantics(V.getSemantics());
|
2012-07-05 01:04:04 +08:00
|
|
|
FloatingLiteralBits.IsExact = isexact;
|
|
|
|
setValue(C, V);
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty)
|
2017-11-18 02:09:48 +08:00
|
|
|
: Expr(FloatingLiteralClass, Empty) {
|
[clang] Add storage for APValue in ConstantExpr
Summary:
When using ConstantExpr we often need the result of the expression to be kept in the AST. Currently this is done on a by the node that needs the result and has been done multiple times for enumerator, for constexpr variables... . This patch adds to ConstantExpr the ability to store the result of evaluating the expression. no functional changes expected.
Changes:
- Add trailling object to ConstantExpr that can hold an APValue or an uint64_t. the uint64_t is here because most ConstantExpr yield integral values so there is an optimized layout for integral values.
- Add basic* serialization support for the trailing result.
- Move conversion functions from an enum to a fltSemantics from clang::FloatingLiteral to llvm::APFloatBase. this change is to make it usable for serializing APValues.
- Add basic* Import support for the trailing result.
- ConstantExpr created in CheckConvertedConstantExpression now stores the result in the ConstantExpr Node.
- Adapt AST dump to print the result when present.
basic* : None, Indeterminate, Int, Float, FixedPoint, ComplexInt, ComplexFloat,
the result is not yet used anywhere but for -ast-dump.
Reviewers: rsmith, martong, shafik
Reviewed By: rsmith
Subscribers: rnkovacs, hiraditya, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D62399
llvm-svn: 363493
2019-06-15 18:24:47 +08:00
|
|
|
setRawSemantics(llvm::APFloatBase::S_IEEEhalf);
|
2012-07-05 01:04:04 +08:00
|
|
|
FloatingLiteralBits.IsExact = false;
|
|
|
|
}
|
|
|
|
|
2010-08-28 17:06:06 +08:00
|
|
|
FloatingLiteral *
|
2013-08-18 18:09:15 +08:00
|
|
|
FloatingLiteral::Create(const ASTContext &C, const llvm::APFloat &V,
|
2010-08-28 17:06:06 +08:00
|
|
|
bool isexact, QualType Type, SourceLocation L) {
|
|
|
|
return new (C) FloatingLiteral(C, V, isexact, Type, L);
|
|
|
|
}
|
|
|
|
|
|
|
|
FloatingLiteral *
|
2013-08-18 18:09:15 +08:00
|
|
|
FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) {
|
2012-01-11 06:40:09 +08:00
|
|
|
return new (C) FloatingLiteral(C, Empty);
|
2010-08-28 17:06:06 +08:00
|
|
|
}
|
|
|
|
|
2008-06-08 06:13:43 +08:00
|
|
|
/// getValueAsApproximateDouble - This returns the value as an inaccurate
|
|
|
|
/// double. Note that this may cause loss of precision, but is useful for
|
|
|
|
/// debugging dumps, etc.
|
|
|
|
double FloatingLiteral::getValueAsApproximateDouble() const {
|
|
|
|
llvm::APFloat V = getValue();
|
2008-10-10 07:02:32 +08:00
|
|
|
bool ignored;
|
2016-12-14 19:57:17 +08:00
|
|
|
V.convert(llvm::APFloat::IEEEdouble(), llvm::APFloat::rmNearestTiesToEven,
|
2008-10-10 07:02:32 +08:00
|
|
|
&ignored);
|
2008-06-08 06:13:43 +08:00
|
|
|
return V.convertToDouble();
|
|
|
|
}
|
|
|
|
|
2018-11-16 00:42:14 +08:00
|
|
|
unsigned StringLiteral::mapCharByteWidth(TargetInfo const &Target,
|
|
|
|
StringKind SK) {
|
|
|
|
unsigned CharByteWidth = 0;
|
|
|
|
switch (SK) {
|
|
|
|
case Ascii:
|
|
|
|
case UTF8:
|
|
|
|
CharByteWidth = Target.getCharWidth();
|
|
|
|
break;
|
|
|
|
case Wide:
|
|
|
|
CharByteWidth = Target.getWCharWidth();
|
|
|
|
break;
|
|
|
|
case UTF16:
|
|
|
|
CharByteWidth = Target.getChar16Width();
|
|
|
|
break;
|
|
|
|
case UTF32:
|
|
|
|
CharByteWidth = Target.getChar32Width();
|
|
|
|
break;
|
2011-11-01 10:23:42 +08:00
|
|
|
}
|
|
|
|
assert((CharByteWidth & 7) == 0 && "Assumes character size is byte multiple");
|
|
|
|
CharByteWidth /= 8;
|
2018-11-16 00:42:14 +08:00
|
|
|
assert((CharByteWidth == 1 || CharByteWidth == 2 || CharByteWidth == 4) &&
|
|
|
|
"The only supported character byte widths are 1,2 and 4!");
|
2011-11-01 10:23:42 +08:00
|
|
|
return CharByteWidth;
|
|
|
|
}
|
|
|
|
|
2018-11-16 01:31:16 +08:00
|
|
|
StringLiteral::StringLiteral(const ASTContext &Ctx, StringRef Str,
|
|
|
|
StringKind Kind, bool Pascal, QualType Ty,
|
|
|
|
const SourceLocation *Loc,
|
|
|
|
unsigned NumConcatenated)
|
|
|
|
: Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false,
|
|
|
|
false) {
|
|
|
|
assert(Ctx.getAsConstantArrayType(Ty) &&
|
2014-02-25 20:26:20 +08:00
|
|
|
"StringLiteral must be of constant array type!");
|
2018-11-16 01:31:16 +08:00
|
|
|
unsigned CharByteWidth = mapCharByteWidth(Ctx.getTargetInfo(), Kind);
|
|
|
|
unsigned ByteLength = Str.size();
|
|
|
|
assert((ByteLength % CharByteWidth == 0) &&
|
|
|
|
"The size of the data must be a multiple of CharByteWidth!");
|
|
|
|
|
|
|
|
// Avoid the expensive division. The compiler should be able to figure it
|
|
|
|
// out by itself. However as of clang 7, even with the appropriate
|
|
|
|
// llvm_unreachable added just here, it is not able to do so.
|
|
|
|
unsigned Length;
|
|
|
|
switch (CharByteWidth) {
|
|
|
|
case 1:
|
|
|
|
Length = ByteLength;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Length = ByteLength / 2;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
Length = ByteLength / 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unsupported character width!");
|
|
|
|
}
|
2014-02-25 20:26:20 +08:00
|
|
|
|
2018-11-16 01:31:16 +08:00
|
|
|
StringLiteralBits.Kind = Kind;
|
|
|
|
StringLiteralBits.CharByteWidth = CharByteWidth;
|
|
|
|
StringLiteralBits.IsPascal = Pascal;
|
|
|
|
StringLiteralBits.NumConcatenated = NumConcatenated;
|
|
|
|
*getTrailingObjects<unsigned>() = Length;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2018-11-16 01:31:16 +08:00
|
|
|
// Initialize the trailing array of SourceLocation.
|
|
|
|
// This is safe since SourceLocation is POD-like.
|
|
|
|
std::memcpy(getTrailingObjects<SourceLocation>(), Loc,
|
|
|
|
NumConcatenated * sizeof(SourceLocation));
|
2011-11-01 10:23:42 +08:00
|
|
|
|
2018-11-16 01:31:16 +08:00
|
|
|
// Initialize the trailing array of char holding the string data.
|
|
|
|
std::memcpy(getTrailingObjects<char>(), Str.data(), ByteLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringLiteral::StringLiteral(EmptyShell Empty, unsigned NumConcatenated,
|
|
|
|
unsigned Length, unsigned CharByteWidth)
|
|
|
|
: Expr(StringLiteralClass, Empty) {
|
|
|
|
StringLiteralBits.CharByteWidth = CharByteWidth;
|
|
|
|
StringLiteralBits.NumConcatenated = NumConcatenated;
|
|
|
|
*getTrailingObjects<unsigned>() = Length;
|
|
|
|
}
|
2006-10-06 13:22:26 +08:00
|
|
|
|
2018-11-16 01:31:16 +08:00
|
|
|
StringLiteral *StringLiteral::Create(const ASTContext &Ctx, StringRef Str,
|
|
|
|
StringKind Kind, bool Pascal, QualType Ty,
|
|
|
|
const SourceLocation *Loc,
|
|
|
|
unsigned NumConcatenated) {
|
|
|
|
void *Mem = Ctx.Allocate(totalSizeToAlloc<unsigned, SourceLocation, char>(
|
|
|
|
1, NumConcatenated, Str.size()),
|
|
|
|
alignof(StringLiteral));
|
|
|
|
return new (Mem)
|
|
|
|
StringLiteral(Ctx, Str, Kind, Pascal, Ty, Loc, NumConcatenated);
|
2009-02-18 13:49:11 +08:00
|
|
|
}
|
|
|
|
|
2018-11-16 01:31:16 +08:00
|
|
|
StringLiteral *StringLiteral::CreateEmpty(const ASTContext &Ctx,
|
|
|
|
unsigned NumConcatenated,
|
|
|
|
unsigned Length,
|
|
|
|
unsigned CharByteWidth) {
|
|
|
|
void *Mem = Ctx.Allocate(totalSizeToAlloc<unsigned, SourceLocation, char>(
|
|
|
|
1, NumConcatenated, Length * CharByteWidth),
|
|
|
|
alignof(StringLiteral));
|
|
|
|
return new (Mem)
|
|
|
|
StringLiteral(EmptyShell(), NumConcatenated, Length, CharByteWidth);
|
2009-04-16 00:35:07 +08:00
|
|
|
}
|
|
|
|
|
2013-02-01 20:35:51 +08:00
|
|
|
void StringLiteral::outputString(raw_ostream &OS) const {
|
2012-06-14 04:25:24 +08:00
|
|
|
switch (getKind()) {
|
|
|
|
case Ascii: break; // no prefix.
|
|
|
|
case Wide: OS << 'L'; break;
|
|
|
|
case UTF8: OS << "u8"; break;
|
|
|
|
case UTF16: OS << 'u'; break;
|
|
|
|
case UTF32: OS << 'U'; break;
|
|
|
|
}
|
|
|
|
OS << '"';
|
|
|
|
static const char Hex[] = "0123456789ABCDEF";
|
|
|
|
|
|
|
|
unsigned LastSlashX = getLength();
|
|
|
|
for (unsigned I = 0, N = getLength(); I != N; ++I) {
|
|
|
|
switch (uint32_t Char = getCodeUnit(I)) {
|
|
|
|
default:
|
|
|
|
// FIXME: Convert UTF-8 back to codepoints before rendering.
|
|
|
|
|
|
|
|
// Convert UTF-16 surrogate pairs back to codepoints before rendering.
|
|
|
|
// Leave invalid surrogates alone; we'll use \x for those.
|
2018-07-31 03:24:48 +08:00
|
|
|
if (getKind() == UTF16 && I != N - 1 && Char >= 0xd800 &&
|
2012-06-14 04:25:24 +08:00
|
|
|
Char <= 0xdbff) {
|
|
|
|
uint32_t Trail = getCodeUnit(I + 1);
|
|
|
|
if (Trail >= 0xdc00 && Trail <= 0xdfff) {
|
|
|
|
Char = 0x10000 + ((Char - 0xd800) << 10) + (Trail - 0xdc00);
|
|
|
|
++I;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Char > 0xff) {
|
|
|
|
// If this is a wide string, output characters over 0xff using \x
|
|
|
|
// escapes. Otherwise, this is a UTF-16 or UTF-32 string, and Char is a
|
|
|
|
// codepoint: use \x escapes for invalid codepoints.
|
|
|
|
if (getKind() == Wide ||
|
|
|
|
(Char >= 0xd800 && Char <= 0xdfff) || Char >= 0x110000) {
|
|
|
|
// FIXME: Is this the best way to print wchar_t?
|
|
|
|
OS << "\\x";
|
|
|
|
int Shift = 28;
|
|
|
|
while ((Char >> Shift) == 0)
|
|
|
|
Shift -= 4;
|
|
|
|
for (/**/; Shift >= 0; Shift -= 4)
|
|
|
|
OS << Hex[(Char >> Shift) & 15];
|
|
|
|
LastSlashX = I;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Char > 0xffff)
|
|
|
|
OS << "\\U00"
|
|
|
|
<< Hex[(Char >> 20) & 15]
|
|
|
|
<< Hex[(Char >> 16) & 15];
|
|
|
|
else
|
|
|
|
OS << "\\u";
|
|
|
|
OS << Hex[(Char >> 12) & 15]
|
|
|
|
<< Hex[(Char >> 8) & 15]
|
|
|
|
<< Hex[(Char >> 4) & 15]
|
|
|
|
<< Hex[(Char >> 0) & 15];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we used \x... for the previous character, and this character is a
|
|
|
|
// hexadecimal digit, prevent it being slurped as part of the \x.
|
|
|
|
if (LastSlashX + 1 == I) {
|
|
|
|
switch (Char) {
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
|
|
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
|
|
|
OS << "\"\"";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(Char <= 0xff &&
|
|
|
|
"Characters above 0xff should already have been handled.");
|
|
|
|
|
2013-02-09 06:30:41 +08:00
|
|
|
if (isPrintable(Char))
|
2012-06-14 04:25:24 +08:00
|
|
|
OS << (char)Char;
|
|
|
|
else // Output anything hard as an octal escape.
|
|
|
|
OS << '\\'
|
|
|
|
<< (char)('0' + ((Char >> 6) & 7))
|
|
|
|
<< (char)('0' + ((Char >> 3) & 7))
|
|
|
|
<< (char)('0' + ((Char >> 0) & 7));
|
|
|
|
break;
|
|
|
|
// Handle some common non-printable cases to make dumps prettier.
|
|
|
|
case '\\': OS << "\\\\"; break;
|
|
|
|
case '"': OS << "\\\""; break;
|
|
|
|
case '\a': OS << "\\a"; break;
|
|
|
|
case '\b': OS << "\\b"; break;
|
2016-11-24 17:41:33 +08:00
|
|
|
case '\f': OS << "\\f"; break;
|
|
|
|
case '\n': OS << "\\n"; break;
|
|
|
|
case '\r': OS << "\\r"; break;
|
|
|
|
case '\t': OS << "\\t"; break;
|
|
|
|
case '\v': OS << "\\v"; break;
|
2012-06-14 04:25:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
OS << '"';
|
|
|
|
}
|
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
/// getLocationOfByte - Return a source location that points to the specified
|
|
|
|
/// byte of this string literal.
|
|
|
|
///
|
|
|
|
/// Strings are amazingly complex. They can be formed from multiple tokens and
|
|
|
|
/// can have escape sequences in them in addition to the usual trigraph and
|
|
|
|
/// escaped newline business. This routine handles this complexity.
|
|
|
|
///
|
2015-12-10 09:11:47 +08:00
|
|
|
/// The *StartToken sets the first token to be searched in this function and
|
|
|
|
/// the *StartTokenByteOffset is the byte offset of the first token. Before
|
|
|
|
/// returning, it updates the *StartToken to the TokNo of the token being found
|
|
|
|
/// and sets *StartTokenByteOffset to the byte offset of the token in the
|
|
|
|
/// string.
|
|
|
|
/// Using these two parameters can reduce the time complexity from O(n^2) to
|
|
|
|
/// O(n) if one wants to get the location of byte for all the tokens in a
|
|
|
|
/// string.
|
2017-11-18 02:09:48 +08:00
|
|
|
///
|
2015-12-10 09:11:47 +08:00
|
|
|
SourceLocation
|
|
|
|
StringLiteral::getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
|
|
|
|
const LangOptions &Features,
|
|
|
|
const TargetInfo &Target, unsigned *StartToken,
|
|
|
|
unsigned *StartTokenByteOffset) const {
|
2018-11-16 00:42:14 +08:00
|
|
|
assert((getKind() == StringLiteral::Ascii ||
|
|
|
|
getKind() == StringLiteral::UTF8) &&
|
2012-06-13 13:37:23 +08:00
|
|
|
"Only narrow string literals are currently supported");
|
2011-07-27 13:40:30 +08:00
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
// Loop over all of the tokens in this string until we find the one that
|
|
|
|
// contains the byte we're looking for.
|
|
|
|
unsigned TokNo = 0;
|
2015-12-10 09:11:47 +08:00
|
|
|
unsigned StringOffset = 0;
|
|
|
|
if (StartToken)
|
|
|
|
TokNo = *StartToken;
|
|
|
|
if (StartTokenByteOffset) {
|
|
|
|
StringOffset = *StartTokenByteOffset;
|
|
|
|
ByteNo -= StringOffset;
|
|
|
|
}
|
2017-11-18 02:09:48 +08:00
|
|
|
while (1) {
|
2010-11-17 15:37:15 +08:00
|
|
|
assert(TokNo < getNumConcatenated() && "Invalid byte number!");
|
|
|
|
SourceLocation StrTokLoc = getStrTokenLoc(TokNo);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
// Get the spelling of the string so that we can get the data that makes up
|
|
|
|
// the string literal, not the identifier for the macro it is potentially
|
|
|
|
// expanded through.
|
|
|
|
SourceLocation StrTokSpellingLoc = SM.getSpellingLoc(StrTokLoc);
|
2015-12-10 09:11:47 +08:00
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
// Re-lex the token to get its length and original spelling.
|
2015-12-10 09:11:47 +08:00
|
|
|
std::pair<FileID, unsigned> LocInfo =
|
|
|
|
SM.getDecomposedLoc(StrTokSpellingLoc);
|
2010-11-17 15:37:15 +08:00
|
|
|
bool Invalid = false;
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
|
2015-12-10 09:11:47 +08:00
|
|
|
if (Invalid) {
|
|
|
|
if (StartTokenByteOffset != nullptr)
|
|
|
|
*StartTokenByteOffset = StringOffset;
|
|
|
|
if (StartToken != nullptr)
|
|
|
|
*StartToken = TokNo;
|
2010-11-17 15:37:15 +08:00
|
|
|
return StrTokSpellingLoc;
|
2015-12-10 09:11:47 +08:00
|
|
|
}
|
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
const char *StrData = Buffer.data()+LocInfo.second;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
// Create a lexer starting at the beginning of this token.
|
2012-05-12 05:39:18 +08:00
|
|
|
Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), Features,
|
|
|
|
Buffer.begin(), StrData, Buffer.end());
|
2010-11-17 15:37:15 +08:00
|
|
|
Token TheTok;
|
|
|
|
TheLexer.LexFromRawLexer(TheTok);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
// Use the StringLiteralParser to compute the length of the string in bytes.
|
2014-06-26 12:58:39 +08:00
|
|
|
StringLiteralParser SLP(TheTok, SM, Features, Target);
|
2010-11-17 15:37:15 +08:00
|
|
|
unsigned TokNumBytes = SLP.GetStringLength();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
// If the byte is in this token, return the location of the byte.
|
|
|
|
if (ByteNo < TokNumBytes ||
|
2011-07-01 04:17:41 +08:00
|
|
|
(ByteNo == TokNumBytes && TokNo == getNumConcatenated() - 1)) {
|
2015-12-10 09:11:47 +08:00
|
|
|
unsigned Offset = SLP.getOffsetOfStringByte(TheTok, ByteNo);
|
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
// Now that we know the offset of the token in the spelling, use the
|
|
|
|
// preprocessor to get the offset in the original source.
|
2015-12-10 09:11:47 +08:00
|
|
|
if (StartTokenByteOffset != nullptr)
|
|
|
|
*StartTokenByteOffset = StringOffset;
|
|
|
|
if (StartToken != nullptr)
|
|
|
|
*StartToken = TokNo;
|
2010-11-17 15:37:15 +08:00
|
|
|
return Lexer::AdvanceToTokenCharacter(StrTokLoc, Offset, SM, Features);
|
|
|
|
}
|
2015-12-10 09:11:47 +08:00
|
|
|
|
2010-11-17 15:37:15 +08:00
|
|
|
// Move to the next string token.
|
2015-12-10 09:11:47 +08:00
|
|
|
StringOffset += TokNumBytes;
|
2010-11-17 15:37:15 +08:00
|
|
|
++TokNo;
|
|
|
|
ByteNo -= TokNumBytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-23 14:42:10 +08:00
|
|
|
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
|
|
|
/// corresponds to, e.g. "sizeof" or "[pre]++".
|
2018-11-14 05:33:22 +08:00
|
|
|
StringRef UnaryOperator::getOpcodeStr(Opcode Op) {
|
|
|
|
switch (Op) {
|
2016-05-13 04:58:56 +08:00
|
|
|
#define UNARY_OPERATION(Name, Spelling) case UO_##Name: return Spelling;
|
|
|
|
#include "clang/AST/OperationKinds.def"
|
2006-08-23 14:42:10 +08:00
|
|
|
}
|
2012-01-17 10:30:50 +08:00
|
|
|
llvm_unreachable("Unknown unary operator");
|
2006-08-23 14:42:10 +08:00
|
|
|
}
|
|
|
|
|
2010-08-25 19:45:40 +08:00
|
|
|
UnaryOperatorKind
|
2009-03-14 07:49:33 +08:00
|
|
|
UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) {
|
|
|
|
switch (OO) {
|
2011-09-23 13:06:16 +08:00
|
|
|
default: llvm_unreachable("No unary operator for overloaded function");
|
2010-08-25 19:45:40 +08:00
|
|
|
case OO_PlusPlus: return Postfix ? UO_PostInc : UO_PreInc;
|
|
|
|
case OO_MinusMinus: return Postfix ? UO_PostDec : UO_PreDec;
|
|
|
|
case OO_Amp: return UO_AddrOf;
|
|
|
|
case OO_Star: return UO_Deref;
|
|
|
|
case OO_Plus: return UO_Plus;
|
|
|
|
case OO_Minus: return UO_Minus;
|
|
|
|
case OO_Tilde: return UO_Not;
|
|
|
|
case OO_Exclaim: return UO_LNot;
|
2015-10-27 14:02:45 +08:00
|
|
|
case OO_Coawait: return UO_Coawait;
|
2009-03-14 07:49:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
|
|
|
|
switch (Opc) {
|
2010-08-25 19:45:40 +08:00
|
|
|
case UO_PostInc: case UO_PreInc: return OO_PlusPlus;
|
|
|
|
case UO_PostDec: case UO_PreDec: return OO_MinusMinus;
|
|
|
|
case UO_AddrOf: return OO_Amp;
|
|
|
|
case UO_Deref: return OO_Star;
|
|
|
|
case UO_Plus: return OO_Plus;
|
|
|
|
case UO_Minus: return OO_Minus;
|
|
|
|
case UO_Not: return OO_Tilde;
|
|
|
|
case UO_LNot: return OO_Exclaim;
|
2015-10-27 14:02:45 +08:00
|
|
|
case UO_Coawait: return OO_Coawait;
|
2009-03-14 07:49:33 +08:00
|
|
|
default: return OO_None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-18 02:09:48 +08:00
|
|
|
|
2006-08-24 12:56:27 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Postfix Operators.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2006-08-24 12:40:38 +08:00
|
|
|
|
2018-12-21 23:20:32 +08:00
|
|
|
CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs,
|
|
|
|
ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK,
|
|
|
|
SourceLocation RParenLoc, unsigned MinNumArgs,
|
|
|
|
ADLCallKind UsesADL)
|
|
|
|
: Expr(SC, Ty, VK, OK_Ordinary, Fn->isTypeDependent(),
|
|
|
|
Fn->isValueDependent(), Fn->isInstantiationDependent(),
|
|
|
|
Fn->containsUnexpandedParameterPack()),
|
|
|
|
RParenLoc(RParenLoc) {
|
|
|
|
NumArgs = std::max<unsigned>(Args.size(), MinNumArgs);
|
|
|
|
unsigned NumPreArgs = PreArgs.size();
|
2018-12-03 22:54:03 +08:00
|
|
|
CallExprBits.NumPreArgs = NumPreArgs;
|
2018-12-21 23:20:32 +08:00
|
|
|
assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!");
|
|
|
|
|
|
|
|
unsigned OffsetToTrailingObjects = offsetToTrailingObjects(SC);
|
|
|
|
CallExprBits.OffsetToTrailingObjects = OffsetToTrailingObjects;
|
|
|
|
assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) &&
|
|
|
|
"OffsetToTrailingObjects overflow!");
|
|
|
|
|
|
|
|
CallExprBits.UsesADL = static_cast<bool>(UsesADL);
|
2018-12-03 22:54:03 +08:00
|
|
|
|
2018-12-21 23:20:32 +08:00
|
|
|
setCallee(Fn);
|
|
|
|
for (unsigned I = 0; I != NumPreArgs; ++I) {
|
|
|
|
updateDependenciesFromArg(PreArgs[I]);
|
|
|
|
setPreArg(I, PreArgs[I]);
|
2016-01-15 07:31:30 +08:00
|
|
|
}
|
2018-12-21 23:20:32 +08:00
|
|
|
for (unsigned I = 0; I != Args.size(); ++I) {
|
|
|
|
updateDependenciesFromArg(Args[I]);
|
|
|
|
setArg(I, Args[I]);
|
2010-12-15 09:34:56 +08:00
|
|
|
}
|
2018-12-21 23:20:32 +08:00
|
|
|
for (unsigned I = Args.size(); I != NumArgs; ++I) {
|
|
|
|
setArg(I, nullptr);
|
2018-12-03 22:54:03 +08:00
|
|
|
}
|
2008-11-15 00:09:21 +08:00
|
|
|
}
|
2008-01-18 01:46:27 +08:00
|
|
|
|
2018-12-21 23:20:32 +08:00
|
|
|
CallExpr::CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs,
|
|
|
|
EmptyShell Empty)
|
2018-12-03 22:54:03 +08:00
|
|
|
: Expr(SC, Empty), NumArgs(NumArgs) {
|
2011-02-09 05:18:02 +08:00
|
|
|
CallExprBits.NumPreArgs = NumPreArgs;
|
2018-12-21 23:20:32 +08:00
|
|
|
assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!");
|
|
|
|
|
|
|
|
unsigned OffsetToTrailingObjects = offsetToTrailingObjects(SC);
|
|
|
|
CallExprBits.OffsetToTrailingObjects = OffsetToTrailingObjects;
|
|
|
|
assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) &&
|
|
|
|
"OffsetToTrailingObjects overflow!");
|
2009-04-16 01:43:59 +08:00
|
|
|
}
|
|
|
|
|
2018-12-21 23:20:32 +08:00
|
|
|
CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn,
|
|
|
|
ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK,
|
|
|
|
SourceLocation RParenLoc, unsigned MinNumArgs,
|
|
|
|
ADLCallKind UsesADL) {
|
|
|
|
unsigned NumArgs = std::max<unsigned>(Args.size(), MinNumArgs);
|
|
|
|
unsigned SizeOfTrailingObjects =
|
|
|
|
CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs);
|
|
|
|
void *Mem =
|
|
|
|
Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr));
|
|
|
|
return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK,
|
|
|
|
RParenLoc, MinNumArgs, UsesADL);
|
|
|
|
}
|
|
|
|
|
|
|
|
CallExpr *CallExpr::CreateTemporary(void *Mem, Expr *Fn, QualType Ty,
|
|
|
|
ExprValueKind VK, SourceLocation RParenLoc,
|
|
|
|
ADLCallKind UsesADL) {
|
|
|
|
assert(!(reinterpret_cast<uintptr_t>(Mem) % alignof(CallExpr)) &&
|
|
|
|
"Misaligned memory in CallExpr::CreateTemporary!");
|
|
|
|
return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, /*Args=*/{}, Ty,
|
|
|
|
VK, RParenLoc, /*MinNumArgs=*/0, UsesADL);
|
|
|
|
}
|
|
|
|
|
|
|
|
CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
|
|
|
|
EmptyShell Empty) {
|
|
|
|
unsigned SizeOfTrailingObjects =
|
|
|
|
CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs);
|
|
|
|
void *Mem =
|
|
|
|
Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr));
|
|
|
|
return new (Mem) CallExpr(CallExprClass, /*NumPreArgs=*/0, NumArgs, Empty);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned CallExpr::offsetToTrailingObjects(StmtClass SC) {
|
|
|
|
switch (SC) {
|
|
|
|
case CallExprClass:
|
|
|
|
return sizeof(CallExpr);
|
|
|
|
case CXXOperatorCallExprClass:
|
|
|
|
return sizeof(CXXOperatorCallExpr);
|
|
|
|
case CXXMemberCallExprClass:
|
|
|
|
return sizeof(CXXMemberCallExpr);
|
|
|
|
case UserDefinedLiteralClass:
|
|
|
|
return sizeof(UserDefinedLiteral);
|
|
|
|
case CUDAKernelCallExprClass:
|
|
|
|
return sizeof(CUDAKernelCallExpr);
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unexpected class deriving from CallExpr!");
|
|
|
|
}
|
|
|
|
}
|
2018-12-03 22:54:03 +08:00
|
|
|
|
2016-01-15 07:31:30 +08:00
|
|
|
void CallExpr::updateDependenciesFromArg(Expr *Arg) {
|
|
|
|
if (Arg->isTypeDependent())
|
|
|
|
ExprBits.TypeDependent = true;
|
|
|
|
if (Arg->isValueDependent())
|
|
|
|
ExprBits.ValueDependent = true;
|
|
|
|
if (Arg->isInstantiationDependent())
|
|
|
|
ExprBits.InstantiationDependent = true;
|
|
|
|
if (Arg->containsUnexpandedParameterPack())
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
|
|
|
}
|
|
|
|
|
2016-10-27 07:46:34 +08:00
|
|
|
Decl *Expr::getReferencedDeclOfCallee() {
|
|
|
|
Expr *CEE = IgnoreParenImpCasts();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2020-02-06 11:01:33 +08:00
|
|
|
while (SubstNonTypeTemplateParmExpr *NTTP =
|
|
|
|
dyn_cast<SubstNonTypeTemplateParmExpr>(CEE)) {
|
|
|
|
CEE = NTTP->getReplacement()->IgnoreParenImpCasts();
|
2011-09-07 05:41:04 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-09-11 04:55:30 +08:00
|
|
|
// If we're calling a dereference, look at the pointer instead.
|
2020-02-06 11:01:33 +08:00
|
|
|
while (true) {
|
|
|
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
|
|
|
|
if (BO->isPtrMemOp()) {
|
|
|
|
CEE = BO->getRHS()->IgnoreParenImpCasts();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
|
|
|
|
if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_AddrOf ||
|
|
|
|
UO->getOpcode() == UO_Plus) {
|
|
|
|
CEE = UO->getSubExpr()->IgnoreParenImpCasts();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2010-09-11 04:55:30 +08:00
|
|
|
}
|
2020-02-06 11:01:33 +08:00
|
|
|
|
2009-07-17 23:46:27 +08:00
|
|
|
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE))
|
2009-12-21 07:11:08 +08:00
|
|
|
return DRE->getDecl();
|
2009-12-24 08:28:18 +08:00
|
|
|
if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
|
|
|
|
return ME->getMemberDecl();
|
2019-02-27 00:20:41 +08:00
|
|
|
if (auto *BE = dyn_cast<BlockExpr>(CEE))
|
|
|
|
return BE->getBlockDecl();
|
2009-07-17 15:29:51 +08:00
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-07-17 15:29:51 +08:00
|
|
|
}
|
|
|
|
|
2020-02-06 11:01:33 +08:00
|
|
|
/// If this is a call to a builtin, return the builtin ID. If not, return 0.
|
2013-12-29 05:59:02 +08:00
|
|
|
unsigned CallExpr::getBuiltinCallee() const {
|
2020-02-06 11:01:33 +08:00
|
|
|
auto *FDecl =
|
|
|
|
dyn_cast_or_null<FunctionDecl>(getCallee()->getReferencedDeclOfCallee());
|
|
|
|
return FDecl ? FDecl->getBuiltinID() : 0;
|
2008-10-06 13:00:53 +08:00
|
|
|
}
|
2008-01-31 10:13:57 +08:00
|
|
|
|
2015-06-10 21:53:15 +08:00
|
|
|
bool CallExpr::isUnevaluatedBuiltinCall(const ASTContext &Ctx) const {
|
2013-12-29 05:59:02 +08:00
|
|
|
if (unsigned BI = getBuiltinCallee())
|
2013-01-18 07:46:04 +08:00
|
|
|
return Ctx.BuiltinInfo.isUnevaluated(BI);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-26 01:36:15 +08:00
|
|
|
QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const {
|
|
|
|
const Expr *Callee = getCallee();
|
|
|
|
QualType CalleeType = Callee->getType();
|
|
|
|
if (const auto *FnTypePtr = CalleeType->getAs<PointerType>()) {
|
2009-05-26 12:57:27 +08:00
|
|
|
CalleeType = FnTypePtr->getPointeeType();
|
2015-02-26 01:36:15 +08:00
|
|
|
} else if (const auto *BPT = CalleeType->getAs<BlockPointerType>()) {
|
2009-05-26 12:57:27 +08:00
|
|
|
CalleeType = BPT->getPointeeType();
|
2015-02-26 01:36:15 +08:00
|
|
|
} else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
|
|
|
|
if (isa<CXXPseudoDestructorExpr>(Callee->IgnoreParens()))
|
|
|
|
return Ctx.VoidTy;
|
|
|
|
|
2011-04-27 04:42:42 +08:00
|
|
|
// This should never be overloaded and so should never return null.
|
2015-02-26 01:36:15 +08:00
|
|
|
CalleeType = Expr::findBoundMemberType(Callee);
|
|
|
|
}
|
|
|
|
|
2011-04-27 04:42:42 +08:00
|
|
|
const FunctionType *FnType = CalleeType->castAs<FunctionType>();
|
2014-01-26 00:55:45 +08:00
|
|
|
return FnType->getReturnType();
|
2009-05-26 12:57:27 +08:00
|
|
|
}
|
2008-10-06 13:00:53 +08:00
|
|
|
|
2019-01-03 22:24:31 +08:00
|
|
|
const Attr *CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const {
|
|
|
|
// If the return type is a struct, union, or enum that is marked nodiscard,
|
|
|
|
// then return the return type attribute.
|
|
|
|
if (const TagDecl *TD = getCallReturnType(Ctx)->getAsTagDecl())
|
|
|
|
if (const auto *A = TD->getAttr<WarnUnusedResultAttr>())
|
|
|
|
return A;
|
|
|
|
|
|
|
|
// Otherwise, see if the callee is marked nodiscard and return that attribute
|
|
|
|
// instead.
|
|
|
|
const Decl *D = getCalleeDecl();
|
|
|
|
return D ? D->getAttr<WarnUnusedResultAttr>() : nullptr;
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:03 +08:00
|
|
|
SourceLocation CallExpr::getBeginLoc() const {
|
2012-03-09 23:39:24 +08:00
|
|
|
if (isa<CXXOperatorCallExpr>(this))
|
2018-08-10 05:08:08 +08:00
|
|
|
return cast<CXXOperatorCallExpr>(this)->getBeginLoc();
|
2012-03-09 23:39:24 +08:00
|
|
|
|
2018-08-10 05:08:08 +08:00
|
|
|
SourceLocation begin = getCallee()->getBeginLoc();
|
2014-08-15 09:39:12 +08:00
|
|
|
if (begin.isInvalid() && getNumArgs() > 0 && getArg(0))
|
2018-08-10 05:08:08 +08:00
|
|
|
begin = getArg(0)->getBeginLoc();
|
2012-03-09 23:39:24 +08:00
|
|
|
return begin;
|
|
|
|
}
|
2018-08-10 04:05:47 +08:00
|
|
|
SourceLocation CallExpr::getEndLoc() const {
|
2012-03-09 23:39:24 +08:00
|
|
|
if (isa<CXXOperatorCallExpr>(this))
|
2018-08-10 05:09:38 +08:00
|
|
|
return cast<CXXOperatorCallExpr>(this)->getEndLoc();
|
2012-03-09 23:39:24 +08:00
|
|
|
|
|
|
|
SourceLocation end = getRParenLoc();
|
2014-08-15 09:39:12 +08:00
|
|
|
if (end.isInvalid() && getNumArgs() > 0 && getArg(getNumArgs() - 1))
|
2018-08-10 05:09:38 +08:00
|
|
|
end = getArg(getNumArgs() - 1)->getEndLoc();
|
2012-03-09 23:39:24 +08:00
|
|
|
return end;
|
|
|
|
}
|
2011-02-21 14:23:05 +08:00
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
OffsetOfExpr *OffsetOfExpr::Create(const ASTContext &C, QualType type,
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
SourceLocation OperatorLoc,
|
2018-07-31 03:24:48 +08:00
|
|
|
TypeSourceInfo *tsi,
|
2012-08-24 19:54:20 +08:00
|
|
|
ArrayRef<OffsetOfNode> comps,
|
|
|
|
ArrayRef<Expr*> exprs,
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
SourceLocation RParenLoc) {
|
2015-12-30 06:31:18 +08:00
|
|
|
void *Mem = C.Allocate(
|
|
|
|
totalSizeToAlloc<OffsetOfNode, Expr *>(comps.size(), exprs.size()));
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
|
2012-08-24 19:54:20 +08:00
|
|
|
return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, comps, exprs,
|
|
|
|
RParenLoc);
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
OffsetOfExpr *OffsetOfExpr::CreateEmpty(const ASTContext &C,
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
unsigned numComps, unsigned numExprs) {
|
2015-12-30 06:31:18 +08:00
|
|
|
void *Mem =
|
|
|
|
C.Allocate(totalSizeToAlloc<OffsetOfNode, Expr *>(numComps, numExprs));
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
return new (Mem) OffsetOfExpr(numComps, numExprs);
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
OffsetOfExpr::OffsetOfExpr(const ASTContext &C, QualType type,
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
2012-08-24 19:54:20 +08:00
|
|
|
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
SourceLocation RParenLoc)
|
2010-11-18 14:31:45 +08:00
|
|
|
: Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary,
|
2018-07-31 03:24:48 +08:00
|
|
|
/*TypeDependent=*/false,
|
2010-12-15 09:34:56 +08:00
|
|
|
/*ValueDependent=*/tsi->getType()->isDependentType(),
|
2011-07-01 09:22:09 +08:00
|
|
|
tsi->getType()->isInstantiationDependentType(),
|
2010-12-15 09:34:56 +08:00
|
|
|
tsi->getType()->containsUnexpandedParameterPack()),
|
2018-07-31 03:24:48 +08:00
|
|
|
OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi),
|
2012-08-24 19:54:20 +08:00
|
|
|
NumComps(comps.size()), NumExprs(exprs.size())
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
{
|
2012-08-24 19:54:20 +08:00
|
|
|
for (unsigned i = 0; i != comps.size(); ++i) {
|
|
|
|
setComponent(i, comps[i]);
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-08-24 19:54:20 +08:00
|
|
|
for (unsigned i = 0; i != exprs.size(); ++i) {
|
|
|
|
if (exprs[i]->isTypeDependent() || exprs[i]->isValueDependent())
|
2010-12-15 09:34:56 +08:00
|
|
|
ExprBits.ValueDependent = true;
|
2012-08-24 19:54:20 +08:00
|
|
|
if (exprs[i]->containsUnexpandedParameterPack())
|
2010-12-15 09:34:56 +08:00
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
|
|
|
|
2012-08-24 19:54:20 +08:00
|
|
|
setIndexExpr(i, exprs[i]);
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-30 06:31:18 +08:00
|
|
|
IdentifierInfo *OffsetOfNode::getFieldName() const {
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
assert(getKind() == Field || getKind() == Identifier);
|
|
|
|
if (getKind() == Field)
|
|
|
|
return getField()->getIdentifier();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2017-11-18 02:09:48 +08:00
|
|
|
return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask);
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
}
|
|
|
|
|
2015-01-15 18:04:14 +08:00
|
|
|
UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr(
|
|
|
|
UnaryExprOrTypeTrait ExprKind, Expr *E, QualType resultType,
|
|
|
|
SourceLocation op, SourceLocation rp)
|
|
|
|
: Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary,
|
|
|
|
false, // Never type-dependent (C++ [temp.dep.expr]p3).
|
|
|
|
// Value-dependent if the argument is type-dependent.
|
|
|
|
E->isTypeDependent(), E->isInstantiationDependent(),
|
|
|
|
E->containsUnexpandedParameterPack()),
|
|
|
|
OpLoc(op), RParenLoc(rp) {
|
|
|
|
UnaryExprOrTypeTraitExprBits.Kind = ExprKind;
|
|
|
|
UnaryExprOrTypeTraitExprBits.IsType = false;
|
|
|
|
Argument.Ex = E;
|
|
|
|
|
|
|
|
// Check to see if we are in the situation where alignof(decl) should be
|
|
|
|
// dependent because decl's alignment is dependent.
|
2018-10-27 03:26:45 +08:00
|
|
|
if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) {
|
2015-01-15 18:04:14 +08:00
|
|
|
if (!isValueDependent() || !isInstantiationDependent()) {
|
|
|
|
E = E->IgnoreParens();
|
|
|
|
|
|
|
|
const ValueDecl *D = nullptr;
|
|
|
|
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
|
|
|
|
D = DRE->getDecl();
|
|
|
|
else if (const auto *ME = dyn_cast<MemberExpr>(E))
|
|
|
|
D = ME->getMemberDecl();
|
|
|
|
|
|
|
|
if (D) {
|
|
|
|
for (const auto *I : D->specific_attrs<AlignedAttr>()) {
|
|
|
|
if (I->isAlignmentDependent()) {
|
|
|
|
setValueDependent(true);
|
|
|
|
setInstantiationDependent(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-07 07:24:15 +08:00
|
|
|
MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
|
|
|
|
ValueDecl *MemberDecl,
|
|
|
|
const DeclarationNameInfo &NameInfo, QualType T,
|
2019-06-12 01:50:36 +08:00
|
|
|
ExprValueKind VK, ExprObjectKind OK,
|
|
|
|
NonOdrUseReason NOUR)
|
2019-06-07 07:24:15 +08:00
|
|
|
: Expr(MemberExprClass, T, VK, OK, Base->isTypeDependent(),
|
|
|
|
Base->isValueDependent(), Base->isInstantiationDependent(),
|
|
|
|
Base->containsUnexpandedParameterPack()),
|
|
|
|
Base(Base), MemberDecl(MemberDecl), MemberDNLoc(NameInfo.getInfo()),
|
|
|
|
MemberLoc(NameInfo.getLoc()) {
|
|
|
|
assert(!NameInfo.getName() ||
|
|
|
|
MemberDecl->getDeclName() == NameInfo.getName());
|
|
|
|
MemberExprBits.IsArrow = IsArrow;
|
|
|
|
MemberExprBits.HasQualifierOrFoundDecl = false;
|
|
|
|
MemberExprBits.HasTemplateKWAndArgsInfo = false;
|
|
|
|
MemberExprBits.HadMultipleCandidates = false;
|
2019-06-12 01:50:36 +08:00
|
|
|
MemberExprBits.NonOdrUseReason = NOUR;
|
2019-06-07 07:24:15 +08:00
|
|
|
MemberExprBits.OperatorLoc = OperatorLoc;
|
|
|
|
}
|
|
|
|
|
2015-03-24 23:07:53 +08:00
|
|
|
MemberExpr *MemberExpr::Create(
|
2019-06-07 07:24:15 +08:00
|
|
|
const ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
|
2015-03-24 23:07:53 +08:00
|
|
|
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
|
2019-06-07 07:24:15 +08:00
|
|
|
ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
|
|
|
|
DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs,
|
2019-06-12 01:50:36 +08:00
|
|
|
QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) {
|
2019-06-07 07:24:15 +08:00
|
|
|
bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl ||
|
|
|
|
FoundDecl.getAccess() != MemberDecl->getAccess();
|
|
|
|
bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
|
2015-12-30 02:15:14 +08:00
|
|
|
std::size_t Size =
|
|
|
|
totalSizeToAlloc<MemberExprNameQualifier, ASTTemplateKWAndArgsInfo,
|
2019-06-07 07:24:15 +08:00
|
|
|
TemplateArgumentLoc>(
|
|
|
|
HasQualOrFound ? 1 : 0, HasTemplateKWAndArgsInfo ? 1 : 0,
|
|
|
|
TemplateArgs ? TemplateArgs->size() : 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2016-10-20 22:27:22 +08:00
|
|
|
void *Mem = C.Allocate(Size, alignof(MemberExpr));
|
2019-06-12 01:50:36 +08:00
|
|
|
MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
|
|
|
|
NameInfo, T, VK, OK, NOUR);
|
2010-03-31 05:47:33 +08:00
|
|
|
|
2019-12-04 10:15:17 +08:00
|
|
|
if (isa<FieldDecl>(MemberDecl)) {
|
2019-12-04 06:20:52 +08:00
|
|
|
DeclContext *DC = MemberDecl->getDeclContext();
|
|
|
|
// dyn_cast_or_null is used to handle objC variables which do not
|
|
|
|
// have a declaration context.
|
|
|
|
CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC);
|
|
|
|
if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC))
|
|
|
|
E->setTypeDependent(T->isDependentType());
|
2020-02-13 03:30:02 +08:00
|
|
|
|
|
|
|
// Bitfield with value-dependent width is type-dependent.
|
|
|
|
FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl);
|
|
|
|
if (FD && FD->isBitField() && FD->getBitWidth()->isValueDependent())
|
|
|
|
E->setTypeDependent(true);
|
2019-12-04 06:20:52 +08:00
|
|
|
}
|
|
|
|
|
2019-06-07 07:24:15 +08:00
|
|
|
if (HasQualOrFound) {
|
2011-03-01 05:54:11 +08:00
|
|
|
// FIXME: Wrong. We should be looking at the member declaration we found.
|
|
|
|
if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) {
|
2010-03-31 05:47:33 +08:00
|
|
|
E->setValueDependent(true);
|
|
|
|
E->setTypeDependent(true);
|
2011-07-01 09:22:09 +08:00
|
|
|
E->setInstantiationDependent(true);
|
2018-07-31 03:24:48 +08:00
|
|
|
}
|
|
|
|
else if (QualifierLoc &&
|
|
|
|
QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent())
|
2011-07-01 09:22:09 +08:00
|
|
|
E->setInstantiationDependent(true);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2018-11-15 21:56:22 +08:00
|
|
|
E->MemberExprBits.HasQualifierOrFoundDecl = true;
|
2010-03-31 05:47:33 +08:00
|
|
|
|
2015-12-30 02:15:14 +08:00
|
|
|
MemberExprNameQualifier *NQ =
|
|
|
|
E->getTrailingObjects<MemberExprNameQualifier>();
|
2011-03-01 05:54:11 +08:00
|
|
|
NQ->QualifierLoc = QualifierLoc;
|
2019-06-07 07:24:15 +08:00
|
|
|
NQ->FoundDecl = FoundDecl;
|
2010-03-31 05:47:33 +08:00
|
|
|
}
|
|
|
|
|
2018-11-15 21:56:22 +08:00
|
|
|
E->MemberExprBits.HasTemplateKWAndArgsInfo =
|
2019-06-07 07:24:15 +08:00
|
|
|
TemplateArgs || TemplateKWLoc.isValid();
|
2012-01-27 17:46:47 +08:00
|
|
|
|
2019-06-07 07:24:15 +08:00
|
|
|
if (TemplateArgs) {
|
2011-07-01 09:22:09 +08:00
|
|
|
bool Dependent = false;
|
|
|
|
bool InstantiationDependent = false;
|
|
|
|
bool ContainsUnexpandedParameterPack = false;
|
2015-12-30 02:15:14 +08:00
|
|
|
E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
|
2019-06-07 07:24:15 +08:00
|
|
|
TemplateKWLoc, *TemplateArgs,
|
|
|
|
E->getTrailingObjects<TemplateArgumentLoc>(), Dependent,
|
|
|
|
InstantiationDependent, ContainsUnexpandedParameterPack);
|
2011-07-01 09:22:09 +08:00
|
|
|
if (InstantiationDependent)
|
|
|
|
E->setInstantiationDependent(true);
|
2012-01-27 17:46:47 +08:00
|
|
|
} else if (TemplateKWLoc.isValid()) {
|
2015-12-30 02:15:14 +08:00
|
|
|
E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
|
|
|
|
TemplateKWLoc);
|
2010-03-31 05:47:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return E;
|
2009-09-01 07:41:50 +08:00
|
|
|
}
|
|
|
|
|
2019-06-07 07:24:15 +08:00
|
|
|
MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context,
|
|
|
|
bool HasQualifier, bool HasFoundDecl,
|
|
|
|
bool HasTemplateKWAndArgsInfo,
|
|
|
|
unsigned NumTemplateArgs) {
|
|
|
|
assert((!NumTemplateArgs || HasTemplateKWAndArgsInfo) &&
|
|
|
|
"template args but no template arg info?");
|
|
|
|
bool HasQualOrFound = HasQualifier || HasFoundDecl;
|
|
|
|
std::size_t Size =
|
|
|
|
totalSizeToAlloc<MemberExprNameQualifier, ASTTemplateKWAndArgsInfo,
|
|
|
|
TemplateArgumentLoc>(HasQualOrFound ? 1 : 0,
|
|
|
|
HasTemplateKWAndArgsInfo ? 1 : 0,
|
|
|
|
NumTemplateArgs);
|
|
|
|
void *Mem = Context.Allocate(Size, alignof(MemberExpr));
|
|
|
|
return new (Mem) MemberExpr(EmptyShell());
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:03 +08:00
|
|
|
SourceLocation MemberExpr::getBeginLoc() const {
|
2011-03-03 05:06:53 +08:00
|
|
|
if (isImplicitAccess()) {
|
|
|
|
if (hasQualifier())
|
2012-03-09 23:39:15 +08:00
|
|
|
return getQualifierLoc().getBeginLoc();
|
|
|
|
return MemberLoc;
|
2011-03-03 05:06:53 +08:00
|
|
|
}
|
2012-01-27 17:46:47 +08:00
|
|
|
|
2012-03-09 23:39:15 +08:00
|
|
|
// FIXME: We don't want this to happen. Rather, we should be able to
|
|
|
|
// detect all kinds of implicit accesses more cleanly.
|
2018-08-10 05:08:08 +08:00
|
|
|
SourceLocation BaseStartLoc = getBase()->getBeginLoc();
|
2012-03-09 23:39:15 +08:00
|
|
|
if (BaseStartLoc.isValid())
|
|
|
|
return BaseStartLoc;
|
|
|
|
return MemberLoc;
|
|
|
|
}
|
2018-08-10 04:05:47 +08:00
|
|
|
SourceLocation MemberExpr::getEndLoc() const {
|
2012-11-08 21:52:58 +08:00
|
|
|
SourceLocation EndLoc = getMemberNameInfo().getEndLoc();
|
2012-03-09 23:39:15 +08:00
|
|
|
if (hasExplicitTemplateArgs())
|
2012-11-08 21:52:58 +08:00
|
|
|
EndLoc = getRAngleLoc();
|
|
|
|
else if (EndLoc.isInvalid())
|
2018-08-10 05:09:38 +08:00
|
|
|
EndLoc = getBase()->getEndLoc();
|
2012-11-08 21:52:58 +08:00
|
|
|
return EndLoc;
|
2011-03-03 05:06:53 +08:00
|
|
|
}
|
|
|
|
|
2013-12-07 21:51:35 +08:00
|
|
|
bool CastExpr::CastConsistency() const {
|
2011-09-09 13:25:32 +08:00
|
|
|
switch (getCastKind()) {
|
|
|
|
case CK_DerivedToBase:
|
|
|
|
case CK_UncheckedDerivedToBase:
|
|
|
|
case CK_DerivedToBaseMemberPointer:
|
|
|
|
case CK_BaseToDerived:
|
|
|
|
case CK_BaseToDerivedMemberPointer:
|
|
|
|
assert(!path_empty() && "Cast kind should have a base path!");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CK_CPointerToObjCPointerCast:
|
|
|
|
assert(getType()->isObjCObjectPointerType());
|
|
|
|
assert(getSubExpr()->getType()->isPointerType());
|
|
|
|
goto CheckNoBasePath;
|
|
|
|
|
|
|
|
case CK_BlockPointerToObjCPointerCast:
|
|
|
|
assert(getType()->isObjCObjectPointerType());
|
|
|
|
assert(getSubExpr()->getType()->isBlockPointerType());
|
|
|
|
goto CheckNoBasePath;
|
|
|
|
|
2012-02-15 09:22:51 +08:00
|
|
|
case CK_ReinterpretMemberPointer:
|
|
|
|
assert(getType()->isMemberPointerType());
|
|
|
|
assert(getSubExpr()->getType()->isMemberPointerType());
|
|
|
|
goto CheckNoBasePath;
|
|
|
|
|
2011-09-09 13:25:32 +08:00
|
|
|
case CK_BitCast:
|
|
|
|
// Arbitrary casts to C pointer types count as bitcasts.
|
|
|
|
// Otherwise, we should only have block and ObjC pointer casts
|
|
|
|
// here if they stay within the type kind.
|
|
|
|
if (!getType()->isPointerType()) {
|
2018-07-31 03:24:48 +08:00
|
|
|
assert(getType()->isObjCObjectPointerType() ==
|
2011-09-09 13:25:32 +08:00
|
|
|
getSubExpr()->getType()->isObjCObjectPointerType());
|
2018-07-31 03:24:48 +08:00
|
|
|
assert(getType()->isBlockPointerType() ==
|
2011-09-09 13:25:32 +08:00
|
|
|
getSubExpr()->getType()->isBlockPointerType());
|
|
|
|
}
|
|
|
|
goto CheckNoBasePath;
|
|
|
|
|
|
|
|
case CK_AnyPointerToBlockPointerCast:
|
|
|
|
assert(getType()->isBlockPointerType());
|
|
|
|
assert(getSubExpr()->getType()->isAnyPointerType() &&
|
|
|
|
!getSubExpr()->getType()->isBlockPointerType());
|
|
|
|
goto CheckNoBasePath;
|
|
|
|
|
2012-02-22 13:02:47 +08:00
|
|
|
case CK_CopyAndAutoreleaseBlockObject:
|
|
|
|
assert(getType()->isBlockPointerType());
|
|
|
|
assert(getSubExpr()->getType()->isBlockPointerType());
|
|
|
|
goto CheckNoBasePath;
|
2012-08-31 08:14:07 +08:00
|
|
|
|
|
|
|
case CK_FunctionToPointerDecay:
|
|
|
|
assert(getType()->isPointerType());
|
|
|
|
assert(getSubExpr()->getType()->isFunctionType());
|
|
|
|
goto CheckNoBasePath;
|
|
|
|
|
2018-11-17 00:22:56 +08:00
|
|
|
case CK_AddressSpaceConversion: {
|
|
|
|
auto Ty = getType();
|
|
|
|
auto SETy = getSubExpr()->getType();
|
|
|
|
assert(getValueKindForType(Ty) == Expr::getValueKindForType(SETy));
|
2019-11-27 19:03:11 +08:00
|
|
|
if (isRValue()) {
|
2018-11-17 00:22:56 +08:00
|
|
|
Ty = Ty->getPointeeType();
|
|
|
|
SETy = SETy->getPointeeType();
|
2019-01-14 19:44:22 +08:00
|
|
|
}
|
2018-11-17 00:22:56 +08:00
|
|
|
assert(!Ty.isNull() && !SETy.isNull() &&
|
|
|
|
Ty.getAddressSpace() != SETy.getAddressSpace());
|
|
|
|
goto CheckNoBasePath;
|
|
|
|
}
|
2011-09-09 13:25:32 +08:00
|
|
|
// These should not have an inheritance path.
|
|
|
|
case CK_Dynamic:
|
|
|
|
case CK_ToUnion:
|
|
|
|
case CK_ArrayToPointerDecay:
|
|
|
|
case CK_NullToMemberPointer:
|
|
|
|
case CK_NullToPointer:
|
|
|
|
case CK_ConstructorConversion:
|
|
|
|
case CK_IntegralToPointer:
|
|
|
|
case CK_PointerToIntegral:
|
|
|
|
case CK_ToVoid:
|
|
|
|
case CK_VectorSplat:
|
|
|
|
case CK_IntegralCast:
|
2016-01-13 09:52:39 +08:00
|
|
|
case CK_BooleanToSignedIntegral:
|
2011-09-09 13:25:32 +08:00
|
|
|
case CK_IntegralToFloating:
|
|
|
|
case CK_FloatingToIntegral:
|
|
|
|
case CK_FloatingCast:
|
|
|
|
case CK_ObjCObjectLValueCast:
|
|
|
|
case CK_FloatingRealToComplex:
|
|
|
|
case CK_FloatingComplexToReal:
|
|
|
|
case CK_FloatingComplexCast:
|
|
|
|
case CK_FloatingComplexToIntegralComplex:
|
|
|
|
case CK_IntegralRealToComplex:
|
|
|
|
case CK_IntegralComplexToReal:
|
|
|
|
case CK_IntegralComplexCast:
|
|
|
|
case CK_IntegralComplexToFloatingComplex:
|
2011-09-10 14:18:15 +08:00
|
|
|
case CK_ARCProduceObject:
|
|
|
|
case CK_ARCConsumeObject:
|
|
|
|
case CK_ARCReclaimReturnedObject:
|
|
|
|
case CK_ARCExtendBlockObject:
|
2018-10-23 23:19:20 +08:00
|
|
|
case CK_ZeroToOCLOpaqueType:
|
2016-07-29 03:26:30 +08:00
|
|
|
case CK_IntToOCLSampler:
|
2018-10-16 00:07:02 +08:00
|
|
|
case CK_FixedPointCast:
|
2019-03-06 08:28:43 +08:00
|
|
|
case CK_FixedPointToIntegral:
|
|
|
|
case CK_IntegralToFixedPoint:
|
2011-09-09 13:25:32 +08:00
|
|
|
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
|
|
|
|
goto CheckNoBasePath;
|
|
|
|
|
|
|
|
case CK_Dependent:
|
|
|
|
case CK_LValueToRValue:
|
|
|
|
case CK_NoOp:
|
2012-01-17 01:27:18 +08:00
|
|
|
case CK_AtomicToNonAtomic:
|
|
|
|
case CK_NonAtomicToAtomic:
|
2011-09-09 13:25:32 +08:00
|
|
|
case CK_PointerToBoolean:
|
|
|
|
case CK_IntegralToBoolean:
|
|
|
|
case CK_FloatingToBoolean:
|
|
|
|
case CK_MemberPointerToBoolean:
|
|
|
|
case CK_FloatingComplexToBoolean:
|
|
|
|
case CK_IntegralComplexToBoolean:
|
|
|
|
case CK_LValueBitCast: // -> bool&
|
2019-07-03 02:28:13 +08:00
|
|
|
case CK_LValueToRValueBitCast:
|
2011-09-09 13:25:32 +08:00
|
|
|
case CK_UserDefinedConversion: // operator bool()
|
2012-08-31 08:14:07 +08:00
|
|
|
case CK_BuiltinFnToFnPtr:
|
2018-10-24 01:55:35 +08:00
|
|
|
case CK_FixedPointToBoolean:
|
2011-09-09 13:25:32 +08:00
|
|
|
CheckNoBasePath:
|
|
|
|
assert(path_empty() && "Cast kind should not have a base path!");
|
|
|
|
break;
|
|
|
|
}
|
2013-12-07 21:51:35 +08:00
|
|
|
return true;
|
2011-09-09 13:25:32 +08:00
|
|
|
}
|
|
|
|
|
[C++2a] Implement operator<=> CodeGen and ExprConstant
Summary:
This patch tackles long hanging fruit for the builtin operator<=> expressions. It is currently needs some cleanup before landing, but I want to get some initial feedback.
The main changes are:
* Lookup, build, and store the required standard library types and expressions in `ASTContext`. By storing them in ASTContext we don't need to store (and duplicate) the required expressions in the BinaryOperator AST nodes.
* Implement [expr.spaceship] checking, including diagnosing narrowing conversions.
* Implement `ExprConstant` for builtin spaceship operators.
* Implement builitin operator<=> support in `CodeGenAgg`. Initially I emitted the required comparisons using `ScalarExprEmitter::VisitBinaryOperator`, but this caused the operand expressions to be emitted once for every required cmp.
* Implement [builtin.over] with modifications to support the intent of P0946R0. See the note on `BuiltinOperatorOverloadBuilder::addThreeWayArithmeticOverloads` for more information about the workaround.
Reviewers: rsmith, aaron.ballman, majnemer, rnk, compnerd, rjmccall
Reviewed By: rjmccall
Subscribers: rjmccall, rsmith, aaron.ballman, junbuml, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D45476
llvm-svn: 331677
2018-05-08 05:07:10 +08:00
|
|
|
const char *CastExpr::getCastKindName(CastKind CK) {
|
|
|
|
switch (CK) {
|
2016-05-13 04:58:56 +08:00
|
|
|
#define CAST_OPERATION(Name) case CK_##Name: return #Name;
|
|
|
|
#include "clang/AST/OperationKinds.def"
|
2009-09-03 08:59:21 +08:00
|
|
|
}
|
2010-11-13 17:02:35 +08:00
|
|
|
llvm_unreachable("Unhandled cast kind!");
|
2009-09-03 08:59:21 +08:00
|
|
|
}
|
|
|
|
|
2017-11-18 02:09:48 +08:00
|
|
|
namespace {
|
2018-06-28 04:30:34 +08:00
|
|
|
const Expr *skipImplicitTemporary(const Expr *E) {
|
2017-11-18 02:09:48 +08:00
|
|
|
// Skip through reference binding to temporary.
|
2018-06-28 04:30:34 +08:00
|
|
|
if (auto *Materialize = dyn_cast<MaterializeTemporaryExpr>(E))
|
2019-11-17 18:41:55 +08:00
|
|
|
E = Materialize->getSubExpr();
|
2017-06-27 16:19:09 +08:00
|
|
|
|
2017-11-18 02:09:48 +08:00
|
|
|
// Skip any temporary bindings; they're implicit.
|
2018-06-28 04:30:34 +08:00
|
|
|
if (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
|
|
|
|
E = Binder->getSubExpr();
|
2017-06-27 16:19:09 +08:00
|
|
|
|
2018-06-28 04:30:34 +08:00
|
|
|
return E;
|
2017-11-18 02:09:48 +08:00
|
|
|
}
|
2017-06-27 16:19:09 +08:00
|
|
|
}
|
|
|
|
|
2009-12-15 03:27:10 +08:00
|
|
|
Expr *CastExpr::getSubExprAsWritten() {
|
2018-06-28 04:30:34 +08:00
|
|
|
const Expr *SubExpr = nullptr;
|
|
|
|
const CastExpr *E = this;
|
2009-12-15 03:27:10 +08:00
|
|
|
do {
|
2017-06-27 16:19:09 +08:00
|
|
|
SubExpr = skipImplicitTemporary(E->getSubExpr());
|
2011-06-22 01:03:29 +08:00
|
|
|
|
2009-12-15 03:27:10 +08:00
|
|
|
// Conversions by constructor and conversion functions have a
|
|
|
|
// subexpression describing the call; strip it off.
|
2010-08-25 19:45:40 +08:00
|
|
|
if (E->getCastKind() == CK_ConstructorConversion)
|
2017-06-27 16:19:09 +08:00
|
|
|
SubExpr =
|
|
|
|
skipImplicitTemporary(cast<CXXConstructExpr>(SubExpr)->getArg(0));
|
2016-02-03 06:23:03 +08:00
|
|
|
else if (E->getCastKind() == CK_UserDefinedConversion) {
|
|
|
|
assert((isa<CXXMemberCallExpr>(SubExpr) ||
|
|
|
|
isa<BlockExpr>(SubExpr)) &&
|
|
|
|
"Unexpected SubExpr for CK_UserDefinedConversion.");
|
2018-06-28 04:30:34 +08:00
|
|
|
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SubExpr))
|
|
|
|
SubExpr = MCE->getImplicitObjectArgument();
|
2016-02-03 06:23:03 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-12-15 03:27:10 +08:00
|
|
|
// If the subexpression we're left with is an implicit cast, look
|
|
|
|
// through that, too.
|
2018-07-31 03:24:48 +08:00
|
|
|
} while ((E = dyn_cast<ImplicitCastExpr>(SubExpr)));
|
|
|
|
|
2018-06-28 04:30:34 +08:00
|
|
|
return const_cast<Expr*>(SubExpr);
|
|
|
|
}
|
|
|
|
|
|
|
|
NamedDecl *CastExpr::getConversionFunction() const {
|
|
|
|
const Expr *SubExpr = nullptr;
|
|
|
|
|
|
|
|
for (const CastExpr *E = this; E; E = dyn_cast<ImplicitCastExpr>(SubExpr)) {
|
|
|
|
SubExpr = skipImplicitTemporary(E->getSubExpr());
|
|
|
|
|
|
|
|
if (E->getCastKind() == CK_ConstructorConversion)
|
|
|
|
return cast<CXXConstructExpr>(SubExpr)->getConstructor();
|
|
|
|
|
|
|
|
if (E->getCastKind() == CK_UserDefinedConversion) {
|
|
|
|
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SubExpr))
|
|
|
|
return MCE->getMethodDecl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
2009-12-15 03:27:10 +08:00
|
|
|
}
|
|
|
|
|
2010-08-07 14:22:56 +08:00
|
|
|
CXXBaseSpecifier **CastExpr::path_buffer() {
|
|
|
|
switch (getStmtClass()) {
|
|
|
|
#define ABSTRACT_STMT(x)
|
2015-12-30 10:27:28 +08:00
|
|
|
#define CASTEXPR(Type, Base) \
|
|
|
|
case Stmt::Type##Class: \
|
|
|
|
return static_cast<Type *>(this)->getTrailingObjects<CXXBaseSpecifier *>();
|
2010-08-07 14:22:56 +08:00
|
|
|
#define STMT(Type, Base)
|
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
default:
|
|
|
|
llvm_unreachable("non-cast expressions not possible here");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-16 05:42:47 +08:00
|
|
|
const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType,
|
|
|
|
QualType opType) {
|
|
|
|
auto RD = unionType->castAs<RecordType>()->getDecl();
|
|
|
|
return getTargetFieldForToUnionCast(RD, opType);
|
|
|
|
}
|
|
|
|
|
|
|
|
const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD,
|
|
|
|
QualType OpType) {
|
|
|
|
auto &Ctx = RD->getASTContext();
|
|
|
|
RecordDecl::field_iterator Field, FieldEnd;
|
|
|
|
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
|
|
|
|
Field != FieldEnd; ++Field) {
|
|
|
|
if (Ctx.hasSameUnqualifiedType(Field->getType(), OpType) &&
|
|
|
|
!Field->isUnnamedBitfield()) {
|
|
|
|
return *Field;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T,
|
2010-08-07 14:22:56 +08:00
|
|
|
CastKind Kind, Expr *Operand,
|
|
|
|
const CXXCastPath *BasePath,
|
2010-08-25 18:28:54 +08:00
|
|
|
ExprValueKind VK) {
|
2010-08-07 14:22:56 +08:00
|
|
|
unsigned PathSize = (BasePath ? BasePath->size() : 0);
|
2019-01-10 00:41:33 +08:00
|
|
|
void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
|
2019-06-15 01:46:38 +08:00
|
|
|
// Per C++ [conv.lval]p3, lvalue-to-rvalue conversions on class and
|
|
|
|
// std::nullptr_t have special semantics not captured by CK_LValueToRValue.
|
|
|
|
assert((Kind != CK_LValueToRValue ||
|
|
|
|
!(T->isNullPtrType() || T->getAsCXXRecordDecl())) &&
|
|
|
|
"invalid type for lvalue-to-rvalue conversion");
|
2010-08-07 14:22:56 +08:00
|
|
|
ImplicitCastExpr *E =
|
2010-08-25 18:28:54 +08:00
|
|
|
new (Buffer) ImplicitCastExpr(T, Kind, Operand, PathSize, VK);
|
2015-12-30 10:27:28 +08:00
|
|
|
if (PathSize)
|
|
|
|
std::uninitialized_copy_n(BasePath->data(), BasePath->size(),
|
|
|
|
E->getTrailingObjects<CXXBaseSpecifier *>());
|
2010-08-07 14:22:56 +08:00
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(const ASTContext &C,
|
2010-08-07 14:22:56 +08:00
|
|
|
unsigned PathSize) {
|
2019-01-10 00:41:33 +08:00
|
|
|
void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
|
2010-08-07 14:22:56 +08:00
|
|
|
return new (Buffer) ImplicitCastExpr(EmptyShell(), PathSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
CStyleCastExpr *CStyleCastExpr::Create(const ASTContext &C, QualType T,
|
2010-11-18 14:31:45 +08:00
|
|
|
ExprValueKind VK, CastKind K, Expr *Op,
|
2010-08-07 14:22:56 +08:00
|
|
|
const CXXCastPath *BasePath,
|
|
|
|
TypeSourceInfo *WrittenTy,
|
|
|
|
SourceLocation L, SourceLocation R) {
|
|
|
|
unsigned PathSize = (BasePath ? BasePath->size() : 0);
|
2019-01-10 00:41:33 +08:00
|
|
|
void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
|
2010-08-07 14:22:56 +08:00
|
|
|
CStyleCastExpr *E =
|
2010-11-18 14:31:45 +08:00
|
|
|
new (Buffer) CStyleCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, R);
|
2015-12-30 10:27:28 +08:00
|
|
|
if (PathSize)
|
|
|
|
std::uninitialized_copy_n(BasePath->data(), BasePath->size(),
|
|
|
|
E->getTrailingObjects<CXXBaseSpecifier *>());
|
2010-08-07 14:22:56 +08:00
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
CStyleCastExpr *CStyleCastExpr::CreateEmpty(const ASTContext &C,
|
|
|
|
unsigned PathSize) {
|
2019-01-10 00:41:33 +08:00
|
|
|
void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize));
|
2010-08-07 14:22:56 +08:00
|
|
|
return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize);
|
|
|
|
}
|
|
|
|
|
2006-08-23 14:42:10 +08:00
|
|
|
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
|
|
|
/// corresponds to, e.g. "<<=".
|
2012-10-08 09:11:04 +08:00
|
|
|
StringRef BinaryOperator::getOpcodeStr(Opcode Op) {
|
2006-08-23 14:42:10 +08:00
|
|
|
switch (Op) {
|
2016-05-13 04:58:56 +08:00
|
|
|
#define BINARY_OPERATION(Name, Spelling) case BO_##Name: return Spelling;
|
|
|
|
#include "clang/AST/OperationKinds.def"
|
2006-08-23 14:42:10 +08:00
|
|
|
}
|
2012-01-21 05:50:17 +08:00
|
|
|
llvm_unreachable("Invalid OpCode!");
|
2006-08-23 14:42:10 +08:00
|
|
|
}
|
2007-04-20 07:00:49 +08:00
|
|
|
|
2010-08-25 19:45:40 +08:00
|
|
|
BinaryOperatorKind
|
2009-03-14 02:40:31 +08:00
|
|
|
BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
|
|
|
|
switch (OO) {
|
2011-09-23 13:06:16 +08:00
|
|
|
default: llvm_unreachable("Not an overloadable binary operator");
|
2010-08-25 19:45:40 +08:00
|
|
|
case OO_Plus: return BO_Add;
|
|
|
|
case OO_Minus: return BO_Sub;
|
|
|
|
case OO_Star: return BO_Mul;
|
|
|
|
case OO_Slash: return BO_Div;
|
|
|
|
case OO_Percent: return BO_Rem;
|
|
|
|
case OO_Caret: return BO_Xor;
|
|
|
|
case OO_Amp: return BO_And;
|
|
|
|
case OO_Pipe: return BO_Or;
|
|
|
|
case OO_Equal: return BO_Assign;
|
2017-12-14 23:16:18 +08:00
|
|
|
case OO_Spaceship: return BO_Cmp;
|
2010-08-25 19:45:40 +08:00
|
|
|
case OO_Less: return BO_LT;
|
|
|
|
case OO_Greater: return BO_GT;
|
|
|
|
case OO_PlusEqual: return BO_AddAssign;
|
|
|
|
case OO_MinusEqual: return BO_SubAssign;
|
|
|
|
case OO_StarEqual: return BO_MulAssign;
|
|
|
|
case OO_SlashEqual: return BO_DivAssign;
|
|
|
|
case OO_PercentEqual: return BO_RemAssign;
|
|
|
|
case OO_CaretEqual: return BO_XorAssign;
|
|
|
|
case OO_AmpEqual: return BO_AndAssign;
|
|
|
|
case OO_PipeEqual: return BO_OrAssign;
|
|
|
|
case OO_LessLess: return BO_Shl;
|
|
|
|
case OO_GreaterGreater: return BO_Shr;
|
|
|
|
case OO_LessLessEqual: return BO_ShlAssign;
|
|
|
|
case OO_GreaterGreaterEqual: return BO_ShrAssign;
|
|
|
|
case OO_EqualEqual: return BO_EQ;
|
|
|
|
case OO_ExclaimEqual: return BO_NE;
|
|
|
|
case OO_LessEqual: return BO_LE;
|
|
|
|
case OO_GreaterEqual: return BO_GE;
|
|
|
|
case OO_AmpAmp: return BO_LAnd;
|
|
|
|
case OO_PipePipe: return BO_LOr;
|
|
|
|
case OO_Comma: return BO_Comma;
|
|
|
|
case OO_ArrowStar: return BO_PtrMemI;
|
2009-03-14 02:40:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
|
|
|
|
static const OverloadedOperatorKind OverOps[] = {
|
|
|
|
/* .* Cannot be overloaded */OO_None, OO_ArrowStar,
|
|
|
|
OO_Star, OO_Slash, OO_Percent,
|
|
|
|
OO_Plus, OO_Minus,
|
|
|
|
OO_LessLess, OO_GreaterGreater,
|
2017-12-14 23:16:18 +08:00
|
|
|
OO_Spaceship,
|
2009-03-14 02:40:31 +08:00
|
|
|
OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
|
|
|
|
OO_EqualEqual, OO_ExclaimEqual,
|
|
|
|
OO_Amp,
|
|
|
|
OO_Caret,
|
|
|
|
OO_Pipe,
|
|
|
|
OO_AmpAmp,
|
|
|
|
OO_PipePipe,
|
|
|
|
OO_Equal, OO_StarEqual,
|
|
|
|
OO_SlashEqual, OO_PercentEqual,
|
|
|
|
OO_PlusEqual, OO_MinusEqual,
|
|
|
|
OO_LessLessEqual, OO_GreaterGreaterEqual,
|
|
|
|
OO_AmpEqual, OO_CaretEqual,
|
|
|
|
OO_PipeEqual,
|
|
|
|
OO_Comma
|
|
|
|
};
|
|
|
|
return OverOps[Opc];
|
|
|
|
}
|
|
|
|
|
2017-09-20 04:26:40 +08:00
|
|
|
bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx,
|
|
|
|
Opcode Opc,
|
|
|
|
Expr *LHS, Expr *RHS) {
|
|
|
|
if (Opc != BO_Add)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check that we have one pointer and one integer operand.
|
|
|
|
Expr *PExp;
|
|
|
|
if (LHS->getType()->isPointerType()) {
|
|
|
|
if (!RHS->getType()->isIntegerType())
|
|
|
|
return false;
|
|
|
|
PExp = LHS;
|
|
|
|
} else if (RHS->getType()->isPointerType()) {
|
|
|
|
if (!LHS->getType()->isIntegerType())
|
|
|
|
return false;
|
|
|
|
PExp = RHS;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the pointer is a nullptr.
|
|
|
|
if (!PExp->IgnoreParenCasts()
|
|
|
|
->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check that the pointee type is char-sized.
|
|
|
|
const PointerType *PTy = PExp->getType()->getAs<PointerType>();
|
|
|
|
if (!PTy || !PTy->getPointeeType()->isCharType())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
Implement __builtin_LINE() et. al. to support source location capture.
Summary:
This patch implements the source location builtins `__builtin_LINE(), `__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These builtins are needed to implement [`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, and Clangs behavior is intended to match as closely as possible.
Reviewers: rsmith, joerg, aaron.ballman, bogner, majnemer, shafik, martong
Reviewed By: rsmith
Subscribers: rnkovacs, loskutov, riccibruno, mgorny, kunitoki, alexr, majnemer, hfinkel, cfe-commits
Differential Revision: https://reviews.llvm.org/D37035
llvm-svn: 360937
2019-05-17 05:04:15 +08:00
|
|
|
|
|
|
|
static QualType getDecayedSourceLocExprType(const ASTContext &Ctx,
|
|
|
|
SourceLocExpr::IdentKind Kind) {
|
|
|
|
switch (Kind) {
|
|
|
|
case SourceLocExpr::File:
|
|
|
|
case SourceLocExpr::Function: {
|
|
|
|
QualType ArrTy = Ctx.getStringLiteralArrayType(Ctx.CharTy, 0);
|
|
|
|
return Ctx.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType());
|
|
|
|
}
|
|
|
|
case SourceLocExpr::Line:
|
|
|
|
case SourceLocExpr::Column:
|
|
|
|
return Ctx.UnsignedIntTy;
|
|
|
|
}
|
|
|
|
llvm_unreachable("unhandled case");
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocExpr::SourceLocExpr(const ASTContext &Ctx, IdentKind Kind,
|
|
|
|
SourceLocation BLoc, SourceLocation RParenLoc,
|
|
|
|
DeclContext *ParentContext)
|
|
|
|
: Expr(SourceLocExprClass, getDecayedSourceLocExprType(Ctx, Kind),
|
|
|
|
VK_RValue, OK_Ordinary, false, false, false, false),
|
|
|
|
BuiltinLoc(BLoc), RParenLoc(RParenLoc), ParentContext(ParentContext) {
|
|
|
|
SourceLocExprBits.Kind = Kind;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef SourceLocExpr::getBuiltinStr() const {
|
|
|
|
switch (getIdentKind()) {
|
|
|
|
case File:
|
|
|
|
return "__builtin_FILE";
|
|
|
|
case Function:
|
|
|
|
return "__builtin_FUNCTION";
|
|
|
|
case Line:
|
|
|
|
return "__builtin_LINE";
|
|
|
|
case Column:
|
|
|
|
return "__builtin_COLUMN";
|
|
|
|
}
|
|
|
|
llvm_unreachable("unexpected IdentKind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
|
|
|
|
const Expr *DefaultExpr) const {
|
|
|
|
SourceLocation Loc;
|
|
|
|
const DeclContext *Context;
|
|
|
|
|
|
|
|
std::tie(Loc,
|
|
|
|
Context) = [&]() -> std::pair<SourceLocation, const DeclContext *> {
|
|
|
|
if (auto *DIE = dyn_cast_or_null<CXXDefaultInitExpr>(DefaultExpr))
|
|
|
|
return {DIE->getUsedLocation(), DIE->getUsedContext()};
|
|
|
|
if (auto *DAE = dyn_cast_or_null<CXXDefaultArgExpr>(DefaultExpr))
|
|
|
|
return {DAE->getUsedLocation(), DAE->getUsedContext()};
|
|
|
|
return {this->getLocation(), this->getParentContext()};
|
|
|
|
}();
|
|
|
|
|
|
|
|
PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(
|
|
|
|
Ctx.getSourceManager().getExpansionRange(Loc).getEnd());
|
|
|
|
|
|
|
|
auto MakeStringLiteral = [&](StringRef Tmp) {
|
|
|
|
using LValuePathEntry = APValue::LValuePathEntry;
|
|
|
|
StringLiteral *Res = Ctx.getPredefinedStringLiteralFromCache(Tmp);
|
|
|
|
// Decay the string to a pointer to the first character.
|
|
|
|
LValuePathEntry Path[1] = {LValuePathEntry::ArrayIndex(0)};
|
|
|
|
return APValue(Res, CharUnits::Zero(), Path, /*OnePastTheEnd=*/false);
|
|
|
|
};
|
|
|
|
|
|
|
|
switch (getIdentKind()) {
|
|
|
|
case SourceLocExpr::File:
|
|
|
|
return MakeStringLiteral(PLoc.getFilename());
|
|
|
|
case SourceLocExpr::Function: {
|
|
|
|
const Decl *CurDecl = dyn_cast_or_null<Decl>(Context);
|
|
|
|
return MakeStringLiteral(
|
|
|
|
CurDecl ? PredefinedExpr::ComputeName(PredefinedExpr::Function, CurDecl)
|
|
|
|
: std::string(""));
|
|
|
|
}
|
|
|
|
case SourceLocExpr::Line:
|
|
|
|
case SourceLocExpr::Column: {
|
|
|
|
llvm::APSInt IntVal(Ctx.getIntWidth(Ctx.UnsignedIntTy),
|
2019-07-16 12:46:31 +08:00
|
|
|
/*isUnsigned=*/true);
|
Implement __builtin_LINE() et. al. to support source location capture.
Summary:
This patch implements the source location builtins `__builtin_LINE(), `__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These builtins are needed to implement [`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, and Clangs behavior is intended to match as closely as possible.
Reviewers: rsmith, joerg, aaron.ballman, bogner, majnemer, shafik, martong
Reviewed By: rsmith
Subscribers: rnkovacs, loskutov, riccibruno, mgorny, kunitoki, alexr, majnemer, hfinkel, cfe-commits
Differential Revision: https://reviews.llvm.org/D37035
llvm-svn: 360937
2019-05-17 05:04:15 +08:00
|
|
|
IntVal = getIdentKind() == SourceLocExpr::Line ? PLoc.getLine()
|
|
|
|
: PLoc.getColumn();
|
|
|
|
return APValue(IntVal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm_unreachable("unhandled case");
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
|
2012-08-24 19:54:20 +08:00
|
|
|
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
|
2017-11-18 02:09:48 +08:00
|
|
|
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
|
|
|
|
false, false),
|
|
|
|
InitExprs(C, initExprs.size()),
|
|
|
|
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(nullptr, true)
|
|
|
|
{
|
2012-02-17 16:42:25 +08:00
|
|
|
sawArrayRangeDesignator(false);
|
2012-08-24 19:54:20 +08:00
|
|
|
for (unsigned I = 0; I != initExprs.size(); ++I) {
|
2010-02-19 09:50:18 +08:00
|
|
|
if (initExprs[I]->isTypeDependent())
|
2010-10-26 16:39:16 +08:00
|
|
|
ExprBits.TypeDependent = true;
|
2010-02-19 09:50:18 +08:00
|
|
|
if (initExprs[I]->isValueDependent())
|
2010-10-26 16:39:16 +08:00
|
|
|
ExprBits.ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
if (initExprs[I]->isInstantiationDependent())
|
|
|
|
ExprBits.InstantiationDependent = true;
|
2010-12-15 09:34:56 +08:00
|
|
|
if (initExprs[I]->containsUnexpandedParameterPack())
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
2009-11-20 07:25:22 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-08-24 19:54:20 +08:00
|
|
|
InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end());
|
2007-08-31 12:56:16 +08:00
|
|
|
}
|
2007-06-27 13:38:08 +08:00
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
void InitListExpr::reserveInits(const ASTContext &C, unsigned NumInits) {
|
2010-02-19 09:50:18 +08:00
|
|
|
if (NumInits > InitExprs.size())
|
2010-04-14 07:39:13 +08:00
|
|
|
InitExprs.reserve(C, NumInits);
|
2009-03-21 07:58:33 +08:00
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
void InitListExpr::resizeInits(const ASTContext &C, unsigned NumInits) {
|
2014-05-12 13:36:57 +08:00
|
|
|
InitExprs.resize(C, NumInits, nullptr);
|
2009-01-29 05:54:33 +08:00
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
Expr *InitListExpr::updateInit(const ASTContext &C, unsigned Init, Expr *expr) {
|
2010-02-19 09:50:18 +08:00
|
|
|
if (Init >= InitExprs.size()) {
|
2014-05-12 13:36:57 +08:00
|
|
|
InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, nullptr);
|
2013-12-06 09:27:24 +08:00
|
|
|
setInit(Init, expr);
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-01-29 05:54:33 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-29 05:54:33 +08:00
|
|
|
Expr *Result = cast_or_null<Expr>(InitExprs[Init]);
|
2013-12-06 09:27:24 +08:00
|
|
|
setInit(Init, expr);
|
2009-01-29 05:54:33 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2011-04-22 04:03:38 +08:00
|
|
|
void InitListExpr::setArrayFiller(Expr *filler) {
|
2011-10-22 07:02:22 +08:00
|
|
|
assert(!hasArrayFiller() && "Filler already set!");
|
2011-04-22 04:03:38 +08:00
|
|
|
ArrayFillerOrUnionFieldInit = filler;
|
|
|
|
// Fill out any "holes" in the array due to designated initializers.
|
|
|
|
Expr **inits = getInits();
|
|
|
|
for (unsigned i = 0, e = getNumInits(); i != e; ++i)
|
2014-05-12 13:36:57 +08:00
|
|
|
if (inits[i] == nullptr)
|
2011-04-22 04:03:38 +08:00
|
|
|
inits[i] = filler;
|
|
|
|
}
|
|
|
|
|
2012-04-15 10:50:59 +08:00
|
|
|
bool InitListExpr::isStringLiteralInit() const {
|
|
|
|
if (getNumInits() != 1)
|
|
|
|
return false;
|
2012-08-21 04:55:45 +08:00
|
|
|
const ArrayType *AT = getType()->getAsArrayTypeUnsafe();
|
|
|
|
if (!AT || !AT->getElementType()->isIntegerType())
|
2012-04-15 10:50:59 +08:00
|
|
|
return false;
|
2014-01-19 14:31:34 +08:00
|
|
|
// It is possible for getInit() to return null.
|
|
|
|
const Expr *Init = getInit(0);
|
|
|
|
if (!Init)
|
|
|
|
return false;
|
|
|
|
Init = Init->IgnoreParens();
|
2012-04-15 10:50:59 +08:00
|
|
|
return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
|
|
|
|
}
|
|
|
|
|
2016-12-07 07:52:28 +08:00
|
|
|
bool InitListExpr::isTransparent() const {
|
|
|
|
assert(isSemanticForm() && "syntactic form never semantically transparent");
|
|
|
|
|
|
|
|
// A glvalue InitListExpr is always just sugar.
|
|
|
|
if (isGLValue()) {
|
|
|
|
assert(getNumInits() == 1 && "multiple inits in glvalue init list");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we're sugar if and only if we have exactly one initializer that
|
|
|
|
// is of the same type.
|
|
|
|
if (getNumInits() != 1 || !getInit(0))
|
|
|
|
return false;
|
|
|
|
|
2017-02-24 06:41:47 +08:00
|
|
|
// Don't confuse aggregate initialization of a struct X { X &x; }; with a
|
|
|
|
// transparent struct copy.
|
|
|
|
if (!getInit(0)->isRValue() && getType()->isRecordType())
|
|
|
|
return false;
|
|
|
|
|
2016-12-07 07:52:28 +08:00
|
|
|
return getType().getCanonicalType() ==
|
|
|
|
getInit(0)->getType().getCanonicalType();
|
|
|
|
}
|
|
|
|
|
2017-09-29 17:44:41 +08:00
|
|
|
bool InitListExpr::isIdiomaticZeroInitializer(const LangOptions &LangOpts) const {
|
|
|
|
assert(isSyntacticForm() && "only test syntactic form as zero initializer");
|
|
|
|
|
2019-07-16 09:13:36 +08:00
|
|
|
if (LangOpts.CPlusPlus || getNumInits() != 1 || !getInit(0)) {
|
2017-09-29 17:44:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-07-16 09:13:36 +08:00
|
|
|
const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(getInit(0)->IgnoreImplicit());
|
2017-09-29 17:44:41 +08:00
|
|
|
return Lit && Lit->getValue() == 0;
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:03 +08:00
|
|
|
SourceLocation InitListExpr::getBeginLoc() const {
|
2012-11-09 02:41:43 +08:00
|
|
|
if (InitListExpr *SyntacticForm = getSyntacticForm())
|
2018-08-10 05:08:08 +08:00
|
|
|
return SyntacticForm->getBeginLoc();
|
2012-12-25 22:51:39 +08:00
|
|
|
SourceLocation Beg = LBraceLoc;
|
2010-11-09 10:11:40 +08:00
|
|
|
if (Beg.isInvalid()) {
|
|
|
|
// Find the first non-null initializer.
|
|
|
|
for (InitExprsTy::const_iterator I = InitExprs.begin(),
|
2018-07-31 03:24:48 +08:00
|
|
|
E = InitExprs.end();
|
2010-11-09 10:11:40 +08:00
|
|
|
I != E; ++I) {
|
|
|
|
if (Stmt *S = *I) {
|
2018-08-10 05:08:08 +08:00
|
|
|
Beg = S->getBeginLoc();
|
2010-11-09 10:11:40 +08:00
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
}
|
2010-11-09 10:11:40 +08:00
|
|
|
}
|
|
|
|
}
|
2012-12-25 22:51:39 +08:00
|
|
|
return Beg;
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:47 +08:00
|
|
|
SourceLocation InitListExpr::getEndLoc() const {
|
2012-12-25 22:51:39 +08:00
|
|
|
if (InitListExpr *SyntacticForm = getSyntacticForm())
|
2018-08-10 05:09:38 +08:00
|
|
|
return SyntacticForm->getEndLoc();
|
2012-12-25 22:51:39 +08:00
|
|
|
SourceLocation End = RBraceLoc;
|
2010-11-09 10:11:40 +08:00
|
|
|
if (End.isInvalid()) {
|
|
|
|
// Find the first non-null initializer from the end.
|
|
|
|
for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(),
|
2012-12-25 22:51:39 +08:00
|
|
|
E = InitExprs.rend();
|
|
|
|
I != E; ++I) {
|
2010-11-09 10:11:40 +08:00
|
|
|
if (Stmt *S = *I) {
|
2018-08-10 05:09:38 +08:00
|
|
|
End = S->getEndLoc();
|
2010-11-09 10:11:40 +08:00
|
|
|
break;
|
2012-12-25 22:51:39 +08:00
|
|
|
}
|
2010-11-09 10:11:40 +08:00
|
|
|
}
|
|
|
|
}
|
2012-12-25 22:51:39 +08:00
|
|
|
return End;
|
2010-11-09 10:11:40 +08:00
|
|
|
}
|
|
|
|
|
2008-09-04 23:31:07 +08:00
|
|
|
/// getFunctionType - Return the underlying function type for this block.
|
2017-11-18 02:09:48 +08:00
|
|
|
///
|
2012-02-17 11:32:35 +08:00
|
|
|
const FunctionProtoType *BlockExpr::getFunctionType() const {
|
|
|
|
// The block pointer is never sugared, but the function type might be.
|
|
|
|
return cast<BlockPointerType>(getType())
|
|
|
|
->getPointeeType()->castAs<FunctionProtoType>();
|
2008-09-04 02:15:37 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
SourceLocation BlockExpr::getCaretLocation() const {
|
|
|
|
return TheBlock->getCaretLocation();
|
2008-10-09 01:01:13 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
const Stmt *BlockExpr::getBody() const {
|
2009-04-18 08:02:19 +08:00
|
|
|
return TheBlock->getBody();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
Stmt *BlockExpr::getBody() {
|
|
|
|
return TheBlock->getBody();
|
2009-04-18 08:02:19 +08:00
|
|
|
}
|
2008-10-09 01:01:13 +08:00
|
|
|
|
2017-11-18 02:09:48 +08:00
|
|
|
|
2007-06-27 13:38:08 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Generic Expression Routines
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
/// isUnusedResultAWarning - Return true if this immediate expression should
|
|
|
|
/// be warned about if the result is unused. If so, fill in Loc and Ranges
|
|
|
|
/// with location to warn on and the source range[s] to report with the
|
|
|
|
/// warning.
|
2018-07-31 03:24:48 +08:00
|
|
|
bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
|
2012-05-24 08:47:05 +08:00
|
|
|
SourceRange &R1, SourceRange &R2,
|
|
|
|
ASTContext &Ctx) const {
|
2009-05-16 07:10:19 +08:00
|
|
|
// Don't warn if the expr is type dependent. The type could end up
|
|
|
|
// instantiating to void.
|
|
|
|
if (isTypeDependent())
|
|
|
|
return false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-27 13:38:08 +08:00
|
|
|
switch (getStmtClass()) {
|
|
|
|
default:
|
2010-03-12 15:11:26 +08:00
|
|
|
if (getType()->isVoidType())
|
|
|
|
return false;
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2009-02-14 15:37:35 +08:00
|
|
|
Loc = getExprLoc();
|
|
|
|
R1 = getSourceRange();
|
|
|
|
return true;
|
2007-06-27 13:38:08 +08:00
|
|
|
case ParenExprClass:
|
2009-02-14 15:37:35 +08:00
|
|
|
return cast<ParenExpr>(this)->getSubExpr()->
|
2012-05-24 08:47:05 +08:00
|
|
|
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2011-04-15 08:35:48 +08:00
|
|
|
case GenericSelectionExprClass:
|
|
|
|
return cast<GenericSelectionExpr>(this)->getResultExpr()->
|
2012-05-24 08:47:05 +08:00
|
|
|
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2018-03-27 08:58:16 +08:00
|
|
|
case CoawaitExprClass:
|
2018-03-27 11:33:06 +08:00
|
|
|
case CoyieldExprClass:
|
|
|
|
return cast<CoroutineSuspendExpr>(this)->getResumeExpr()->
|
2018-03-27 08:58:16 +08:00
|
|
|
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2013-07-20 08:40:58 +08:00
|
|
|
case ChooseExprClass:
|
|
|
|
return cast<ChooseExpr>(this)->getChosenSubExpr()->
|
|
|
|
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2007-06-27 13:38:08 +08:00
|
|
|
case UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *UO = cast<UnaryOperator>(this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-27 13:38:08 +08:00
|
|
|
switch (UO->getOpcode()) {
|
2012-05-24 08:47:05 +08:00
|
|
|
case UO_Plus:
|
|
|
|
case UO_Minus:
|
|
|
|
case UO_AddrOf:
|
|
|
|
case UO_Not:
|
|
|
|
case UO_LNot:
|
|
|
|
case UO_Deref:
|
|
|
|
break;
|
2015-10-27 14:02:45 +08:00
|
|
|
case UO_Coawait:
|
|
|
|
// This is just the 'operator co_await' call inside the guts of a
|
|
|
|
// dependent co_await call.
|
2010-08-25 19:45:40 +08:00
|
|
|
case UO_PostInc:
|
|
|
|
case UO_PostDec:
|
|
|
|
case UO_PreInc:
|
|
|
|
case UO_PreDec: // ++/--
|
2009-02-14 15:37:35 +08:00
|
|
|
return false; // Not a warning.
|
2010-08-25 19:45:40 +08:00
|
|
|
case UO_Real:
|
|
|
|
case UO_Imag:
|
2007-06-27 13:58:59 +08:00
|
|
|
// accessing a piece of a volatile complex is a side-effect.
|
2009-11-04 07:25:48 +08:00
|
|
|
if (Ctx.getCanonicalType(UO->getSubExpr()->getType())
|
|
|
|
.isVolatileQualified())
|
2009-02-14 15:37:35 +08:00
|
|
|
return false;
|
|
|
|
break;
|
2010-08-25 19:45:40 +08:00
|
|
|
case UO_Extension:
|
2012-05-24 08:47:05 +08:00
|
|
|
return UO->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2007-06-27 13:38:08 +08:00
|
|
|
}
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2009-02-14 15:37:35 +08:00
|
|
|
Loc = UO->getOperatorLoc();
|
|
|
|
R1 = UO->getSubExpr()->getSourceRange();
|
|
|
|
return true;
|
2007-06-27 13:38:08 +08:00
|
|
|
}
|
2007-12-01 14:07:34 +08:00
|
|
|
case BinaryOperatorClass: {
|
2009-02-14 15:37:35 +08:00
|
|
|
const BinaryOperator *BO = cast<BinaryOperator>(this);
|
2010-04-08 02:49:21 +08:00
|
|
|
switch (BO->getOpcode()) {
|
|
|
|
default:
|
|
|
|
break;
|
2010-06-30 18:53:14 +08:00
|
|
|
// Consider the RHS of comma for side effects. LHS was checked by
|
|
|
|
// Sema::CheckCommaOperands.
|
2010-08-25 19:45:40 +08:00
|
|
|
case BO_Comma:
|
2010-04-08 02:49:21 +08:00
|
|
|
// ((foo = <blah>), 0) is an idiom for hiding the result (and
|
|
|
|
// lvalue-ness) of an assignment written in a macro.
|
|
|
|
if (IntegerLiteral *IE =
|
|
|
|
dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens()))
|
|
|
|
if (IE->getValue() == 0)
|
|
|
|
return false;
|
2012-05-24 08:47:05 +08:00
|
|
|
return BO->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2010-06-30 18:53:14 +08:00
|
|
|
// Consider '||', '&&' to have side effects if the LHS or RHS does.
|
2010-08-25 19:45:40 +08:00
|
|
|
case BO_LAnd:
|
|
|
|
case BO_LOr:
|
2012-05-24 08:47:05 +08:00
|
|
|
if (!BO->getLHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx) ||
|
|
|
|
!BO->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx))
|
2010-06-30 18:53:14 +08:00
|
|
|
return false;
|
|
|
|
break;
|
2010-02-16 12:10:53 +08:00
|
|
|
}
|
2009-02-14 15:37:35 +08:00
|
|
|
if (BO->isAssignmentOp())
|
|
|
|
return false;
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2009-02-14 15:37:35 +08:00
|
|
|
Loc = BO->getOperatorLoc();
|
|
|
|
R1 = BO->getLHS()->getSourceRange();
|
|
|
|
R2 = BO->getRHS()->getSourceRange();
|
|
|
|
return true;
|
2007-12-01 14:07:34 +08:00
|
|
|
}
|
2007-08-25 10:00:02 +08:00
|
|
|
case CompoundAssignOperatorClass:
|
2010-05-09 06:41:50 +08:00
|
|
|
case VAArgExprClass:
|
2011-10-11 10:20:01 +08:00
|
|
|
case AtomicExprClass:
|
2009-02-14 15:37:35 +08:00
|
|
|
return false;
|
2007-06-27 13:38:08 +08:00
|
|
|
|
2007-12-02 03:58:28 +08:00
|
|
|
case ConditionalOperatorClass: {
|
2011-03-02 04:34:48 +08:00
|
|
|
// If only one of the LHS or RHS is a warning, the operator might
|
|
|
|
// be being used for control flow. Only warn if both the LHS and
|
|
|
|
// RHS are warnings.
|
2019-06-20 02:37:01 +08:00
|
|
|
const auto *Exp = cast<ConditionalOperator>(this);
|
|
|
|
return Exp->getLHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx) &&
|
|
|
|
Exp->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
|
|
|
}
|
|
|
|
case BinaryConditionalOperatorClass: {
|
|
|
|
const auto *Exp = cast<BinaryConditionalOperator>(this);
|
|
|
|
return Exp->getFalseExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2007-12-02 03:58:28 +08:00
|
|
|
}
|
|
|
|
|
2007-06-27 13:58:59 +08:00
|
|
|
case MemberExprClass:
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2009-02-14 15:37:35 +08:00
|
|
|
Loc = cast<MemberExpr>(this)->getMemberLoc();
|
|
|
|
R1 = SourceRange(Loc, Loc);
|
|
|
|
R2 = cast<MemberExpr>(this)->getBase()->getSourceRange();
|
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-27 13:38:08 +08:00
|
|
|
case ArraySubscriptExprClass:
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2009-02-14 15:37:35 +08:00
|
|
|
Loc = cast<ArraySubscriptExpr>(this)->getRBracketLoc();
|
|
|
|
R1 = cast<ArraySubscriptExpr>(this)->getLHS()->getSourceRange();
|
|
|
|
R2 = cast<ArraySubscriptExpr>(this)->getRHS()->getSourceRange();
|
|
|
|
return true;
|
2008-05-27 23:24:04 +08:00
|
|
|
|
2011-08-17 17:49:44 +08:00
|
|
|
case CXXOperatorCallExprClass: {
|
2014-03-11 11:11:08 +08:00
|
|
|
// Warn about operator ==,!=,<,>,<=, and >= even when user-defined operator
|
2011-08-17 17:49:44 +08:00
|
|
|
// overloads as there is no reasonable way to define these such that they
|
|
|
|
// have non-trivial, desirable side-effects. See the -Wunused-comparison
|
2014-03-11 11:11:08 +08:00
|
|
|
// warning: operators == and != are commonly typo'ed, and so warning on them
|
2011-08-17 17:49:44 +08:00
|
|
|
// provides additional value as well. If this list is updated,
|
|
|
|
// DiagnoseUnusedComparison should be as well.
|
|
|
|
const CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(this);
|
2014-03-11 11:11:08 +08:00
|
|
|
switch (Op->getOperator()) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case OO_EqualEqual:
|
|
|
|
case OO_ExclaimEqual:
|
|
|
|
case OO_Less:
|
|
|
|
case OO_Greater:
|
|
|
|
case OO_GreaterEqual:
|
|
|
|
case OO_LessEqual:
|
2015-02-26 01:36:15 +08:00
|
|
|
if (Op->getCallReturnType(Ctx)->isReferenceType() ||
|
|
|
|
Op->getCallReturnType(Ctx)->isVoidType())
|
2014-05-15 07:22:10 +08:00
|
|
|
break;
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2011-09-20 02:51:20 +08:00
|
|
|
Loc = Op->getOperatorLoc();
|
|
|
|
R1 = Op->getSourceRange();
|
2011-08-17 17:49:44 +08:00
|
|
|
return true;
|
2011-09-20 02:51:20 +08:00
|
|
|
}
|
2011-08-17 17:49:44 +08:00
|
|
|
|
|
|
|
// Fallthrough for generic call handling.
|
2017-06-03 14:31:42 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2011-08-17 17:49:44 +08:00
|
|
|
}
|
2007-06-27 13:38:08 +08:00
|
|
|
case CallExprClass:
|
2012-03-07 16:35:16 +08:00
|
|
|
case CXXMemberCallExprClass:
|
|
|
|
case UserDefinedLiteralClass: {
|
2009-02-14 15:37:35 +08:00
|
|
|
// If this is a direct call, get the callee.
|
|
|
|
const CallExpr *CE = cast<CallExpr>(this);
|
2009-12-21 07:11:08 +08:00
|
|
|
if (const Decl *FD = CE->getCalleeDecl()) {
|
2009-02-14 15:37:35 +08:00
|
|
|
// If the callee has attribute pure, const, or warn_unused_result, warn
|
|
|
|
// about it. void foo() { strlen("bar"); } should warn.
|
2009-10-13 12:53:48 +08:00
|
|
|
//
|
|
|
|
// Note: If new cases are added here, DiagnoseUnusedExprResult should be
|
|
|
|
// updated to match for QoI.
|
2019-01-03 22:24:31 +08:00
|
|
|
if (CE->hasUnusedResultAttr(Ctx) ||
|
2013-12-19 10:39:40 +08:00
|
|
|
FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>()) {
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2018-08-10 05:08:08 +08:00
|
|
|
Loc = CE->getCallee()->getBeginLoc();
|
2009-10-13 12:53:48 +08:00
|
|
|
R1 = CE->getCallee()->getSourceRange();
|
|
|
|
|
|
|
|
if (unsigned NumArgs = CE->getNumArgs())
|
2018-08-10 05:08:08 +08:00
|
|
|
R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
|
2018-08-10 05:09:38 +08:00
|
|
|
CE->getArg(NumArgs - 1)->getEndLoc());
|
2009-10-13 12:53:48 +08:00
|
|
|
return true;
|
|
|
|
}
|
2009-02-14 15:37:35 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2009-11-18 01:11:23 +08:00
|
|
|
|
2012-10-23 14:15:26 +08:00
|
|
|
// If we don't know precisely what we're looking at, let's not warn.
|
|
|
|
case UnresolvedLookupExprClass:
|
|
|
|
case CXXUnresolvedConstructExprClass:
|
|
|
|
return false;
|
|
|
|
|
2009-11-18 01:11:23 +08:00
|
|
|
case CXXTemporaryObjectExprClass:
|
2017-11-18 02:09:48 +08:00
|
|
|
case CXXConstructExprClass: {
|
2013-07-21 21:15:58 +08:00
|
|
|
if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
|
2019-07-25 23:10:56 +08:00
|
|
|
const auto *WarnURAttr = Type->getAttr<WarnUnusedResultAttr>();
|
|
|
|
if (Type->hasAttr<WarnUnusedAttr>() ||
|
|
|
|
(WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) {
|
2013-07-21 21:15:58 +08:00
|
|
|
WarnE = this;
|
2018-08-10 05:08:08 +08:00
|
|
|
Loc = getBeginLoc();
|
2013-07-21 21:15:58 +08:00
|
|
|
R1 = getSourceRange();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2019-07-25 23:10:56 +08:00
|
|
|
|
|
|
|
const auto *CE = cast<CXXConstructExpr>(this);
|
|
|
|
if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
|
|
|
|
const auto *WarnURAttr = Ctor->getAttr<WarnUnusedResultAttr>();
|
|
|
|
if (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) {
|
|
|
|
WarnE = this;
|
|
|
|
Loc = getBeginLoc();
|
|
|
|
R1 = getSourceRange();
|
|
|
|
|
|
|
|
if (unsigned NumArgs = CE->getNumArgs())
|
|
|
|
R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
|
|
|
|
CE->getArg(NumArgs - 1)->getEndLoc());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-18 01:11:23 +08:00
|
|
|
return false;
|
2017-11-18 02:09:48 +08:00
|
|
|
}
|
2009-11-18 01:11:23 +08:00
|
|
|
|
2010-03-31 02:22:15 +08:00
|
|
|
case ObjCMessageExprClass: {
|
|
|
|
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Ctx.getLangOpts().ObjCAutoRefCount &&
|
2011-06-16 07:02:42 +08:00
|
|
|
ME->isInstanceMessage() &&
|
|
|
|
!ME->getType()->isVoidType() &&
|
2013-07-20 04:25:56 +08:00
|
|
|
ME->getMethodFamily() == OMF_init) {
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2011-06-16 07:02:42 +08:00
|
|
|
Loc = getExprLoc();
|
|
|
|
R1 = ME->getSourceRange();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-19 06:59:10 +08:00
|
|
|
if (const ObjCMethodDecl *MD = ME->getMethodDecl())
|
2015-02-17 07:49:44 +08:00
|
|
|
if (MD->hasAttr<WarnUnusedResultAttr>()) {
|
2014-07-19 06:59:10 +08:00
|
|
|
WarnE = this;
|
|
|
|
Loc = getExprLoc();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-02-14 15:37:35 +08:00
|
|
|
return false;
|
2010-03-31 02:22:15 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-12-02 09:19:52 +08:00
|
|
|
case ObjCPropertyRefExprClass:
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2009-08-17 00:51:50 +08:00
|
|
|
Loc = getExprLoc();
|
|
|
|
R1 = getSourceRange();
|
2009-08-17 00:45:18 +08:00
|
|
|
return true;
|
2010-12-02 09:19:52 +08:00
|
|
|
|
2011-11-06 17:01:30 +08:00
|
|
|
case PseudoObjectExprClass: {
|
|
|
|
const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(this);
|
|
|
|
|
|
|
|
// Only complain about things that have the form of a getter.
|
|
|
|
if (isa<UnaryOperator>(PO->getSyntacticForm()) ||
|
|
|
|
isa<BinaryOperator>(PO->getSyntacticForm()))
|
|
|
|
return false;
|
|
|
|
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2011-11-06 17:01:30 +08:00
|
|
|
Loc = getExprLoc();
|
|
|
|
R1 = getSourceRange();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-07-27 03:51:01 +08:00
|
|
|
case StmtExprClass: {
|
|
|
|
// Statement exprs don't logically have side effects themselves, but are
|
|
|
|
// sometimes used in macros in ways that give them a type that is unused.
|
|
|
|
// For example ({ blah; foo(); }) will end up with a type if foo has a type.
|
|
|
|
// however, if the result of the stmt expr is dead, we don't want to emit a
|
|
|
|
// warning.
|
|
|
|
const CompoundStmt *CS = cast<StmtExpr>(this)->getSubStmt();
|
2010-09-20 05:21:10 +08:00
|
|
|
if (!CS->body_empty()) {
|
2008-07-27 03:51:01 +08:00
|
|
|
if (const Expr *E = dyn_cast<Expr>(CS->body_back()))
|
2012-05-24 08:47:05 +08:00
|
|
|
return E->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2010-09-20 05:21:10 +08:00
|
|
|
if (const LabelStmt *Label = dyn_cast<LabelStmt>(CS->body_back()))
|
|
|
|
if (const Expr *E = dyn_cast<Expr>(Label->getSubStmt()))
|
2012-05-24 08:47:05 +08:00
|
|
|
return E->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2010-09-20 05:21:10 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-12 15:11:26 +08:00
|
|
|
if (getType()->isVoidType())
|
|
|
|
return false;
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2009-02-14 15:37:35 +08:00
|
|
|
Loc = cast<StmtExpr>(this)->getLParenLoc();
|
|
|
|
R1 = getSourceRange();
|
|
|
|
return true;
|
2008-07-27 03:51:01 +08:00
|
|
|
}
|
2012-09-25 07:02:26 +08:00
|
|
|
case CXXFunctionalCastExprClass:
|
2012-05-24 08:47:05 +08:00
|
|
|
case CStyleCastExprClass: {
|
2012-05-25 05:05:41 +08:00
|
|
|
// Ignore an explicit cast to void unless the operand is a non-trivial
|
2012-05-24 08:47:05 +08:00
|
|
|
// volatile lvalue.
|
2012-05-25 05:05:41 +08:00
|
|
|
const CastExpr *CE = cast<CastExpr>(this);
|
2012-05-24 08:47:05 +08:00
|
|
|
if (CE->getCastKind() == CK_ToVoid) {
|
|
|
|
if (CE->getSubExpr()->isGLValue() &&
|
2012-05-25 05:05:41 +08:00
|
|
|
CE->getSubExpr()->getType().isVolatileQualified()) {
|
|
|
|
const DeclRefExpr *DRE =
|
|
|
|
dyn_cast<DeclRefExpr>(CE->getSubExpr()->IgnoreParens());
|
|
|
|
if (!(DRE && isa<VarDecl>(DRE->getDecl()) &&
|
2017-10-19 23:58:58 +08:00
|
|
|
cast<VarDecl>(DRE->getDecl())->hasLocalStorage()) &&
|
|
|
|
!isa<CallExpr>(CE->getSubExpr()->IgnoreParens())) {
|
2012-05-25 05:05:41 +08:00
|
|
|
return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc,
|
|
|
|
R1, R2, Ctx);
|
|
|
|
}
|
|
|
|
}
|
2010-03-12 15:11:26 +08:00
|
|
|
return false;
|
2012-05-24 08:47:05 +08:00
|
|
|
}
|
2012-05-25 05:05:41 +08:00
|
|
|
|
2012-05-24 08:47:05 +08:00
|
|
|
// If this is a cast to a constructor conversion, check the operand.
|
2009-11-18 01:11:23 +08:00
|
|
|
// Otherwise, the result of the cast is unused.
|
2012-05-24 08:47:05 +08:00
|
|
|
if (CE->getCastKind() == CK_ConstructorConversion)
|
|
|
|
return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2012-05-25 05:05:41 +08:00
|
|
|
|
2012-05-24 08:47:05 +08:00
|
|
|
WarnE = this;
|
2012-05-25 05:05:41 +08:00
|
|
|
if (const CXXFunctionalCastExpr *CXXCE =
|
|
|
|
dyn_cast<CXXFunctionalCastExpr>(this)) {
|
2018-08-10 05:08:08 +08:00
|
|
|
Loc = CXXCE->getBeginLoc();
|
2012-05-25 05:05:41 +08:00
|
|
|
R1 = CXXCE->getSubExpr()->getSourceRange();
|
|
|
|
} else {
|
|
|
|
const CStyleCastExpr *CStyleCE = cast<CStyleCastExpr>(this);
|
|
|
|
Loc = CStyleCE->getLParenLoc();
|
|
|
|
R1 = CStyleCE->getSubExpr()->getSourceRange();
|
|
|
|
}
|
2009-02-14 15:37:35 +08:00
|
|
|
return true;
|
2009-11-18 01:11:23 +08:00
|
|
|
}
|
2012-05-24 08:47:05 +08:00
|
|
|
case ImplicitCastExprClass: {
|
|
|
|
const CastExpr *ICE = cast<ImplicitCastExpr>(this);
|
|
|
|
|
|
|
|
// lvalue-to-rvalue conversion on a volatile lvalue is a side-effect.
|
|
|
|
if (ICE->getCastKind() == CK_LValueToRValue &&
|
|
|
|
ICE->getSubExpr()->getType().isVolatileQualified())
|
|
|
|
return false;
|
2008-05-20 05:24:43 +08:00
|
|
|
|
2012-05-24 08:47:05 +08:00
|
|
|
return ICE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
|
|
|
}
|
2008-04-08 12:40:51 +08:00
|
|
|
case CXXDefaultArgExprClass:
|
2009-11-04 07:25:48 +08:00
|
|
|
return (cast<CXXDefaultArgExpr>(this)
|
2012-05-24 08:47:05 +08:00
|
|
|
->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx));
|
2013-04-21 06:23:05 +08:00
|
|
|
case CXXDefaultInitExprClass:
|
|
|
|
return (cast<CXXDefaultInitExpr>(this)
|
|
|
|
->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx));
|
2008-11-22 03:14:01 +08:00
|
|
|
|
|
|
|
case CXXNewExprClass:
|
|
|
|
// FIXME: In theory, there might be new expressions that don't have side
|
|
|
|
// effects (e.g. a placement new with an uninitialized POD).
|
|
|
|
case CXXDeleteExprClass:
|
2009-02-14 15:37:35 +08:00
|
|
|
return false;
|
2016-12-07 07:52:28 +08:00
|
|
|
case MaterializeTemporaryExprClass:
|
2019-11-17 18:41:55 +08:00
|
|
|
return cast<MaterializeTemporaryExpr>(this)
|
|
|
|
->getSubExpr()
|
|
|
|
->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2009-08-16 12:11:06 +08:00
|
|
|
case CXXBindTemporaryExprClass:
|
2016-12-07 07:52:28 +08:00
|
|
|
return cast<CXXBindTemporaryExpr>(this)->getSubExpr()
|
|
|
|
->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2010-12-06 16:20:24 +08:00
|
|
|
case ExprWithCleanupsClass:
|
2016-12-07 07:52:28 +08:00
|
|
|
return cast<ExprWithCleanups>(this)->getSubExpr()
|
|
|
|
->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
2008-11-22 03:14:01 +08:00
|
|
|
}
|
2007-06-27 13:38:08 +08:00
|
|
|
}
|
|
|
|
|
2009-02-23 02:40:18 +08:00
|
|
|
/// isOBJCGCCandidate - Check if an expression is objc gc'able.
|
2009-09-09 07:38:54 +08:00
|
|
|
/// returns true, if it is; false otherwise.
|
2009-06-02 05:29:32 +08:00
|
|
|
bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
|
2011-04-15 08:35:48 +08:00
|
|
|
const Expr *E = IgnoreParens();
|
|
|
|
switch (E->getStmtClass()) {
|
2009-02-23 02:40:18 +08:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case ObjCIvarRefExprClass:
|
|
|
|
return true;
|
2009-02-24 02:59:50 +08:00
|
|
|
case Expr::UnaryOperatorClass:
|
2011-04-15 08:35:48 +08:00
|
|
|
return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
|
2009-02-23 02:40:18 +08:00
|
|
|
case ImplicitCastExprClass:
|
2011-04-15 08:35:48 +08:00
|
|
|
return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
|
2011-06-22 01:03:29 +08:00
|
|
|
case MaterializeTemporaryExprClass:
|
2019-11-17 18:41:55 +08:00
|
|
|
return cast<MaterializeTemporaryExpr>(E)->getSubExpr()->isOBJCGCCandidate(
|
|
|
|
Ctx);
|
2009-05-06 07:28:21 +08:00
|
|
|
case CStyleCastExprClass:
|
2011-04-15 08:35:48 +08:00
|
|
|
return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
|
2009-10-24 02:54:35 +08:00
|
|
|
case DeclRefExprClass: {
|
2012-03-10 17:33:50 +08:00
|
|
|
const Decl *D = cast<DeclRefExpr>(E)->getDecl();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-06-02 05:29:32 +08:00
|
|
|
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
if (VD->hasGlobalStorage())
|
|
|
|
return true;
|
|
|
|
QualType T = VD->getType();
|
2009-09-17 02:09:18 +08:00
|
|
|
// dereferencing to a pointer is always a gc'able candidate,
|
|
|
|
// unless it is __weak.
|
2009-09-17 14:31:17 +08:00
|
|
|
return T->isPointerType() &&
|
2009-09-25 03:53:00 +08:00
|
|
|
(Ctx.getObjCGCAttrKind(T) != Qualifiers::Weak);
|
2009-06-02 05:29:32 +08:00
|
|
|
}
|
2009-02-23 02:40:18 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-09-01 07:41:50 +08:00
|
|
|
case MemberExprClass: {
|
2011-04-15 08:35:48 +08:00
|
|
|
const MemberExpr *M = cast<MemberExpr>(E);
|
2009-06-02 05:29:32 +08:00
|
|
|
return M->getBase()->isOBJCGCCandidate(Ctx);
|
2009-02-23 02:40:18 +08:00
|
|
|
}
|
|
|
|
case ArraySubscriptExprClass:
|
2011-04-15 08:35:48 +08:00
|
|
|
return cast<ArraySubscriptExpr>(E)->getBase()->isOBJCGCCandidate(Ctx);
|
2009-02-23 02:40:18 +08:00
|
|
|
}
|
|
|
|
}
|
2010-09-11 04:55:33 +08:00
|
|
|
|
2010-11-02 02:49:26 +08:00
|
|
|
bool Expr::isBoundMemberFunction(ASTContext &Ctx) const {
|
|
|
|
if (isTypeDependent())
|
|
|
|
return false;
|
2010-11-24 13:12:34 +08:00
|
|
|
return ClassifyLValue(Ctx) == Expr::LV_MemberFunction;
|
2010-11-02 02:49:26 +08:00
|
|
|
}
|
|
|
|
|
2011-04-27 04:42:42 +08:00
|
|
|
QualType Expr::findBoundMemberType(const Expr *expr) {
|
2011-10-19 05:02:43 +08:00
|
|
|
assert(expr->hasPlaceholderType(BuiltinType::BoundMember));
|
2011-04-27 04:42:42 +08:00
|
|
|
|
|
|
|
// Bound member expressions are always one of these possibilities:
|
|
|
|
// x->m x.m x->*y x.*y
|
|
|
|
// (possibly parenthesized)
|
|
|
|
|
|
|
|
expr = expr->IgnoreParens();
|
|
|
|
if (const MemberExpr *mem = dyn_cast<MemberExpr>(expr)) {
|
|
|
|
assert(isa<CXXMethodDecl>(mem->getMemberDecl()));
|
|
|
|
return mem->getMemberDecl()->getType();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const BinaryOperator *op = dyn_cast<BinaryOperator>(expr)) {
|
|
|
|
QualType type = op->getRHS()->getType()->castAs<MemberPointerType>()
|
|
|
|
->getPointeeType();
|
|
|
|
assert(type->isFunctionType());
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2015-02-26 01:36:15 +08:00
|
|
|
assert(isa<UnresolvedMemberExpr>(expr) || isa<CXXPseudoDestructorExpr>(expr));
|
2011-04-27 04:42:42 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
static Expr *IgnoreImpCastsSingleStep(Expr *E) {
|
|
|
|
if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
|
|
|
|
return ICE->getSubExpr();
|
|
|
|
|
|
|
|
if (auto *FE = dyn_cast<FullExpr>(E))
|
|
|
|
return FE->getSubExpr();
|
|
|
|
|
2019-02-04 03:50:56 +08:00
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) {
|
|
|
|
// FIXME: Skip MaterializeTemporaryExpr and SubstNonTypeTemplateParmExpr in
|
|
|
|
// addition to what IgnoreImpCasts() skips to account for the current
|
|
|
|
// behaviour of IgnoreParenImpCasts().
|
|
|
|
Expr *SubE = IgnoreImpCastsSingleStep(E);
|
|
|
|
if (SubE != E)
|
|
|
|
return SubE;
|
2008-02-13 09:02:39 +08:00
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
|
2019-11-17 18:41:55 +08:00
|
|
|
return MTE->getSubExpr();
|
2019-02-17 21:32:39 +08:00
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
|
|
|
|
return NTTP->getReplacement();
|
2019-02-17 21:32:39 +08:00
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Expr *IgnoreCastsSingleStep(Expr *E) {
|
|
|
|
if (auto *CE = dyn_cast<CastExpr>(E))
|
|
|
|
return CE->getSubExpr();
|
|
|
|
|
|
|
|
if (auto *FE = dyn_cast<FullExpr>(E))
|
|
|
|
return FE->getSubExpr();
|
|
|
|
|
|
|
|
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
|
2019-11-17 18:41:55 +08:00
|
|
|
return MTE->getSubExpr();
|
2019-02-18 02:50:51 +08:00
|
|
|
|
|
|
|
if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
|
|
|
|
return NTTP->getReplacement();
|
2019-02-17 21:32:39 +08:00
|
|
|
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
static Expr *IgnoreLValueCastsSingleStep(Expr *E) {
|
|
|
|
// Skip what IgnoreCastsSingleStep skips, except that only
|
|
|
|
// lvalue-to-rvalue casts are skipped.
|
|
|
|
if (auto *CE = dyn_cast<CastExpr>(E))
|
|
|
|
if (CE->getCastKind() != CK_LValueToRValue)
|
|
|
|
return E;
|
|
|
|
|
|
|
|
return IgnoreCastsSingleStep(E);
|
2014-04-16 15:26:09 +08:00
|
|
|
}
|
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
static Expr *IgnoreBaseCastsSingleStep(Expr *E) {
|
|
|
|
if (auto *CE = dyn_cast<CastExpr>(E))
|
|
|
|
if (CE->getCastKind() == CK_DerivedToBase ||
|
|
|
|
CE->getCastKind() == CK_UncheckedDerivedToBase ||
|
|
|
|
CE->getCastKind() == CK_NoOp)
|
|
|
|
return CE->getSubExpr();
|
|
|
|
|
|
|
|
return E;
|
2010-12-04 11:47:34 +08:00
|
|
|
}
|
2012-06-28 09:56:38 +08:00
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
static Expr *IgnoreImplicitSingleStep(Expr *E) {
|
|
|
|
Expr *SubE = IgnoreImpCastsSingleStep(E);
|
|
|
|
if (SubE != E)
|
|
|
|
return SubE;
|
|
|
|
|
|
|
|
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
|
2019-11-17 18:41:55 +08:00
|
|
|
return MTE->getSubExpr();
|
2019-02-18 02:50:51 +08:00
|
|
|
|
|
|
|
if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
|
|
|
|
return BTE->getSubExpr();
|
|
|
|
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2019-12-06 10:04:46 +08:00
|
|
|
static Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) {
|
|
|
|
if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
|
|
|
|
return ICE->getSubExprAsWritten();
|
|
|
|
|
|
|
|
return IgnoreImplicitSingleStep(E);
|
|
|
|
}
|
|
|
|
|
2020-01-11 20:09:45 +08:00
|
|
|
static Expr *IgnoreParensOnlySingleStep(Expr *E) {
|
|
|
|
if (auto *PE = dyn_cast<ParenExpr>(E))
|
|
|
|
return PE->getSubExpr();
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
static Expr *IgnoreParensSingleStep(Expr *E) {
|
|
|
|
if (auto *PE = dyn_cast<ParenExpr>(E))
|
|
|
|
return PE->getSubExpr();
|
|
|
|
|
|
|
|
if (auto *UO = dyn_cast<UnaryOperator>(E)) {
|
|
|
|
if (UO->getOpcode() == UO_Extension)
|
|
|
|
return UO->getSubExpr();
|
2019-02-17 21:47:29 +08:00
|
|
|
}
|
2019-02-18 02:50:51 +08:00
|
|
|
|
|
|
|
else if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) {
|
|
|
|
if (!GSE->isResultDependent())
|
|
|
|
return GSE->getResultExpr();
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (auto *CE = dyn_cast<ChooseExpr>(E)) {
|
|
|
|
if (!CE->isConditionDependent())
|
|
|
|
return CE->getChosenSubExpr();
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (auto *CE = dyn_cast<ConstantExpr>(E))
|
|
|
|
return CE->getSubExpr();
|
|
|
|
|
|
|
|
return E;
|
2019-02-17 21:32:39 +08:00
|
|
|
}
|
2012-06-28 09:56:38 +08:00
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
static Expr *IgnoreNoopCastsSingleStep(const ASTContext &Ctx, Expr *E) {
|
|
|
|
if (auto *CE = dyn_cast<CastExpr>(E)) {
|
|
|
|
// We ignore integer <-> casts that are of the same width, ptr<->ptr and
|
|
|
|
// ptr<->int casts of the same width. We also ignore all identity casts.
|
|
|
|
Expr *SubExpr = CE->getSubExpr();
|
|
|
|
bool IsIdentityCast =
|
|
|
|
Ctx.hasSameUnqualifiedType(E->getType(), SubExpr->getType());
|
|
|
|
bool IsSameWidthCast =
|
|
|
|
(E->getType()->isPointerType() || E->getType()->isIntegralType(Ctx)) &&
|
|
|
|
(SubExpr->getType()->isPointerType() ||
|
|
|
|
SubExpr->getType()->isIntegralType(Ctx)) &&
|
|
|
|
(Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SubExpr->getType()));
|
|
|
|
|
|
|
|
if (IsIdentityCast || IsSameWidthCast)
|
|
|
|
return SubExpr;
|
2012-06-28 09:56:38 +08:00
|
|
|
}
|
2019-02-18 02:50:51 +08:00
|
|
|
|
|
|
|
else if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
|
|
|
|
return NTTP->getReplacement();
|
|
|
|
|
2019-02-17 21:32:39 +08:00
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
static Expr *IgnoreExprNodesImpl(Expr *E) { return E; }
|
|
|
|
template <typename FnTy, typename... FnTys>
|
|
|
|
static Expr *IgnoreExprNodesImpl(Expr *E, FnTy &&Fn, FnTys &&... Fns) {
|
|
|
|
return IgnoreExprNodesImpl(Fn(E), std::forward<FnTys>(Fns)...);
|
|
|
|
}
|
2019-02-17 21:32:39 +08:00
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
/// Given an expression E and functions Fn_1,...,Fn_n : Expr * -> Expr *,
|
|
|
|
/// Recursively apply each of the functions to E until reaching a fixed point.
|
|
|
|
/// Note that a null E is valid; in this case nothing is done.
|
|
|
|
template <typename... FnTys>
|
|
|
|
static Expr *IgnoreExprNodes(Expr *E, FnTys &&... Fns) {
|
|
|
|
Expr *LastE = nullptr;
|
|
|
|
while (E != LastE) {
|
|
|
|
LastE = E;
|
|
|
|
E = IgnoreExprNodesImpl(E, std::forward<FnTys>(Fns)...);
|
2019-02-17 21:47:29 +08:00
|
|
|
}
|
2019-02-18 02:50:51 +08:00
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *Expr::IgnoreImpCasts() {
|
|
|
|
return IgnoreExprNodes(this, IgnoreImpCastsSingleStep);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *Expr::IgnoreCasts() {
|
|
|
|
return IgnoreExprNodes(this, IgnoreCastsSingleStep);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *Expr::IgnoreImplicit() {
|
|
|
|
return IgnoreExprNodes(this, IgnoreImplicitSingleStep);
|
|
|
|
}
|
|
|
|
|
2019-12-06 10:04:46 +08:00
|
|
|
Expr *Expr::IgnoreImplicitAsWritten() {
|
|
|
|
return IgnoreExprNodes(this, IgnoreImplicitAsWrittenSingleStep);
|
|
|
|
}
|
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
Expr *Expr::IgnoreParens() {
|
|
|
|
return IgnoreExprNodes(this, IgnoreParensSingleStep);
|
2012-06-28 09:56:38 +08:00
|
|
|
}
|
|
|
|
|
2010-05-06 06:59:52 +08:00
|
|
|
Expr *Expr::IgnoreParenImpCasts() {
|
2019-02-18 02:50:51 +08:00
|
|
|
return IgnoreExprNodes(this, IgnoreParensSingleStep,
|
|
|
|
IgnoreImpCastsExtraSingleStep);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *Expr::IgnoreParenCasts() {
|
|
|
|
return IgnoreExprNodes(this, IgnoreParensSingleStep, IgnoreCastsSingleStep);
|
2010-05-06 06:59:52 +08:00
|
|
|
}
|
|
|
|
|
2011-06-10 01:06:51 +08:00
|
|
|
Expr *Expr::IgnoreConversionOperator() {
|
2019-02-04 03:50:56 +08:00
|
|
|
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(this)) {
|
2011-06-22 01:22:09 +08:00
|
|
|
if (MCE->getMethodDecl() && isa<CXXConversionDecl>(MCE->getMethodDecl()))
|
2011-06-10 01:06:51 +08:00
|
|
|
return MCE->getImplicitObjectArgument();
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
Expr *Expr::IgnoreParenLValueCasts() {
|
|
|
|
return IgnoreExprNodes(this, IgnoreParensSingleStep,
|
|
|
|
IgnoreLValueCastsSingleStep);
|
|
|
|
}
|
2019-02-17 21:47:29 +08:00
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
Expr *Expr::ignoreParenBaseCasts() {
|
|
|
|
return IgnoreExprNodes(this, IgnoreParensSingleStep,
|
|
|
|
IgnoreBaseCastsSingleStep);
|
|
|
|
}
|
2019-02-17 21:47:29 +08:00
|
|
|
|
2019-02-18 02:50:51 +08:00
|
|
|
Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) {
|
|
|
|
return IgnoreExprNodes(this, IgnoreParensSingleStep, [&Ctx](Expr *E) {
|
|
|
|
return IgnoreNoopCastsSingleStep(Ctx, E);
|
|
|
|
});
|
2009-03-14 01:28:01 +08:00
|
|
|
}
|
|
|
|
|
2019-05-04 23:51:58 +08:00
|
|
|
Expr *Expr::IgnoreUnlessSpelledInSource() {
|
|
|
|
Expr *E = this;
|
|
|
|
|
|
|
|
Expr *LastE = nullptr;
|
|
|
|
while (E != LastE) {
|
|
|
|
LastE = E;
|
2020-01-11 20:09:45 +08:00
|
|
|
E = IgnoreExprNodes(E, IgnoreImplicitSingleStep, IgnoreImpCastsSingleStep,
|
|
|
|
IgnoreParensOnlySingleStep);
|
2019-05-04 23:51:58 +08:00
|
|
|
|
|
|
|
auto SR = E->getSourceRange();
|
|
|
|
|
|
|
|
if (auto *C = dyn_cast<CXXConstructExpr>(E)) {
|
|
|
|
if (C->getNumArgs() == 1) {
|
|
|
|
Expr *A = C->getArg(0);
|
|
|
|
if (A->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C))
|
|
|
|
E = A;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
|
|
|
|
Expr *ExprNode = C->getImplicitObjectArgument()->IgnoreParenImpCasts();
|
|
|
|
if (ExprNode->getSourceRange() == SR)
|
|
|
|
E = ExprNode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2009-12-15 03:27:10 +08:00
|
|
|
bool Expr::isDefaultArgument() const {
|
|
|
|
const Expr *E = this;
|
2011-06-22 01:03:29 +08:00
|
|
|
if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
|
2019-11-17 18:41:55 +08:00
|
|
|
E = M->getSubExpr();
|
2011-06-22 01:03:29 +08:00
|
|
|
|
2009-12-15 03:27:10 +08:00
|
|
|
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
|
|
|
|
E = ICE->getSubExprAsWritten();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-12-15 03:27:10 +08:00
|
|
|
return isa<CXXDefaultArgExpr>(E);
|
|
|
|
}
|
2009-03-14 01:28:01 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Skip over any no-op casts and any temporary-binding
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
/// expressions.
|
2010-11-29 00:40:49 +08:00
|
|
|
static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
|
2011-06-22 01:03:29 +08:00
|
|
|
if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
|
2019-11-17 18:41:55 +08:00
|
|
|
E = M->getSubExpr();
|
2011-06-22 01:03:29 +08:00
|
|
|
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
|
2010-08-25 19:45:40 +08:00
|
|
|
if (ICE->getCastKind() == CK_NoOp)
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
E = ICE->getSubExpr();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (const CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
|
|
|
|
E = BE->getSubExpr();
|
|
|
|
|
|
|
|
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
|
2010-08-25 19:45:40 +08:00
|
|
|
if (ICE->getCastKind() == CK_NoOp)
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
E = ICE->getSubExpr();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
2010-11-29 00:40:49 +08:00
|
|
|
|
|
|
|
return E->IgnoreParens();
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
}
|
|
|
|
|
2010-09-15 18:14:12 +08:00
|
|
|
/// isTemporaryObject - Determines if this expression produces a
|
|
|
|
/// temporary of the given class type.
|
|
|
|
bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const {
|
|
|
|
if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy)))
|
|
|
|
return false;
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
|
2010-11-29 00:40:49 +08:00
|
|
|
const Expr *E = skipTemporaryBindingsNoOpCastsAndParens(this);
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
|
2010-09-16 04:59:13 +08:00
|
|
|
// Temporaries are by definition pr-values of class type.
|
2010-09-28 01:30:38 +08:00
|
|
|
if (!E->Classify(C).isPRValue()) {
|
|
|
|
// In this context, property reference is a message call and is pr-value.
|
2010-12-02 09:19:52 +08:00
|
|
|
if (!isa<ObjCPropertyRefExpr>(E))
|
2010-09-28 01:30:38 +08:00
|
|
|
return false;
|
|
|
|
}
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
|
2010-09-16 14:57:56 +08:00
|
|
|
// Black-list a few cases which yield pr-values of class type that don't
|
|
|
|
// refer to temporaries of that type:
|
|
|
|
|
|
|
|
// - implicit derived-to-base conversions
|
2010-09-15 18:14:12 +08:00
|
|
|
if (isa<ImplicitCastExpr>(E)) {
|
|
|
|
switch (cast<ImplicitCastExpr>(E)->getCastKind()) {
|
|
|
|
case CK_DerivedToBase:
|
|
|
|
case CK_UncheckedDerivedToBase:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
}
|
|
|
|
|
2010-09-16 14:57:56 +08:00
|
|
|
// - member expressions (all)
|
|
|
|
if (isa<MemberExpr>(E))
|
|
|
|
return false;
|
|
|
|
|
2012-06-16 07:51:06 +08:00
|
|
|
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
|
|
|
|
if (BO->isPtrMemOp())
|
|
|
|
return false;
|
|
|
|
|
2011-02-17 18:25:35 +08:00
|
|
|
// - opaque values (all)
|
|
|
|
if (isa<OpaqueValueExpr>(E))
|
|
|
|
return false;
|
|
|
|
|
2010-09-15 18:14:12 +08:00
|
|
|
return true;
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
}
|
|
|
|
|
2011-03-03 05:06:53 +08:00
|
|
|
bool Expr::isImplicitCXXThis() const {
|
|
|
|
const Expr *E = this;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-03-03 05:06:53 +08:00
|
|
|
// Strip away parentheses and casts we don't care about.
|
|
|
|
while (true) {
|
|
|
|
if (const ParenExpr *Paren = dyn_cast<ParenExpr>(E)) {
|
|
|
|
E = Paren->getSubExpr();
|
|
|
|
continue;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-03-03 05:06:53 +08:00
|
|
|
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
|
|
|
|
if (ICE->getCastKind() == CK_NoOp ||
|
|
|
|
ICE->getCastKind() == CK_LValueToRValue ||
|
2018-07-31 03:24:48 +08:00
|
|
|
ICE->getCastKind() == CK_DerivedToBase ||
|
2011-03-03 05:06:53 +08:00
|
|
|
ICE->getCastKind() == CK_UncheckedDerivedToBase) {
|
|
|
|
E = ICE->getSubExpr();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-03-03 05:06:53 +08:00
|
|
|
if (const UnaryOperator* UnOp = dyn_cast<UnaryOperator>(E)) {
|
|
|
|
if (UnOp->getOpcode() == UO_Extension) {
|
|
|
|
E = UnOp->getSubExpr();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-06-22 01:03:29 +08:00
|
|
|
if (const MaterializeTemporaryExpr *M
|
|
|
|
= dyn_cast<MaterializeTemporaryExpr>(E)) {
|
2019-11-17 18:41:55 +08:00
|
|
|
E = M->getSubExpr();
|
2011-06-22 01:03:29 +08:00
|
|
|
continue;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-03-03 05:06:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-03-03 05:06:53 +08:00
|
|
|
if (const CXXThisExpr *This = dyn_cast<CXXThisExpr>(E))
|
|
|
|
return This->isImplicit();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-03-03 05:06:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-12-06 07:32:09 +08:00
|
|
|
/// hasAnyTypeDependentArguments - Determines if any of the expressions
|
|
|
|
/// in Exprs is type-dependent.
|
2013-01-13 03:30:44 +08:00
|
|
|
bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
|
2012-02-25 19:00:22 +08:00
|
|
|
for (unsigned I = 0; I < Exprs.size(); ++I)
|
2008-12-06 07:32:09 +08:00
|
|
|
if (Exprs[I]->isTypeDependent())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-05-23 03:20:46 +08:00
|
|
|
bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
|
|
|
|
const Expr **Culprit) const {
|
2019-05-18 01:16:53 +08:00
|
|
|
assert(!isValueDependent() &&
|
|
|
|
"Expression evaluator can't be called on a dependent expression.");
|
|
|
|
|
2009-01-25 11:12:18 +08:00
|
|
|
// This function is attempting whether an expression is an initializer
|
2013-07-17 06:40:53 +08:00
|
|
|
// which can be evaluated at compile-time. It very closely parallels
|
|
|
|
// ConstExprEmitter in CGExprConstant.cpp; if they don't match, it
|
|
|
|
// will lead to unexpected results. Like ConstExprEmitter, it falls back
|
|
|
|
// to isEvaluatable most of the time.
|
|
|
|
//
|
2010-08-03 05:13:48 +08:00
|
|
|
// If we ever capture reference-binding directly in the AST, we can
|
|
|
|
// kill the second parameter.
|
|
|
|
|
|
|
|
if (IsForRef) {
|
|
|
|
EvalResult Result;
|
2014-05-23 03:20:46 +08:00
|
|
|
if (EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects)
|
|
|
|
return true;
|
|
|
|
if (Culprit)
|
|
|
|
*Culprit = this;
|
|
|
|
return false;
|
2010-08-03 05:13:48 +08:00
|
|
|
}
|
2009-02-20 10:36:22 +08:00
|
|
|
|
2008-11-24 13:23:59 +08:00
|
|
|
switch (getStmtClass()) {
|
2009-01-25 11:12:18 +08:00
|
|
|
default: break;
|
2008-11-24 13:23:59 +08:00
|
|
|
case StringLiteralClass:
|
2009-02-25 06:18:39 +08:00
|
|
|
case ObjCEncodeExprClass:
|
2008-11-24 13:23:59 +08:00
|
|
|
return true;
|
2010-08-02 05:51:45 +08:00
|
|
|
case CXXTemporaryObjectExprClass:
|
|
|
|
case CXXConstructExprClass: {
|
|
|
|
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
|
2010-08-03 05:13:48 +08:00
|
|
|
|
2013-07-17 06:40:53 +08:00
|
|
|
if (CE->getConstructor()->isTrivial() &&
|
|
|
|
CE->getConstructor()->getParent()->hasTrivialDestructor()) {
|
|
|
|
// Trivial default constructor
|
2011-11-10 14:34:14 +08:00
|
|
|
if (!CE->getNumArgs()) return true;
|
|
|
|
|
2013-07-17 06:40:53 +08:00
|
|
|
// Trivial copy constructor
|
|
|
|
assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument");
|
2014-05-23 03:20:46 +08:00
|
|
|
return CE->getArg(0)->isConstantInitializer(Ctx, false, Culprit);
|
2011-11-10 14:34:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2010-08-02 05:51:45 +08:00
|
|
|
}
|
2018-12-01 07:41:18 +08:00
|
|
|
case ConstantExprClass: {
|
|
|
|
// FIXME: We should be able to return "true" here, but it can lead to extra
|
|
|
|
// error messages. E.g. in Sema/array-init.c.
|
|
|
|
const Expr *Exp = cast<ConstantExpr>(this)->getSubExpr();
|
|
|
|
return Exp->isConstantInitializer(Ctx, false, Culprit);
|
|
|
|
}
|
2009-01-18 11:20:47 +08:00
|
|
|
case CompoundLiteralExprClass: {
|
2009-02-20 10:36:22 +08:00
|
|
|
// This handles gcc's extension that allows global initializers like
|
|
|
|
// "struct x {int x;} x = (struct x) {};".
|
|
|
|
// FIXME: This accepts other cases it shouldn't!
|
2009-01-18 11:20:47 +08:00
|
|
|
const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
|
2014-05-23 03:20:46 +08:00
|
|
|
return Exp->isConstantInitializer(Ctx, false, Culprit);
|
2009-01-18 11:20:47 +08:00
|
|
|
}
|
2015-06-10 08:27:52 +08:00
|
|
|
case DesignatedInitUpdateExprClass: {
|
|
|
|
const DesignatedInitUpdateExpr *DIUE = cast<DesignatedInitUpdateExpr>(this);
|
|
|
|
return DIUE->getBase()->isConstantInitializer(Ctx, false, Culprit) &&
|
|
|
|
DIUE->getUpdater()->isConstantInitializer(Ctx, false, Culprit);
|
|
|
|
}
|
2008-11-24 13:23:59 +08:00
|
|
|
case InitListExprClass: {
|
2013-07-17 06:40:53 +08:00
|
|
|
const InitListExpr *ILE = cast<InitListExpr>(this);
|
2019-05-10 14:39:20 +08:00
|
|
|
assert(ILE->isSemanticForm() && "InitListExpr must be in semantic form");
|
2013-07-17 06:40:53 +08:00
|
|
|
if (ILE->getType()->isArrayType()) {
|
|
|
|
unsigned numInits = ILE->getNumInits();
|
|
|
|
for (unsigned i = 0; i < numInits; i++) {
|
2014-05-23 03:20:46 +08:00
|
|
|
if (!ILE->getInit(i)->isConstantInitializer(Ctx, false, Culprit))
|
2013-07-17 06:40:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2008-11-24 13:23:59 +08:00
|
|
|
}
|
2013-07-17 06:40:53 +08:00
|
|
|
|
|
|
|
if (ILE->getType()->isRecordType()) {
|
|
|
|
unsigned ElementNo = 0;
|
2019-10-03 19:22:48 +08:00
|
|
|
RecordDecl *RD = ILE->getType()->castAs<RecordType>()->getDecl();
|
2014-08-22 00:06:57 +08:00
|
|
|
for (const auto *Field : RD->fields()) {
|
2013-07-17 06:40:53 +08:00
|
|
|
// If this is a union, skip all the fields that aren't being initialized.
|
2014-08-22 00:06:57 +08:00
|
|
|
if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field)
|
2013-07-17 06:40:53 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Don't emit anonymous bitfields, they just affect layout.
|
|
|
|
if (Field->isUnnamedBitfield())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ElementNo < ILE->getNumInits()) {
|
|
|
|
const Expr *Elt = ILE->getInit(ElementNo++);
|
|
|
|
if (Field->isBitField()) {
|
|
|
|
// Bitfields have to evaluate to an integer.
|
2018-12-01 07:41:18 +08:00
|
|
|
EvalResult Result;
|
|
|
|
if (!Elt->EvaluateAsInt(Result, Ctx)) {
|
2014-05-23 03:20:46 +08:00
|
|
|
if (Culprit)
|
|
|
|
*Culprit = Elt;
|
2013-07-17 06:40:53 +08:00
|
|
|
return false;
|
2014-05-23 03:20:46 +08:00
|
|
|
}
|
2013-07-17 06:40:53 +08:00
|
|
|
} else {
|
|
|
|
bool RefType = Field->getType()->isReferenceType();
|
2014-05-23 03:20:46 +08:00
|
|
|
if (!Elt->isConstantInitializer(Ctx, RefType, Culprit))
|
2013-07-17 06:40:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2008-11-24 13:23:59 +08:00
|
|
|
}
|
2009-01-30 01:44:32 +08:00
|
|
|
case ImplicitValueInitExprClass:
|
2015-06-10 08:27:52 +08:00
|
|
|
case NoInitExprClass:
|
2009-01-30 01:44:32 +08:00
|
|
|
return true;
|
2009-10-13 15:14:16 +08:00
|
|
|
case ParenExprClass:
|
2010-08-03 05:13:48 +08:00
|
|
|
return cast<ParenExpr>(this)->getSubExpr()
|
2014-05-23 03:20:46 +08:00
|
|
|
->isConstantInitializer(Ctx, IsForRef, Culprit);
|
2011-04-15 08:35:48 +08:00
|
|
|
case GenericSelectionExprClass:
|
|
|
|
return cast<GenericSelectionExpr>(this)->getResultExpr()
|
2014-05-23 03:20:46 +08:00
|
|
|
->isConstantInitializer(Ctx, IsForRef, Culprit);
|
2010-09-27 15:13:32 +08:00
|
|
|
case ChooseExprClass:
|
2014-05-23 03:20:46 +08:00
|
|
|
if (cast<ChooseExpr>(this)->isConditionDependent()) {
|
|
|
|
if (Culprit)
|
|
|
|
*Culprit = this;
|
2013-07-20 08:40:58 +08:00
|
|
|
return false;
|
2014-05-23 03:20:46 +08:00
|
|
|
}
|
2013-07-20 08:40:58 +08:00
|
|
|
return cast<ChooseExpr>(this)->getChosenSubExpr()
|
2014-05-23 03:20:46 +08:00
|
|
|
->isConstantInitializer(Ctx, IsForRef, Culprit);
|
2009-01-25 11:12:18 +08:00
|
|
|
case UnaryOperatorClass: {
|
|
|
|
const UnaryOperator* Exp = cast<UnaryOperator>(this);
|
2010-08-25 19:45:40 +08:00
|
|
|
if (Exp->getOpcode() == UO_Extension)
|
2014-05-23 03:20:46 +08:00
|
|
|
return Exp->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
|
2009-01-25 11:12:18 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-08-03 05:13:48 +08:00
|
|
|
case CXXFunctionalCastExprClass:
|
2010-08-02 05:51:45 +08:00
|
|
|
case CXXStaticCastExprClass:
|
2009-04-21 13:19:11 +08:00
|
|
|
case ImplicitCastExprClass:
|
2013-07-17 06:40:53 +08:00
|
|
|
case CStyleCastExprClass:
|
|
|
|
case ObjCBridgedCastExprClass:
|
|
|
|
case CXXDynamicCastExprClass:
|
|
|
|
case CXXReinterpretCastExprClass:
|
|
|
|
case CXXConstCastExprClass: {
|
2011-12-07 06:44:34 +08:00
|
|
|
const CastExpr *CE = cast<CastExpr>(this);
|
|
|
|
|
2011-12-21 08:43:02 +08:00
|
|
|
// Handle misc casts we want to ignore.
|
|
|
|
if (CE->getCastKind() == CK_NoOp ||
|
|
|
|
CE->getCastKind() == CK_LValueToRValue ||
|
|
|
|
CE->getCastKind() == CK_ToUnion ||
|
2013-07-17 06:40:53 +08:00
|
|
|
CE->getCastKind() == CK_ConstructorConversion ||
|
|
|
|
CE->getCastKind() == CK_NonAtomicToAtomic ||
|
2016-07-29 03:26:30 +08:00
|
|
|
CE->getCastKind() == CK_AtomicToNonAtomic ||
|
|
|
|
CE->getCastKind() == CK_IntToOCLSampler)
|
2014-05-23 03:20:46 +08:00
|
|
|
return CE->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
|
2011-12-07 06:44:34 +08:00
|
|
|
|
2009-01-25 11:12:18 +08:00
|
|
|
break;
|
2011-12-07 06:44:34 +08:00
|
|
|
}
|
2011-06-22 01:03:29 +08:00
|
|
|
case MaterializeTemporaryExprClass:
|
2019-11-17 18:41:55 +08:00
|
|
|
return cast<MaterializeTemporaryExpr>(this)
|
|
|
|
->getSubExpr()
|
|
|
|
->isConstantInitializer(Ctx, false, Culprit);
|
2017-11-18 02:09:48 +08:00
|
|
|
|
2013-07-17 06:40:53 +08:00
|
|
|
case SubstNonTypeTemplateParmExprClass:
|
|
|
|
return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
|
2014-05-23 03:20:46 +08:00
|
|
|
->isConstantInitializer(Ctx, false, Culprit);
|
2013-07-17 06:40:53 +08:00
|
|
|
case CXXDefaultArgExprClass:
|
|
|
|
return cast<CXXDefaultArgExpr>(this)->getExpr()
|
2014-05-23 03:20:46 +08:00
|
|
|
->isConstantInitializer(Ctx, false, Culprit);
|
2013-07-17 06:40:53 +08:00
|
|
|
case CXXDefaultInitExprClass:
|
|
|
|
return cast<CXXDefaultInitExpr>(this)->getExpr()
|
2014-05-23 03:20:46 +08:00
|
|
|
->isConstantInitializer(Ctx, false, Culprit);
|
2008-11-24 13:23:59 +08:00
|
|
|
}
|
2015-12-08 11:21:47 +08:00
|
|
|
// Allow certain forms of UB in constant initializers: signed integer
|
|
|
|
// overflow and floating-point division by zero. We'll give a warning on
|
|
|
|
// these, but they're common enough that we have to accept them.
|
|
|
|
if (isEvaluatable(Ctx, SE_AllowUndefinedBehavior))
|
2014-05-23 03:20:46 +08:00
|
|
|
return true;
|
|
|
|
if (Culprit)
|
|
|
|
*Culprit = this;
|
|
|
|
return false;
|
2007-09-03 04:30:18 +08:00
|
|
|
}
|
|
|
|
|
2018-02-14 05:31:47 +08:00
|
|
|
bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const {
|
|
|
|
const FunctionDecl* FD = getDirectCallee();
|
|
|
|
if (!FD || (FD->getBuiltinID() != Builtin::BI__assume &&
|
|
|
|
FD->getBuiltinID() != Builtin::BI__builtin_assume))
|
|
|
|
return false;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2018-02-14 05:31:47 +08:00
|
|
|
const Expr* Arg = getArg(0);
|
|
|
|
bool ArgVal;
|
|
|
|
return !Arg->isValueDependent() &&
|
|
|
|
Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal;
|
|
|
|
}
|
|
|
|
|
2015-06-10 23:18:23 +08:00
|
|
|
namespace {
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Look for any side effects within a Stmt.
|
2015-06-10 23:18:23 +08:00
|
|
|
class SideEffectFinder : public ConstEvaluatedExprVisitor<SideEffectFinder> {
|
2017-11-18 02:09:48 +08:00
|
|
|
typedef ConstEvaluatedExprVisitor<SideEffectFinder> Inherited;
|
2015-06-10 23:18:23 +08:00
|
|
|
const bool IncludePossibleEffects;
|
2017-11-18 02:09:48 +08:00
|
|
|
bool HasSideEffects;
|
2015-06-10 23:18:23 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
explicit SideEffectFinder(const ASTContext &Context, bool IncludePossible)
|
2017-11-18 02:09:48 +08:00
|
|
|
: Inherited(Context),
|
|
|
|
IncludePossibleEffects(IncludePossible), HasSideEffects(false) { }
|
2015-06-10 23:18:23 +08:00
|
|
|
|
|
|
|
bool hasSideEffects() const { return HasSideEffects; }
|
|
|
|
|
|
|
|
void VisitExpr(const Expr *E) {
|
|
|
|
if (!HasSideEffects &&
|
|
|
|
E->HasSideEffects(Context, IncludePossibleEffects))
|
|
|
|
HasSideEffects = true;
|
|
|
|
}
|
|
|
|
};
|
2017-11-18 02:09:48 +08:00
|
|
|
}
|
2015-06-10 23:18:23 +08:00
|
|
|
|
2014-12-18 05:57:17 +08:00
|
|
|
bool Expr::HasSideEffects(const ASTContext &Ctx,
|
|
|
|
bool IncludePossibleEffects) const {
|
|
|
|
// In circumstances where we care about definite side effects instead of
|
|
|
|
// potential side effects, we want to ignore expressions that are part of a
|
|
|
|
// macro expansion as a potential side effect.
|
|
|
|
if (!IncludePossibleEffects && getExprLoc().isMacroID())
|
|
|
|
return false;
|
|
|
|
|
2012-08-07 12:16:51 +08:00
|
|
|
if (isInstantiationDependent())
|
2014-12-18 05:57:17 +08:00
|
|
|
return IncludePossibleEffects;
|
2012-08-07 12:16:51 +08:00
|
|
|
|
|
|
|
switch (getStmtClass()) {
|
|
|
|
case NoStmtClass:
|
|
|
|
#define ABSTRACT_STMT(Type)
|
|
|
|
#define STMT(Type, Base) case Type##Class:
|
|
|
|
#define EXPR(Type, Base)
|
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
llvm_unreachable("unexpected Expr kind");
|
|
|
|
|
|
|
|
case DependentScopeDeclRefExprClass:
|
|
|
|
case CXXUnresolvedConstructExprClass:
|
|
|
|
case CXXDependentScopeMemberExprClass:
|
|
|
|
case UnresolvedLookupExprClass:
|
|
|
|
case UnresolvedMemberExprClass:
|
|
|
|
case PackExpansionExprClass:
|
|
|
|
case SubstNonTypeTemplateParmPackExprClass:
|
2012-09-12 08:56:43 +08:00
|
|
|
case FunctionParmPackExprClass:
|
2014-10-28 02:07:20 +08:00
|
|
|
case TypoExprClass:
|
2014-11-08 13:07:16 +08:00
|
|
|
case CXXFoldExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
llvm_unreachable("shouldn't see dependent / unresolved nodes here");
|
|
|
|
|
2012-08-07 13:18:29 +08:00
|
|
|
case DeclRefExprClass:
|
|
|
|
case ObjCIvarRefExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case PredefinedExprClass:
|
|
|
|
case IntegerLiteralClass:
|
2018-06-21 01:19:40 +08:00
|
|
|
case FixedPointLiteralClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case FloatingLiteralClass:
|
|
|
|
case ImaginaryLiteralClass:
|
|
|
|
case StringLiteralClass:
|
|
|
|
case CharacterLiteralClass:
|
|
|
|
case OffsetOfExprClass:
|
|
|
|
case ImplicitValueInitExprClass:
|
|
|
|
case UnaryExprOrTypeTraitExprClass:
|
|
|
|
case AddrLabelExprClass:
|
|
|
|
case GNUNullExprClass:
|
2016-12-12 10:53:20 +08:00
|
|
|
case ArrayInitIndexExprClass:
|
2015-06-10 08:27:52 +08:00
|
|
|
case NoInitExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case CXXBoolLiteralExprClass:
|
|
|
|
case CXXNullPtrLiteralExprClass:
|
|
|
|
case CXXThisExprClass:
|
|
|
|
case CXXScalarValueInitExprClass:
|
|
|
|
case TypeTraitExprClass:
|
|
|
|
case ArrayTypeTraitExprClass:
|
|
|
|
case ExpressionTraitExprClass:
|
|
|
|
case CXXNoexceptExprClass:
|
|
|
|
case SizeOfPackExprClass:
|
|
|
|
case ObjCStringLiteralClass:
|
|
|
|
case ObjCEncodeExprClass:
|
|
|
|
case ObjCBoolLiteralExprClass:
|
2016-07-16 08:35:23 +08:00
|
|
|
case ObjCAvailabilityCheckExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case CXXUuidofExprClass:
|
|
|
|
case OpaqueValueExprClass:
|
Implement __builtin_LINE() et. al. to support source location capture.
Summary:
This patch implements the source location builtins `__builtin_LINE(), `__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These builtins are needed to implement [`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, and Clangs behavior is intended to match as closely as possible.
Reviewers: rsmith, joerg, aaron.ballman, bogner, majnemer, shafik, martong
Reviewed By: rsmith
Subscribers: rnkovacs, loskutov, riccibruno, mgorny, kunitoki, alexr, majnemer, hfinkel, cfe-commits
Differential Revision: https://reviews.llvm.org/D37035
llvm-svn: 360937
2019-05-17 05:04:15 +08:00
|
|
|
case SourceLocExprClass:
|
2019-10-15 23:24:26 +08:00
|
|
|
case ConceptSpecializationExprClass:
|
2020-01-18 15:11:43 +08:00
|
|
|
case RequiresExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
// These never have a side-effect.
|
|
|
|
return false;
|
|
|
|
|
2018-10-31 11:48:47 +08:00
|
|
|
case ConstantExprClass:
|
|
|
|
// FIXME: Move this into the "return false;" block above.
|
|
|
|
return cast<ConstantExpr>(this)->getSubExpr()->HasSideEffects(
|
|
|
|
Ctx, IncludePossibleEffects);
|
|
|
|
|
2012-08-07 12:16:51 +08:00
|
|
|
case CallExprClass:
|
2014-12-18 05:57:17 +08:00
|
|
|
case CXXOperatorCallExprClass:
|
|
|
|
case CXXMemberCallExprClass:
|
|
|
|
case CUDAKernelCallExprClass:
|
2015-04-06 21:22:01 +08:00
|
|
|
case UserDefinedLiteralClass: {
|
|
|
|
// We don't know a call definitely has side effects, except for calls
|
|
|
|
// to pure/const functions that definitely don't.
|
|
|
|
// If the call itself is considered side-effect free, check the operands.
|
|
|
|
const Decl *FD = cast<CallExpr>(this)->getCalleeDecl();
|
|
|
|
bool IsPure = FD && (FD->hasAttr<ConstAttr>() || FD->hasAttr<PureAttr>());
|
|
|
|
if (IsPure || !IncludePossibleEffects)
|
|
|
|
break;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-18 05:57:17 +08:00
|
|
|
case BlockExprClass:
|
|
|
|
case CXXBindTemporaryExprClass:
|
|
|
|
if (!IncludePossibleEffects)
|
|
|
|
break;
|
|
|
|
return true;
|
|
|
|
|
2013-04-16 15:28:30 +08:00
|
|
|
case MSPropertyRefExprClass:
|
2015-11-25 20:01:00 +08:00
|
|
|
case MSPropertySubscriptExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case CompoundAssignOperatorClass:
|
|
|
|
case VAArgExprClass:
|
|
|
|
case AtomicExprClass:
|
|
|
|
case CXXThrowExprClass:
|
|
|
|
case CXXNewExprClass:
|
|
|
|
case CXXDeleteExprClass:
|
2015-10-27 14:02:45 +08:00
|
|
|
case CoawaitExprClass:
|
2017-03-07 07:38:15 +08:00
|
|
|
case DependentCoawaitExprClass:
|
2015-10-27 14:02:45 +08:00
|
|
|
case CoyieldExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
// These always have a side-effect.
|
|
|
|
return true;
|
|
|
|
|
2015-06-10 23:18:23 +08:00
|
|
|
case StmtExprClass: {
|
|
|
|
// StmtExprs have a side-effect if any substatement does.
|
|
|
|
SideEffectFinder Finder(Ctx, IncludePossibleEffects);
|
|
|
|
Finder.Visit(cast<StmtExpr>(this)->getSubStmt());
|
|
|
|
return Finder.hasSideEffects();
|
|
|
|
}
|
|
|
|
|
2016-06-22 04:29:17 +08:00
|
|
|
case ExprWithCleanupsClass:
|
|
|
|
if (IncludePossibleEffects)
|
|
|
|
if (cast<ExprWithCleanups>(this)->cleanupsHaveSideEffects())
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
|
2012-08-07 12:16:51 +08:00
|
|
|
case ParenExprClass:
|
|
|
|
case ArraySubscriptExprClass:
|
2015-08-25 22:24:04 +08:00
|
|
|
case OMPArraySectionExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case MemberExprClass:
|
|
|
|
case ConditionalOperatorClass:
|
|
|
|
case BinaryConditionalOperatorClass:
|
|
|
|
case CompoundLiteralExprClass:
|
|
|
|
case ExtVectorElementExprClass:
|
|
|
|
case DesignatedInitExprClass:
|
2015-06-10 08:27:52 +08:00
|
|
|
case DesignatedInitUpdateExprClass:
|
2016-12-12 10:53:20 +08:00
|
|
|
case ArrayInitLoopExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case ParenListExprClass:
|
|
|
|
case CXXPseudoDestructorExprClass:
|
2019-10-19 08:04:38 +08:00
|
|
|
case CXXRewrittenBinaryOperatorClass:
|
2013-06-13 06:31:48 +08:00
|
|
|
case CXXStdInitializerListExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case SubstNonTypeTemplateParmExprClass:
|
|
|
|
case MaterializeTemporaryExprClass:
|
|
|
|
case ShuffleVectorExprClass:
|
2013-09-18 11:29:45 +08:00
|
|
|
case ConvertVectorExprClass:
|
2012-08-07 12:16:51 +08:00
|
|
|
case AsTypeExprClass:
|
|
|
|
// These have a side-effect if any subexpression does.
|
|
|
|
break;
|
|
|
|
|
2012-08-07 13:18:29 +08:00
|
|
|
case UnaryOperatorClass:
|
|
|
|
if (cast<UnaryOperator>(this)->isIncrementDecrementOp())
|
2012-08-07 12:16:51 +08:00
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BinaryOperatorClass:
|
|
|
|
if (cast<BinaryOperator>(this)->isAssignmentOp())
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case InitListExprClass:
|
|
|
|
// FIXME: The children for an InitListExpr doesn't include the array filler.
|
|
|
|
if (const Expr *E = cast<InitListExpr>(this)->getArrayFiller())
|
2014-12-18 05:57:17 +08:00
|
|
|
if (E->HasSideEffects(Ctx, IncludePossibleEffects))
|
2012-08-07 12:16:51 +08:00
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GenericSelectionExprClass:
|
|
|
|
return cast<GenericSelectionExpr>(this)->getResultExpr()->
|
2014-12-18 05:57:17 +08:00
|
|
|
HasSideEffects(Ctx, IncludePossibleEffects);
|
2012-08-07 12:16:51 +08:00
|
|
|
|
|
|
|
case ChooseExprClass:
|
2014-12-18 05:57:17 +08:00
|
|
|
return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(
|
|
|
|
Ctx, IncludePossibleEffects);
|
2012-08-07 12:16:51 +08:00
|
|
|
|
|
|
|
case CXXDefaultArgExprClass:
|
2014-12-18 05:57:17 +08:00
|
|
|
return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(
|
|
|
|
Ctx, IncludePossibleEffects);
|
2012-08-07 12:16:51 +08:00
|
|
|
|
2014-11-18 07:36:45 +08:00
|
|
|
case CXXDefaultInitExprClass: {
|
|
|
|
const FieldDecl *FD = cast<CXXDefaultInitExpr>(this)->getField();
|
|
|
|
if (const Expr *E = FD->getInClassInitializer())
|
2014-12-18 05:57:17 +08:00
|
|
|
return E->HasSideEffects(Ctx, IncludePossibleEffects);
|
2013-04-21 06:23:05 +08:00
|
|
|
// If we've not yet parsed the initializer, assume it has side-effects.
|
|
|
|
return true;
|
2014-11-18 07:36:45 +08:00
|
|
|
}
|
2013-04-21 06:23:05 +08:00
|
|
|
|
2012-08-07 12:16:51 +08:00
|
|
|
case CXXDynamicCastExprClass: {
|
|
|
|
// A dynamic_cast expression has side-effects if it can throw.
|
|
|
|
const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(this);
|
|
|
|
if (DCE->getTypeAsWritten()->isReferenceType() &&
|
|
|
|
DCE->getCastKind() == CK_Dynamic)
|
|
|
|
return true;
|
2017-12-20 06:06:11 +08:00
|
|
|
}
|
|
|
|
LLVM_FALLTHROUGH;
|
2012-08-07 13:18:29 +08:00
|
|
|
case ImplicitCastExprClass:
|
|
|
|
case CStyleCastExprClass:
|
|
|
|
case CXXStaticCastExprClass:
|
|
|
|
case CXXReinterpretCastExprClass:
|
|
|
|
case CXXConstCastExprClass:
|
2019-07-03 02:28:13 +08:00
|
|
|
case CXXFunctionalCastExprClass:
|
|
|
|
case BuiltinBitCastExprClass: {
|
2015-01-04 01:00:12 +08:00
|
|
|
// While volatile reads are side-effecting in both C and C++, we treat them
|
|
|
|
// as having possible (not definite) side-effects. This allows idiomatic
|
|
|
|
// code to behave without warning, such as sizeof(*v) for a volatile-
|
|
|
|
// qualified pointer.
|
|
|
|
if (!IncludePossibleEffects)
|
|
|
|
break;
|
|
|
|
|
2012-08-07 13:18:29 +08:00
|
|
|
const CastExpr *CE = cast<CastExpr>(this);
|
|
|
|
if (CE->getCastKind() == CK_LValueToRValue &&
|
|
|
|
CE->getSubExpr()->getType().isVolatileQualified())
|
|
|
|
return true;
|
2012-08-07 12:16:51 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-08-14 04:08:14 +08:00
|
|
|
case CXXTypeidExprClass:
|
|
|
|
// typeid might throw if its subexpression is potentially-evaluated, so has
|
|
|
|
// side-effects in that case whether or not its subexpression does.
|
|
|
|
return cast<CXXTypeidExpr>(this)->isPotentiallyEvaluated();
|
2012-08-07 12:16:51 +08:00
|
|
|
|
|
|
|
case CXXConstructExprClass:
|
|
|
|
case CXXTemporaryObjectExprClass: {
|
|
|
|
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
|
2014-12-18 05:57:17 +08:00
|
|
|
if (!CE->getConstructor()->isTrivial() && IncludePossibleEffects)
|
2012-08-07 12:16:51 +08:00
|
|
|
return true;
|
2012-08-07 13:18:29 +08:00
|
|
|
// A trivial constructor does not add any side-effects of its own. Just look
|
|
|
|
// at its arguments.
|
2012-08-07 12:16:51 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
P0136R1, DR1573, DR1645, DR1715, DR1736, DR1903, DR1941, DR1959, DR1991:
Replace inheriting constructors implementation with new approach, voted into
C++ last year as a DR against C++11.
Instead of synthesizing a set of derived class constructors for each inherited
base class constructor, we make the constructors of the base class visible to
constructor lookup in the derived class, using the normal rules for
using-declarations.
For constructors, UsingShadowDecl now has a ConstructorUsingShadowDecl derived
class that tracks the requisite additional information. We create shadow
constructors (not found by name lookup) in the derived class to model the
actual initialization, and have a new expression node,
CXXInheritedCtorInitExpr, to model the initialization of a base class from such
a constructor. (This initialization is special because it performs real perfect
forwarding of arguments.)
In cases where argument forwarding is not possible (for inalloca calls,
variadic calls, and calls with callee parameter cleanup), the shadow inheriting
constructor is not emitted and instead we directly emit the initialization code
into the caller of the inherited constructor.
Note that this new model is not perfectly compatible with the old model in some
corner cases. In particular:
* if B inherits a private constructor from A, and C uses that constructor to
construct a B, then we previously required that A befriends B and B
befriends C, but the new rules require A to befriend C directly, and
* if a derived class has its own constructors (and so its implicit default
constructor is suppressed), it may still inherit a default constructor from
a base class
llvm-svn: 274049
2016-06-29 03:03:57 +08:00
|
|
|
case CXXInheritedCtorInitExprClass: {
|
|
|
|
const auto *ICIE = cast<CXXInheritedCtorInitExpr>(this);
|
|
|
|
if (!ICIE->getConstructor()->isTrivial() && IncludePossibleEffects)
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-08-07 12:16:51 +08:00
|
|
|
case LambdaExprClass: {
|
|
|
|
const LambdaExpr *LE = cast<LambdaExpr>(this);
|
2018-10-20 03:01:34 +08:00
|
|
|
for (Expr *E : LE->capture_inits())
|
|
|
|
if (E->HasSideEffects(Ctx, IncludePossibleEffects))
|
2012-08-07 12:16:51 +08:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PseudoObjectExprClass: {
|
|
|
|
// Only look for side-effects in the semantic form, and look past
|
|
|
|
// OpaqueValueExpr bindings in that form.
|
|
|
|
const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(this);
|
|
|
|
for (PseudoObjectExpr::const_semantics_iterator I = PO->semantics_begin(),
|
|
|
|
E = PO->semantics_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
const Expr *Subexpr = *I;
|
|
|
|
if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Subexpr))
|
|
|
|
Subexpr = OVE->getSourceExpr();
|
2014-12-18 05:57:17 +08:00
|
|
|
if (Subexpr->HasSideEffects(Ctx, IncludePossibleEffects))
|
2012-08-07 12:16:51 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ObjCBoxedExprClass:
|
|
|
|
case ObjCArrayLiteralClass:
|
|
|
|
case ObjCDictionaryLiteralClass:
|
|
|
|
case ObjCSelectorExprClass:
|
|
|
|
case ObjCProtocolExprClass:
|
|
|
|
case ObjCIsaExprClass:
|
|
|
|
case ObjCIndirectCopyRestoreExprClass:
|
|
|
|
case ObjCSubscriptRefExprClass:
|
|
|
|
case ObjCBridgedCastExprClass:
|
2014-12-18 05:57:17 +08:00
|
|
|
case ObjCMessageExprClass:
|
|
|
|
case ObjCPropertyRefExprClass:
|
|
|
|
// FIXME: Classify these cases better.
|
|
|
|
if (IncludePossibleEffects)
|
|
|
|
return true;
|
|
|
|
break;
|
2012-08-07 12:16:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Recurse to children.
|
2015-07-03 05:03:14 +08:00
|
|
|
for (const Stmt *SubStmt : children())
|
|
|
|
if (SubStmt &&
|
|
|
|
cast<Expr>(SubStmt)->HasSideEffects(Ctx, IncludePossibleEffects))
|
|
|
|
return true;
|
2012-08-07 12:16:51 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-23 15:33:15 +08:00
|
|
|
namespace {
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Look for a call to a non-trivial function within an expression.
|
2017-11-18 02:09:48 +08:00
|
|
|
class NonTrivialCallFinder : public ConstEvaluatedExprVisitor<NonTrivialCallFinder>
|
|
|
|
{
|
|
|
|
typedef ConstEvaluatedExprVisitor<NonTrivialCallFinder> Inherited;
|
2015-06-10 21:53:15 +08:00
|
|
|
|
2017-11-18 02:09:48 +08:00
|
|
|
bool NonTrivial;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-02-23 15:33:15 +08:00
|
|
|
public:
|
2015-06-10 21:53:15 +08:00
|
|
|
explicit NonTrivialCallFinder(const ASTContext &Context)
|
2017-11-18 02:09:48 +08:00
|
|
|
: Inherited(Context), NonTrivial(false) { }
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-02-23 15:33:15 +08:00
|
|
|
bool hasNonTrivialCall() const { return NonTrivial; }
|
2015-06-10 21:53:15 +08:00
|
|
|
|
|
|
|
void VisitCallExpr(const CallExpr *E) {
|
|
|
|
if (const CXXMethodDecl *Method
|
|
|
|
= dyn_cast_or_null<const CXXMethodDecl>(E->getCalleeDecl())) {
|
2012-02-23 15:33:15 +08:00
|
|
|
if (Method->isTrivial()) {
|
|
|
|
// Recurse to children of the call.
|
|
|
|
Inherited::VisitStmt(E);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-02-23 15:33:15 +08:00
|
|
|
NonTrivial = true;
|
|
|
|
}
|
2015-06-10 21:53:15 +08:00
|
|
|
|
|
|
|
void VisitCXXConstructExpr(const CXXConstructExpr *E) {
|
2012-02-23 15:33:15 +08:00
|
|
|
if (E->getConstructor()->isTrivial()) {
|
|
|
|
// Recurse to children of the call.
|
|
|
|
Inherited::VisitStmt(E);
|
|
|
|
return;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-02-23 15:33:15 +08:00
|
|
|
NonTrivial = true;
|
|
|
|
}
|
2015-06-10 21:53:15 +08:00
|
|
|
|
|
|
|
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) {
|
2012-02-23 15:33:15 +08:00
|
|
|
if (E->getTemporary()->getDestructor()->isTrivial()) {
|
|
|
|
Inherited::VisitStmt(E);
|
|
|
|
return;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-02-23 15:33:15 +08:00
|
|
|
NonTrivial = true;
|
|
|
|
}
|
|
|
|
};
|
2017-11-18 02:09:48 +08:00
|
|
|
}
|
2012-02-23 15:33:15 +08:00
|
|
|
|
2015-06-10 21:53:15 +08:00
|
|
|
bool Expr::hasNonTrivialCall(const ASTContext &Ctx) const {
|
2012-02-23 15:33:15 +08:00
|
|
|
NonTrivialCallFinder Finder(Ctx);
|
|
|
|
Finder.Visit(this);
|
2018-07-31 03:24:48 +08:00
|
|
|
return Finder.hasNonTrivialCall();
|
2012-02-23 15:33:15 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
/// isNullPointerConstant - C99 6.3.2.3p3 - Return whether this is a null
|
2011-02-19 07:54:50 +08:00
|
|
|
/// pointer constant or not, as well as the specific kind of constant detected.
|
|
|
|
/// Null pointer constants can be integer constant expressions with the
|
|
|
|
/// value zero, casts of zero to void*, nullptr (C++0X), or __null
|
|
|
|
/// (a GNU extension).
|
|
|
|
Expr::NullPointerConstantKind
|
|
|
|
Expr::isNullPointerConstant(ASTContext &Ctx,
|
|
|
|
NullPointerConstantValueDependence NPC) const {
|
2013-11-12 10:22:34 +08:00
|
|
|
if (isValueDependent() &&
|
2014-01-14 20:51:41 +08:00
|
|
|
(!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MSVCCompat)) {
|
2009-09-25 12:25:58 +08:00
|
|
|
switch (NPC) {
|
|
|
|
case NPC_NeverValueDependent:
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Unexpected value dependent expression!");
|
2009-09-25 12:25:58 +08:00
|
|
|
case NPC_ValueDependentIsNull:
|
2011-02-19 07:54:50 +08:00
|
|
|
if (isTypeDependent() || getType()->isIntegralType(Ctx))
|
2012-08-09 01:33:31 +08:00
|
|
|
return NPCK_ZeroExpression;
|
2011-02-19 07:54:50 +08:00
|
|
|
else
|
|
|
|
return NPCK_NotNull;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-09-25 12:25:58 +08:00
|
|
|
case NPC_ValueDependentIsNotNull:
|
2011-02-19 07:54:50 +08:00
|
|
|
return NPCK_NotNull;
|
2009-09-25 12:25:58 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-18 16:46:16 +08:00
|
|
|
|
2008-10-31 22:43:28 +08:00
|
|
|
// Strip off a cast to void*, if it exists. Except in C++.
|
2008-08-19 07:01:59 +08:00
|
|
|
if (const ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(this)) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!Ctx.getLangOpts().CPlusPlus) {
|
2008-10-31 22:43:28 +08:00
|
|
|
// Check that it is a cast to void*.
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const PointerType *PT = CE->getType()->getAs<PointerType>()) {
|
2008-10-31 22:43:28 +08:00
|
|
|
QualType Pointee = PT->getPointeeType();
|
2018-11-28 14:25:06 +08:00
|
|
|
Qualifiers Qs = Pointee.getQualifiers();
|
2017-10-13 11:37:48 +08:00
|
|
|
// Only (void*)0 or equivalent are treated as nullptr. If pointee type
|
|
|
|
// has non-default address space it is not treated as nullptr.
|
|
|
|
// (__generic void*)0 in OpenCL 2.0 should not be treated as nullptr
|
|
|
|
// since it cannot be assigned to a pointer to constant address space.
|
2018-11-28 14:25:06 +08:00
|
|
|
if ((Ctx.getLangOpts().OpenCLVersion >= 200 &&
|
2017-10-13 11:37:48 +08:00
|
|
|
Pointee.getAddressSpace() == LangAS::opencl_generic) ||
|
|
|
|
(Ctx.getLangOpts().OpenCL &&
|
|
|
|
Ctx.getLangOpts().OpenCLVersion < 200 &&
|
2018-11-28 14:25:06 +08:00
|
|
|
Pointee.getAddressSpace() == LangAS::opencl_private))
|
|
|
|
Qs.removeAddressSpace();
|
2017-10-13 11:37:48 +08:00
|
|
|
|
2018-11-28 14:25:06 +08:00
|
|
|
if (Pointee->isVoidType() && Qs.empty() && // to void*
|
|
|
|
CE->getSubExpr()->getType()->isIntegerType()) // from int
|
2009-09-25 12:25:58 +08:00
|
|
|
return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
|
2008-10-31 22:43:28 +08:00
|
|
|
}
|
2007-05-21 01:54:12 +08:00
|
|
|
}
|
2008-01-15 00:10:57 +08:00
|
|
|
} else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(this)) {
|
|
|
|
// Ignore the ImplicitCastExpr type entirely.
|
2009-09-25 12:25:58 +08:00
|
|
|
return ICE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
|
2008-01-15 00:10:57 +08:00
|
|
|
} else if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) {
|
|
|
|
// Accept ((void*)0) as a null pointer constant, as many other
|
|
|
|
// implementations do.
|
2009-09-25 12:25:58 +08:00
|
|
|
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
|
2011-04-15 08:35:48 +08:00
|
|
|
} else if (const GenericSelectionExpr *GE =
|
|
|
|
dyn_cast<GenericSelectionExpr>(this)) {
|
2013-07-20 08:40:58 +08:00
|
|
|
if (GE->isResultDependent())
|
|
|
|
return NPCK_NotNull;
|
2011-04-15 08:35:48 +08:00
|
|
|
return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
|
2013-07-20 08:40:58 +08:00
|
|
|
} else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(this)) {
|
|
|
|
if (CE->isConditionDependent())
|
|
|
|
return NPCK_NotNull;
|
|
|
|
return CE->getChosenSubExpr()->isNullPointerConstant(Ctx, NPC);
|
2009-09-09 23:08:12 +08:00
|
|
|
} else if (const CXXDefaultArgExpr *DefaultArg
|
2008-04-10 10:22:51 +08:00
|
|
|
= dyn_cast<CXXDefaultArgExpr>(this)) {
|
2013-04-21 06:23:05 +08:00
|
|
|
// See through default argument expressions.
|
2009-09-25 12:25:58 +08:00
|
|
|
return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC);
|
2013-04-21 06:23:05 +08:00
|
|
|
} else if (const CXXDefaultInitExpr *DefaultInit
|
|
|
|
= dyn_cast<CXXDefaultInitExpr>(this)) {
|
|
|
|
// See through default initializer expressions.
|
|
|
|
return DefaultInit->getExpr()->isNullPointerConstant(Ctx, NPC);
|
2008-11-29 12:51:27 +08:00
|
|
|
} else if (isa<GNUNullExpr>(this)) {
|
|
|
|
// The GNU __null extension is always a null pointer constant.
|
2011-02-19 07:54:50 +08:00
|
|
|
return NPCK_GNUNull;
|
2018-07-31 03:24:48 +08:00
|
|
|
} else if (const MaterializeTemporaryExpr *M
|
2011-06-22 01:03:29 +08:00
|
|
|
= dyn_cast<MaterializeTemporaryExpr>(this)) {
|
2019-11-17 18:41:55 +08:00
|
|
|
return M->getSubExpr()->isNullPointerConstant(Ctx, NPC);
|
2011-11-06 17:01:30 +08:00
|
|
|
} else if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(this)) {
|
|
|
|
if (const Expr *Source = OVE->getSourceExpr())
|
|
|
|
return Source->isNullPointerConstant(Ctx, NPC);
|
2008-01-14 10:53:34 +08:00
|
|
|
}
|
2008-11-29 12:51:27 +08:00
|
|
|
|
2013-01-02 20:01:23 +08:00
|
|
|
// C++11 nullptr_t is always a null pointer constant.
|
2009-05-11 02:38:11 +08:00
|
|
|
if (getType()->isNullPtrType())
|
2013-01-02 20:01:23 +08:00
|
|
|
return NPCK_CXX11_nullptr;
|
2009-05-11 02:38:11 +08:00
|
|
|
|
2010-09-28 06:42:37 +08:00
|
|
|
if (const RecordType *UT = getType()->getAsUnionType())
|
2013-06-13 10:46:14 +08:00
|
|
|
if (!Ctx.getLangOpts().CPlusPlus11 &&
|
|
|
|
UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
|
2010-09-28 06:42:37 +08:00
|
|
|
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){
|
|
|
|
const Expr *InitExpr = CLE->getInitializer();
|
|
|
|
if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr))
|
|
|
|
return ILE->getInit(0)->isNullPointerConstant(Ctx, NPC);
|
|
|
|
}
|
2008-01-15 00:10:57 +08:00
|
|
|
// This expression must be an integer type.
|
2018-07-31 03:24:48 +08:00
|
|
|
if (!getType()->isIntegerType() ||
|
2012-03-11 15:00:24 +08:00
|
|
|
(Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType()))
|
2011-02-19 07:54:50 +08:00
|
|
|
return NPCK_NotNull;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-01-02 19:42:31 +08:00
|
|
|
if (Ctx.getLangOpts().CPlusPlus11) {
|
2013-06-13 10:46:14 +08:00
|
|
|
// C++11 [conv.ptr]p1: A null pointer constant is an integer literal with
|
|
|
|
// value zero or a prvalue of type std::nullptr_t.
|
2013-11-12 10:22:34 +08:00
|
|
|
// Microsoft mode permits C++98 rules reflecting MSVC behavior.
|
2013-06-13 10:46:14 +08:00
|
|
|
const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(this);
|
2013-11-12 10:22:34 +08:00
|
|
|
if (Lit && !Lit->getValue())
|
|
|
|
return NPCK_ZeroLiteral;
|
2014-01-14 20:51:41 +08:00
|
|
|
else if (!Ctx.getLangOpts().MSVCCompat || !isCXX98IntegralConstantExpr(Ctx))
|
2013-11-12 10:22:34 +08:00
|
|
|
return NPCK_NotNull;
|
2012-02-15 05:38:30 +08:00
|
|
|
} else {
|
2013-06-13 10:46:14 +08:00
|
|
|
// If we have an integer constant expression, we need to *evaluate* it and
|
|
|
|
// test for the value 0.
|
2012-02-15 05:38:30 +08:00
|
|
|
if (!isIntegerConstantExpr(Ctx))
|
|
|
|
return NPCK_NotNull;
|
|
|
|
}
|
2011-02-19 07:54:50 +08:00
|
|
|
|
2012-08-09 01:33:31 +08:00
|
|
|
if (EvaluateKnownConstInt(Ctx) != 0)
|
|
|
|
return NPCK_NotNull;
|
|
|
|
|
|
|
|
if (isa<IntegerLiteral>(this))
|
|
|
|
return NPCK_ZeroLiteral;
|
|
|
|
return NPCK_ZeroExpression;
|
Bug #:
Submitted by:
Reviewed by:
Implemented type checking for compound assignments (*=, /=, etc.).
This encouraged me to do a fairly dramatic refactoring of the Check* functions.
(since I wanted to reuse the existing work, rather than duplicate the logic).
For example, I changed all the Check* functions to return a QualType (instead
of returning an Expr). This had a very nice side benefit...there is now
only one instantiation point for BinaryOperator()! (A property I've always
wanted...separating type checking from AST building is *much* nicer). Another
change is to remove "code" from all the Check* functions (this allowed
me to remove the weird comment about enums/unsigned:-). Removing the
code forced me to add a few functions, however. For example,
< ExprResult CheckAdditiveOperands( // C99 6.5.6
< Expr *lex, Expr *rex, SourceLocation OpLoc, unsigned OpCode);
> inline QualType CheckAdditionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
> inline QualType CheckSubtractionOperands( // C99 6.5.6
> Expr *lex, Expr *rex, SourceLocation OpLoc);
While this isn't as terse, it more closely reflects the differences in
the typechecking logic. For example, I disliked having to check the code again
in CheckMultiplicativeOperands/CheckAdditiveOperands.
Created the following helper functions:
- Expr::isNullPointerConstant().
- SemaExpr.cpp: static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode().
This was purely asethetic, since ParseBinOp() is now larger. I didn't feel
like looking at 2 huge switch statements. ParseBinOp() now avoids using
any of the BinaryOperator predicates (since I switched to a switch statement:-)
Only one regret (minor). I couldn't figure out how to avoid having two assign functions,
CheckCompoundAssignmentOperands, CheckSimpleAssignmentOperands. Conceptually,
the two functions make sense. Unfortunately, their implementation contains a lot of
duplication (thought they aren't that be in the first place).
llvm-svn: 39433
2007-05-05 05:54:46 +08:00
|
|
|
}
|
2007-07-29 07:10:27 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// If this expression is an l-value for an Objective C
|
2010-12-04 11:47:34 +08:00
|
|
|
/// property, find the underlying property reference expression.
|
|
|
|
const ObjCPropertyRefExpr *Expr::getObjCProperty() const {
|
|
|
|
const Expr *E = this;
|
|
|
|
while (true) {
|
|
|
|
assert((E->getValueKind() == VK_LValue &&
|
|
|
|
E->getObjectKind() == OK_ObjCProperty) &&
|
|
|
|
"expression is not a property reference");
|
|
|
|
E = E->IgnoreParenCasts();
|
|
|
|
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
|
|
|
|
if (BO->getOpcode() == BO_Comma) {
|
|
|
|
E = BO->getRHS();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cast<ObjCPropertyRefExpr>(E);
|
|
|
|
}
|
|
|
|
|
2012-10-02 04:34:04 +08:00
|
|
|
bool Expr::isObjCSelfExpr() const {
|
|
|
|
const Expr *E = IgnoreParenImpCasts();
|
|
|
|
|
|
|
|
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
|
|
|
|
if (!DRE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const ImplicitParamDecl *Param = dyn_cast<ImplicitParamDecl>(DRE->getDecl());
|
|
|
|
if (!Param)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(Param->getDeclContext());
|
|
|
|
if (!M)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return M->getSelfDecl() == Param;
|
|
|
|
}
|
|
|
|
|
2013-05-07 05:39:12 +08:00
|
|
|
FieldDecl *Expr::getSourceBitField() {
|
2009-07-06 23:38:40 +08:00
|
|
|
Expr *E = this->IgnoreParens();
|
2009-05-02 10:18:30 +08:00
|
|
|
|
2010-01-30 03:14:02 +08:00
|
|
|
while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
|
2010-12-04 11:47:34 +08:00
|
|
|
if (ICE->getCastKind() == CK_LValueToRValue ||
|
|
|
|
(ICE->getValueKind() != VK_RValue && ICE->getCastKind() == CK_NoOp))
|
2010-01-30 03:14:02 +08:00
|
|
|
E = ICE->getSubExpr()->IgnoreParens();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-10-29 08:13:59 +08:00
|
|
|
if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E))
|
2008-12-21 07:49:58 +08:00
|
|
|
if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl()))
|
2009-05-02 10:18:30 +08:00
|
|
|
if (Field->isBitField())
|
|
|
|
return Field;
|
|
|
|
|
2018-03-01 13:43:23 +08:00
|
|
|
if (ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
|
|
|
|
FieldDecl *Ivar = IvarRef->getDecl();
|
|
|
|
if (Ivar->isBitField())
|
|
|
|
return Ivar;
|
|
|
|
}
|
2013-05-07 05:39:12 +08:00
|
|
|
|
2016-08-12 06:25:46 +08:00
|
|
|
if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) {
|
2010-10-31 03:52:22 +08:00
|
|
|
if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl()))
|
|
|
|
if (Field->isBitField())
|
|
|
|
return Field;
|
|
|
|
|
2016-08-12 06:25:46 +08:00
|
|
|
if (BindingDecl *BD = dyn_cast<BindingDecl>(DeclRef->getDecl()))
|
|
|
|
if (Expr *E = BD->getBinding())
|
|
|
|
return E->getSourceBitField();
|
|
|
|
}
|
|
|
|
|
2011-07-13 10:05:57 +08:00
|
|
|
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) {
|
2009-05-02 10:18:30 +08:00
|
|
|
if (BinOp->isAssignmentOp() && BinOp->getLHS())
|
2013-05-07 05:39:12 +08:00
|
|
|
return BinOp->getLHS()->getSourceBitField();
|
2009-05-02 10:18:30 +08:00
|
|
|
|
2011-07-13 10:05:57 +08:00
|
|
|
if (BinOp->getOpcode() == BO_Comma && BinOp->getRHS())
|
2013-05-07 05:39:12 +08:00
|
|
|
return BinOp->getRHS()->getSourceBitField();
|
2011-07-13 10:05:57 +08:00
|
|
|
}
|
|
|
|
|
2014-09-25 07:55:00 +08:00
|
|
|
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E))
|
|
|
|
if (UnOp->isPrefix() && UnOp->isIncrementDecrementOp())
|
|
|
|
return UnOp->getSubExpr()->getSourceBitField();
|
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2008-10-29 08:13:59 +08:00
|
|
|
}
|
|
|
|
|
2010-02-01 01:18:49 +08:00
|
|
|
bool Expr::refersToVectorElement() const {
|
2016-08-12 06:25:46 +08:00
|
|
|
// FIXME: Why do we not just look at the ObjectKind here?
|
2010-02-01 01:18:49 +08:00
|
|
|
const Expr *E = this->IgnoreParens();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-02-01 01:18:49 +08:00
|
|
|
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
|
2010-08-25 18:28:54 +08:00
|
|
|
if (ICE->getValueKind() != VK_RValue &&
|
2010-08-25 19:45:40 +08:00
|
|
|
ICE->getCastKind() == CK_NoOp)
|
2010-02-01 01:18:49 +08:00
|
|
|
E = ICE->getSubExpr()->IgnoreParens();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-02-01 01:18:49 +08:00
|
|
|
if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E))
|
|
|
|
return ASE->getBase()->getType()->isVectorType();
|
|
|
|
|
|
|
|
if (isa<ExtVectorElementExpr>(E))
|
|
|
|
return true;
|
|
|
|
|
2016-08-12 06:25:46 +08:00
|
|
|
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
|
|
|
|
if (auto *BD = dyn_cast<BindingDecl>(DRE->getDecl()))
|
|
|
|
if (auto *E = BD->getBinding())
|
|
|
|
return E->refersToVectorElement();
|
|
|
|
|
2010-02-01 01:18:49 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-03 18:38:10 +08:00
|
|
|
bool Expr::refersToGlobalRegisterVar() const {
|
|
|
|
const Expr *E = this->IgnoreParenImpCasts();
|
|
|
|
|
|
|
|
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
|
|
|
|
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
|
|
|
|
if (VD->getStorageClass() == SC_Register &&
|
|
|
|
VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-21 11:02:26 +08:00
|
|
|
bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) {
|
|
|
|
E1 = E1->IgnoreParens();
|
|
|
|
E2 = E2->IgnoreParens();
|
|
|
|
|
|
|
|
if (E1->getStmtClass() != E2->getStmtClass())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (E1->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case CXXThisExprClass:
|
|
|
|
return true;
|
|
|
|
case DeclRefExprClass: {
|
|
|
|
// DeclRefExpr without an ImplicitCastExpr can happen for integral
|
|
|
|
// template parameters.
|
|
|
|
const auto *DRE1 = cast<DeclRefExpr>(E1);
|
|
|
|
const auto *DRE2 = cast<DeclRefExpr>(E2);
|
|
|
|
return DRE1->isRValue() && DRE2->isRValue() &&
|
|
|
|
DRE1->getDecl() == DRE2->getDecl();
|
|
|
|
}
|
|
|
|
case ImplicitCastExprClass: {
|
|
|
|
// Peel off implicit casts.
|
|
|
|
while (true) {
|
|
|
|
const auto *ICE1 = dyn_cast<ImplicitCastExpr>(E1);
|
|
|
|
const auto *ICE2 = dyn_cast<ImplicitCastExpr>(E2);
|
|
|
|
if (!ICE1 || !ICE2)
|
|
|
|
return false;
|
|
|
|
if (ICE1->getCastKind() != ICE2->getCastKind())
|
|
|
|
return false;
|
|
|
|
E1 = ICE1->getSubExpr()->IgnoreParens();
|
|
|
|
E2 = ICE2->getSubExpr()->IgnoreParens();
|
|
|
|
// The final cast must be one of these types.
|
|
|
|
if (ICE1->getCastKind() == CK_LValueToRValue ||
|
|
|
|
ICE1->getCastKind() == CK_ArrayToPointerDecay ||
|
|
|
|
ICE1->getCastKind() == CK_FunctionToPointerDecay) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto *DRE1 = dyn_cast<DeclRefExpr>(E1);
|
|
|
|
const auto *DRE2 = dyn_cast<DeclRefExpr>(E2);
|
|
|
|
if (DRE1 && DRE2)
|
|
|
|
return declaresSameEntity(DRE1->getDecl(), DRE2->getDecl());
|
|
|
|
|
|
|
|
const auto *Ivar1 = dyn_cast<ObjCIvarRefExpr>(E1);
|
|
|
|
const auto *Ivar2 = dyn_cast<ObjCIvarRefExpr>(E2);
|
|
|
|
if (Ivar1 && Ivar2) {
|
|
|
|
return Ivar1->isFreeIvar() && Ivar2->isFreeIvar() &&
|
|
|
|
declaresSameEntity(Ivar1->getDecl(), Ivar2->getDecl());
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto *Array1 = dyn_cast<ArraySubscriptExpr>(E1);
|
|
|
|
const auto *Array2 = dyn_cast<ArraySubscriptExpr>(E2);
|
|
|
|
if (Array1 && Array2) {
|
|
|
|
if (!isSameComparisonOperand(Array1->getBase(), Array2->getBase()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
auto Idx1 = Array1->getIdx();
|
|
|
|
auto Idx2 = Array2->getIdx();
|
|
|
|
const auto Integer1 = dyn_cast<IntegerLiteral>(Idx1);
|
|
|
|
const auto Integer2 = dyn_cast<IntegerLiteral>(Idx2);
|
|
|
|
if (Integer1 && Integer2) {
|
2019-09-21 12:18:54 +08:00
|
|
|
if (!llvm::APInt::isSameValue(Integer1->getValue(),
|
|
|
|
Integer2->getValue()))
|
2019-09-21 11:02:26 +08:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
if (!isSameComparisonOperand(Idx1, Idx2))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Walk the MemberExpr chain.
|
|
|
|
while (isa<MemberExpr>(E1) && isa<MemberExpr>(E2)) {
|
|
|
|
const auto *ME1 = cast<MemberExpr>(E1);
|
|
|
|
const auto *ME2 = cast<MemberExpr>(E2);
|
|
|
|
if (!declaresSameEntity(ME1->getMemberDecl(), ME2->getMemberDecl()))
|
|
|
|
return false;
|
|
|
|
if (const auto *D = dyn_cast<VarDecl>(ME1->getMemberDecl()))
|
|
|
|
if (D->isStaticDataMember())
|
|
|
|
return true;
|
|
|
|
E1 = ME1->getBase()->IgnoreParenImpCasts();
|
|
|
|
E2 = ME2->getBase()->IgnoreParenImpCasts();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isa<CXXThisExpr>(E1) && isa<CXXThisExpr>(E2))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// A static member variable can end the MemberExpr chain with either
|
|
|
|
// a MemberExpr or a DeclRefExpr.
|
|
|
|
auto getAnyDecl = [](const Expr *E) -> const ValueDecl * {
|
|
|
|
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
|
|
|
|
return DRE->getDecl();
|
|
|
|
if (const auto *ME = dyn_cast<MemberExpr>(E))
|
|
|
|
return ME->getMemberDecl();
|
|
|
|
return nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
const ValueDecl *VD1 = getAnyDecl(E1);
|
|
|
|
const ValueDecl *VD2 = getAnyDecl(E2);
|
|
|
|
return declaresSameEntity(VD1, VD2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-17 06:14:05 +08:00
|
|
|
/// isArrow - Return true if the base expression is a pointer to vector,
|
|
|
|
/// return false if the base expression is a vector.
|
|
|
|
bool ExtVectorElementExpr::isArrow() const {
|
|
|
|
return getBase()->getType()->isPointerType();
|
|
|
|
}
|
|
|
|
|
2008-04-19 07:10:10 +08:00
|
|
|
unsigned ExtVectorElementExpr::getNumElements() const {
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const VectorType *VT = getType()->getAs<VectorType>())
|
2008-05-09 14:41:27 +08:00
|
|
|
return VT->getNumElements();
|
|
|
|
return 1;
|
2007-08-04 00:00:20 +08:00
|
|
|
}
|
|
|
|
|
2008-05-09 14:41:27 +08:00
|
|
|
/// containsDuplicateElements - Return true if any element access is repeated.
|
2008-04-19 07:10:10 +08:00
|
|
|
bool ExtVectorElementExpr::containsDuplicateElements() const {
|
2009-10-18 10:09:09 +08:00
|
|
|
// FIXME: Refactor this code to an accessor on the AST node which returns the
|
|
|
|
// "type" of component access, and share with code below and in Sema.
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef Comp = Accessor->getName();
|
2009-01-18 10:01:21 +08:00
|
|
|
|
|
|
|
// Halving swizzles do not contain duplicate elements.
|
2009-10-18 07:53:04 +08:00
|
|
|
if (Comp == "hi" || Comp == "lo" || Comp == "even" || Comp == "odd")
|
2009-01-18 10:01:21 +08:00
|
|
|
return false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-18 10:01:21 +08:00
|
|
|
// Advance past s-char prefix on hex swizzles.
|
2009-10-18 07:53:04 +08:00
|
|
|
if (Comp[0] == 's' || Comp[0] == 'S')
|
|
|
|
Comp = Comp.substr(1);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-18 07:53:04 +08:00
|
|
|
for (unsigned i = 0, e = Comp.size(); i != e; ++i)
|
2011-07-23 18:55:15 +08:00
|
|
|
if (Comp.substr(i + 1).find(Comp[i]) != StringRef::npos)
|
2007-07-30 11:29:09 +08:00
|
|
|
return true;
|
2009-10-18 07:53:04 +08:00
|
|
|
|
2007-07-30 11:29:09 +08:00
|
|
|
return false;
|
|
|
|
}
|
2007-08-03 07:36:59 +08:00
|
|
|
|
2008-05-09 14:41:27 +08:00
|
|
|
/// getEncodedElementAccess - We encode the fields as a llvm ConstantArray.
|
2008-05-14 05:03:02 +08:00
|
|
|
void ExtVectorElementExpr::getEncodedElementAccess(
|
2015-07-29 00:25:32 +08:00
|
|
|
SmallVectorImpl<uint32_t> &Elts) const {
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef Comp = Accessor->getName();
|
2016-07-23 02:49:43 +08:00
|
|
|
bool isNumericAccessor = false;
|
|
|
|
if (Comp[0] == 's' || Comp[0] == 'S') {
|
2009-10-18 10:09:31 +08:00
|
|
|
Comp = Comp.substr(1);
|
2016-07-23 02:49:43 +08:00
|
|
|
isNumericAccessor = true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-18 10:09:31 +08:00
|
|
|
bool isHi = Comp == "hi";
|
|
|
|
bool isLo = Comp == "lo";
|
|
|
|
bool isEven = Comp == "even";
|
|
|
|
bool isOdd = Comp == "odd";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-05-09 14:41:27 +08:00
|
|
|
for (unsigned i = 0, e = getNumElements(); i != e; ++i) {
|
|
|
|
uint64_t Index;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-05-09 14:41:27 +08:00
|
|
|
if (isHi)
|
|
|
|
Index = e + i;
|
|
|
|
else if (isLo)
|
|
|
|
Index = i;
|
|
|
|
else if (isEven)
|
|
|
|
Index = 2 * i;
|
|
|
|
else if (isOdd)
|
|
|
|
Index = 2 * i + 1;
|
|
|
|
else
|
2016-07-23 02:49:43 +08:00
|
|
|
Index = ExtVectorType::getAccessorIdx(Comp[i], isNumericAccessor);
|
2007-08-03 07:36:59 +08:00
|
|
|
|
2008-05-14 05:03:02 +08:00
|
|
|
Elts.push_back(Index);
|
2007-08-03 07:36:59 +08:00
|
|
|
}
|
2008-05-09 14:41:27 +08:00
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
ShuffleVectorExpr::ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args,
|
2010-12-15 09:34:56 +08:00
|
|
|
QualType Type, SourceLocation BLoc,
|
2018-07-31 03:24:48 +08:00
|
|
|
SourceLocation RP)
|
2017-11-18 02:09:48 +08:00
|
|
|
: Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary,
|
|
|
|
Type->isDependentType(), Type->isDependentType(),
|
|
|
|
Type->isInstantiationDependentType(),
|
|
|
|
Type->containsUnexpandedParameterPack()),
|
|
|
|
BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(args.size())
|
|
|
|
{
|
2012-08-24 19:54:20 +08:00
|
|
|
SubExprs = new (C) Stmt*[args.size()];
|
|
|
|
for (unsigned i = 0; i != args.size(); i++) {
|
2010-12-15 09:34:56 +08:00
|
|
|
if (args[i]->isTypeDependent())
|
|
|
|
ExprBits.TypeDependent = true;
|
|
|
|
if (args[i]->isValueDependent())
|
|
|
|
ExprBits.ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
if (args[i]->isInstantiationDependent())
|
|
|
|
ExprBits.InstantiationDependent = true;
|
2010-12-15 09:34:56 +08:00
|
|
|
if (args[i]->containsUnexpandedParameterPack())
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
|
|
|
|
|
|
|
SubExprs[i] = args[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs) {
|
2009-08-12 10:28:50 +08:00
|
|
|
if (SubExprs) C.Deallocate(SubExprs);
|
|
|
|
|
2013-05-10 08:43:44 +08:00
|
|
|
this->NumExprs = Exprs.size();
|
2013-05-11 01:30:13 +08:00
|
|
|
SubExprs = new (C) Stmt*[NumExprs];
|
2013-05-10 08:43:44 +08:00
|
|
|
memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size());
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-08-12 10:28:50 +08:00
|
|
|
|
2019-01-26 21:58:15 +08:00
|
|
|
GenericSelectionExpr::GenericSelectionExpr(
|
2019-01-26 22:15:10 +08:00
|
|
|
const ASTContext &, SourceLocation GenericLoc, Expr *ControllingExpr,
|
2019-01-26 21:58:15 +08:00
|
|
|
ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs,
|
|
|
|
SourceLocation DefaultLoc, SourceLocation RParenLoc,
|
|
|
|
bool ContainsUnexpandedParameterPack, unsigned ResultIndex)
|
|
|
|
: Expr(GenericSelectionExprClass, AssocExprs[ResultIndex]->getType(),
|
|
|
|
AssocExprs[ResultIndex]->getValueKind(),
|
|
|
|
AssocExprs[ResultIndex]->getObjectKind(),
|
|
|
|
AssocExprs[ResultIndex]->isTypeDependent(),
|
|
|
|
AssocExprs[ResultIndex]->isValueDependent(),
|
|
|
|
AssocExprs[ResultIndex]->isInstantiationDependent(),
|
|
|
|
ContainsUnexpandedParameterPack),
|
|
|
|
NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex),
|
2019-01-26 22:15:10 +08:00
|
|
|
DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
|
2019-01-26 21:58:15 +08:00
|
|
|
assert(AssocTypes.size() == AssocExprs.size() &&
|
|
|
|
"Must have the same number of association expressions"
|
|
|
|
" and TypeSourceInfo!");
|
|
|
|
assert(ResultIndex < NumAssocs && "ResultIndex is out-of-bounds!");
|
|
|
|
|
2019-01-26 22:15:10 +08:00
|
|
|
GenericSelectionExprBits.GenericLoc = GenericLoc;
|
|
|
|
getTrailingObjects<Stmt *>()[ControllingIndex] = ControllingExpr;
|
2019-01-26 21:58:15 +08:00
|
|
|
std::copy(AssocExprs.begin(), AssocExprs.end(),
|
2019-01-26 22:15:10 +08:00
|
|
|
getTrailingObjects<Stmt *>() + AssocExprStartIndex);
|
|
|
|
std::copy(AssocTypes.begin(), AssocTypes.end(),
|
|
|
|
getTrailingObjects<TypeSourceInfo *>());
|
2019-01-26 21:58:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
GenericSelectionExpr::GenericSelectionExpr(
|
|
|
|
const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr,
|
|
|
|
ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs,
|
|
|
|
SourceLocation DefaultLoc, SourceLocation RParenLoc,
|
|
|
|
bool ContainsUnexpandedParameterPack)
|
|
|
|
: Expr(GenericSelectionExprClass, Context.DependentTy, VK_RValue,
|
|
|
|
OK_Ordinary,
|
|
|
|
/*isTypeDependent=*/true,
|
|
|
|
/*isValueDependent=*/true,
|
|
|
|
/*isInstantiationDependent=*/true, ContainsUnexpandedParameterPack),
|
|
|
|
NumAssocs(AssocExprs.size()), ResultIndex(ResultDependentIndex),
|
2019-01-26 22:15:10 +08:00
|
|
|
DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
|
2019-01-26 21:58:15 +08:00
|
|
|
assert(AssocTypes.size() == AssocExprs.size() &&
|
|
|
|
"Must have the same number of association expressions"
|
|
|
|
" and TypeSourceInfo!");
|
|
|
|
|
2019-01-26 22:15:10 +08:00
|
|
|
GenericSelectionExprBits.GenericLoc = GenericLoc;
|
|
|
|
getTrailingObjects<Stmt *>()[ControllingIndex] = ControllingExpr;
|
2019-01-26 21:58:15 +08:00
|
|
|
std::copy(AssocExprs.begin(), AssocExprs.end(),
|
2019-01-26 22:15:10 +08:00
|
|
|
getTrailingObjects<Stmt *>() + AssocExprStartIndex);
|
|
|
|
std::copy(AssocTypes.begin(), AssocTypes.end(),
|
|
|
|
getTrailingObjects<TypeSourceInfo *>());
|
|
|
|
}
|
|
|
|
|
|
|
|
GenericSelectionExpr::GenericSelectionExpr(EmptyShell Empty, unsigned NumAssocs)
|
|
|
|
: Expr(GenericSelectionExprClass, Empty), NumAssocs(NumAssocs) {}
|
|
|
|
|
|
|
|
GenericSelectionExpr *GenericSelectionExpr::Create(
|
|
|
|
const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr,
|
|
|
|
ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs,
|
|
|
|
SourceLocation DefaultLoc, SourceLocation RParenLoc,
|
|
|
|
bool ContainsUnexpandedParameterPack, unsigned ResultIndex) {
|
|
|
|
unsigned NumAssocs = AssocExprs.size();
|
|
|
|
void *Mem = Context.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs),
|
|
|
|
alignof(GenericSelectionExpr));
|
|
|
|
return new (Mem) GenericSelectionExpr(
|
|
|
|
Context, GenericLoc, ControllingExpr, AssocTypes, AssocExprs, DefaultLoc,
|
|
|
|
RParenLoc, ContainsUnexpandedParameterPack, ResultIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
GenericSelectionExpr *GenericSelectionExpr::Create(
|
|
|
|
const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr,
|
|
|
|
ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs,
|
|
|
|
SourceLocation DefaultLoc, SourceLocation RParenLoc,
|
|
|
|
bool ContainsUnexpandedParameterPack) {
|
|
|
|
unsigned NumAssocs = AssocExprs.size();
|
|
|
|
void *Mem = Context.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs),
|
|
|
|
alignof(GenericSelectionExpr));
|
|
|
|
return new (Mem) GenericSelectionExpr(
|
|
|
|
Context, GenericLoc, ControllingExpr, AssocTypes, AssocExprs, DefaultLoc,
|
|
|
|
RParenLoc, ContainsUnexpandedParameterPack);
|
|
|
|
}
|
|
|
|
|
|
|
|
GenericSelectionExpr *
|
|
|
|
GenericSelectionExpr::CreateEmpty(const ASTContext &Context,
|
|
|
|
unsigned NumAssocs) {
|
|
|
|
void *Mem = Context.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs),
|
|
|
|
alignof(GenericSelectionExpr));
|
|
|
|
return new (Mem) GenericSelectionExpr(EmptyShell(), NumAssocs);
|
2011-04-15 08:35:48 +08:00
|
|
|
}
|
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DesignatedInitExpr
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-06-16 14:47:06 +08:00
|
|
|
IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() const {
|
2009-01-22 08:58:24 +08:00
|
|
|
assert(Kind == FieldDesignator && "Only valid on a field designator");
|
|
|
|
if (Field.NameOrField & 0x01)
|
|
|
|
return reinterpret_cast<IdentifierInfo *>(Field.NameOrField&~0x01);
|
|
|
|
else
|
|
|
|
return getField()->getIdentifier();
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty,
|
2016-06-23 08:15:04 +08:00
|
|
|
llvm::ArrayRef<Designator> Designators,
|
2009-09-09 23:08:12 +08:00
|
|
|
SourceLocation EqualOrColonLoc,
|
2009-04-15 14:41:24 +08:00
|
|
|
bool GNUSyntax,
|
2012-08-24 19:54:20 +08:00
|
|
|
ArrayRef<Expr*> IndexExprs,
|
2009-05-22 07:17:49 +08:00
|
|
|
Expr *Init)
|
2009-09-09 23:08:12 +08:00
|
|
|
: Expr(DesignatedInitExprClass, Ty,
|
2010-11-18 14:31:45 +08:00
|
|
|
Init->getValueKind(), Init->getObjectKind(),
|
2010-12-15 09:34:56 +08:00
|
|
|
Init->isTypeDependent(), Init->isValueDependent(),
|
2011-07-01 09:22:09 +08:00
|
|
|
Init->isInstantiationDependent(),
|
2010-12-15 09:34:56 +08:00
|
|
|
Init->containsUnexpandedParameterPack()),
|
2009-09-09 23:08:12 +08:00
|
|
|
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
|
2016-06-23 08:15:04 +08:00
|
|
|
NumDesignators(Designators.size()), NumSubExprs(IndexExprs.size() + 1) {
|
2010-01-07 07:17:19 +08:00
|
|
|
this->Designators = new (C) Designator[NumDesignators];
|
2009-05-22 07:17:49 +08:00
|
|
|
|
|
|
|
// Record the initializer itself.
|
2015-07-19 01:09:36 +08:00
|
|
|
child_iterator Child = child_begin();
|
2009-05-22 07:17:49 +08:00
|
|
|
*Child++ = Init;
|
|
|
|
|
|
|
|
// Copy the designators and their subexpressions, computing
|
|
|
|
// value-dependence along the way.
|
|
|
|
unsigned IndexIdx = 0;
|
|
|
|
for (unsigned I = 0; I != NumDesignators; ++I) {
|
2009-04-15 14:41:24 +08:00
|
|
|
this->Designators[I] = Designators[I];
|
2009-05-22 07:17:49 +08:00
|
|
|
|
|
|
|
if (this->Designators[I].isArrayDesignator()) {
|
|
|
|
// Compute type- and value-dependence.
|
|
|
|
Expr *Index = IndexExprs[IndexIdx];
|
2010-12-15 09:34:56 +08:00
|
|
|
if (Index->isTypeDependent() || Index->isValueDependent())
|
2015-01-09 09:39:09 +08:00
|
|
|
ExprBits.TypeDependent = ExprBits.ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
if (Index->isInstantiationDependent())
|
|
|
|
ExprBits.InstantiationDependent = true;
|
2010-12-15 09:34:56 +08:00
|
|
|
// Propagate unexpanded parameter packs.
|
|
|
|
if (Index->containsUnexpandedParameterPack())
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
2009-05-22 07:17:49 +08:00
|
|
|
|
|
|
|
// Copy the index expressions into permanent storage.
|
|
|
|
*Child++ = IndexExprs[IndexIdx++];
|
|
|
|
} else if (this->Designators[I].isArrayRangeDesignator()) {
|
|
|
|
// Compute type- and value-dependence.
|
|
|
|
Expr *Start = IndexExprs[IndexIdx];
|
|
|
|
Expr *End = IndexExprs[IndexIdx + 1];
|
2010-12-15 09:34:56 +08:00
|
|
|
if (Start->isTypeDependent() || Start->isValueDependent() ||
|
2011-07-01 09:22:09 +08:00
|
|
|
End->isTypeDependent() || End->isValueDependent()) {
|
2015-01-09 09:39:09 +08:00
|
|
|
ExprBits.TypeDependent = ExprBits.ValueDependent = true;
|
2011-07-01 09:22:09 +08:00
|
|
|
ExprBits.InstantiationDependent = true;
|
2018-07-31 03:24:48 +08:00
|
|
|
} else if (Start->isInstantiationDependent() ||
|
2011-07-01 09:22:09 +08:00
|
|
|
End->isInstantiationDependent()) {
|
|
|
|
ExprBits.InstantiationDependent = true;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-12-15 09:34:56 +08:00
|
|
|
// Propagate unexpanded parameter packs.
|
|
|
|
if (Start->containsUnexpandedParameterPack() ||
|
|
|
|
End->containsUnexpandedParameterPack())
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
2009-05-22 07:17:49 +08:00
|
|
|
|
|
|
|
// Copy the start/end expressions into permanent storage.
|
|
|
|
*Child++ = IndexExprs[IndexIdx++];
|
|
|
|
*Child++ = IndexExprs[IndexIdx++];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-24 19:54:20 +08:00
|
|
|
assert(IndexIdx == IndexExprs.size() && "Wrong number of index expressions");
|
2009-04-15 14:41:24 +08:00
|
|
|
}
|
|
|
|
|
2009-01-22 08:58:24 +08:00
|
|
|
DesignatedInitExpr *
|
2016-06-23 08:15:04 +08:00
|
|
|
DesignatedInitExpr::Create(const ASTContext &C,
|
|
|
|
llvm::ArrayRef<Designator> Designators,
|
2012-08-24 19:54:20 +08:00
|
|
|
ArrayRef<Expr*> IndexExprs,
|
2009-01-22 08:58:24 +08:00
|
|
|
SourceLocation ColonOrEqualLoc,
|
|
|
|
bool UsesColonSyntax, Expr *Init) {
|
2015-12-31 12:18:25 +08:00
|
|
|
void *Mem = C.Allocate(totalSizeToAlloc<Stmt *>(IndexExprs.size() + 1),
|
2016-10-20 22:27:22 +08:00
|
|
|
alignof(DesignatedInitExpr));
|
2016-06-23 08:15:04 +08:00
|
|
|
return new (Mem) DesignatedInitExpr(C, C.VoidTy, Designators,
|
2009-05-22 07:17:49 +08:00
|
|
|
ColonOrEqualLoc, UsesColonSyntax,
|
2012-08-24 19:54:20 +08:00
|
|
|
IndexExprs, Init);
|
2009-01-22 08:58:24 +08:00
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(const ASTContext &C,
|
2009-04-16 08:55:48 +08:00
|
|
|
unsigned NumIndexExprs) {
|
2015-12-31 12:18:25 +08:00
|
|
|
void *Mem = C.Allocate(totalSizeToAlloc<Stmt *>(NumIndexExprs + 1),
|
2016-10-20 22:27:22 +08:00
|
|
|
alignof(DesignatedInitExpr));
|
2009-04-16 08:55:48 +08:00
|
|
|
return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
void DesignatedInitExpr::setDesignators(const ASTContext &C,
|
2010-01-07 07:17:19 +08:00
|
|
|
const Designator *Desigs,
|
2009-04-16 08:55:48 +08:00
|
|
|
unsigned NumDesigs) {
|
2010-01-07 07:17:19 +08:00
|
|
|
Designators = new (C) Designator[NumDesigs];
|
2009-04-16 08:55:48 +08:00
|
|
|
NumDesignators = NumDesigs;
|
|
|
|
for (unsigned I = 0; I != NumDesigs; ++I)
|
|
|
|
Designators[I] = Desigs[I];
|
|
|
|
}
|
|
|
|
|
2011-03-16 23:08:46 +08:00
|
|
|
SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const {
|
|
|
|
DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this);
|
|
|
|
if (size() == 1)
|
|
|
|
return DIE->getDesignator(0)->getSourceRange();
|
2018-08-10 05:08:08 +08:00
|
|
|
return SourceRange(DIE->getDesignator(0)->getBeginLoc(),
|
2018-08-10 05:09:38 +08:00
|
|
|
DIE->getDesignator(size() - 1)->getEndLoc());
|
2011-03-16 23:08:46 +08:00
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:03 +08:00
|
|
|
SourceLocation DesignatedInitExpr::getBeginLoc() const {
|
2009-01-22 08:58:24 +08:00
|
|
|
SourceLocation StartLoc;
|
2016-06-23 08:15:04 +08:00
|
|
|
auto *DIE = const_cast<DesignatedInitExpr *>(this);
|
|
|
|
Designator &First = *DIE->getDesignator(0);
|
2009-01-22 08:58:24 +08:00
|
|
|
if (First.isFieldDesignator()) {
|
2009-03-28 08:41:23 +08:00
|
|
|
if (GNUSyntax)
|
2009-01-22 08:58:24 +08:00
|
|
|
StartLoc = SourceLocation::getFromRawEncoding(First.Field.FieldLoc);
|
|
|
|
else
|
|
|
|
StartLoc = SourceLocation::getFromRawEncoding(First.Field.DotLoc);
|
|
|
|
} else
|
2009-02-17 06:33:34 +08:00
|
|
|
StartLoc =
|
|
|
|
SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc);
|
2012-12-25 22:51:39 +08:00
|
|
|
return StartLoc;
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:47 +08:00
|
|
|
SourceLocation DesignatedInitExpr::getEndLoc() const {
|
2018-08-10 05:09:38 +08:00
|
|
|
return getInit()->getEndLoc();
|
2009-01-22 08:58:24 +08:00
|
|
|
}
|
|
|
|
|
2013-01-26 23:15:52 +08:00
|
|
|
Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) const {
|
2009-01-22 08:58:24 +08:00
|
|
|
assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
|
2015-12-31 12:18:25 +08:00
|
|
|
return getSubExpr(D.ArrayOrRange.Index + 1);
|
2009-01-22 08:58:24 +08:00
|
|
|
}
|
|
|
|
|
2013-01-26 23:15:52 +08:00
|
|
|
Expr *DesignatedInitExpr::getArrayRangeStart(const Designator &D) const {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(D.Kind == Designator::ArrayRangeDesignator &&
|
2009-01-22 08:58:24 +08:00
|
|
|
"Requires array range designator");
|
2015-12-31 12:18:25 +08:00
|
|
|
return getSubExpr(D.ArrayOrRange.Index + 1);
|
2009-01-22 08:58:24 +08:00
|
|
|
}
|
|
|
|
|
2013-01-26 23:15:52 +08:00
|
|
|
Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(D.Kind == Designator::ArrayRangeDesignator &&
|
2009-01-22 08:58:24 +08:00
|
|
|
"Requires array range designator");
|
2015-12-31 12:18:25 +08:00
|
|
|
return getSubExpr(D.ArrayOrRange.Index + 2);
|
2009-01-22 08:58:24 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Replaces the designator at index @p Idx with the series
|
2009-04-15 14:41:24 +08:00
|
|
|
/// of designators in [First, Last).
|
2013-08-18 18:09:15 +08:00
|
|
|
void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx,
|
2009-09-09 23:08:12 +08:00
|
|
|
const Designator *First,
|
2009-04-15 14:41:24 +08:00
|
|
|
const Designator *Last) {
|
|
|
|
unsigned NumNewDesignators = Last - First;
|
|
|
|
if (NumNewDesignators == 0) {
|
|
|
|
std::copy_backward(Designators + Idx + 1,
|
|
|
|
Designators + NumDesignators,
|
|
|
|
Designators + Idx);
|
|
|
|
--NumNewDesignators;
|
|
|
|
return;
|
|
|
|
} else if (NumNewDesignators == 1) {
|
|
|
|
Designators[Idx] = *First;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
Designator *NewDesignators
|
2010-01-07 07:17:19 +08:00
|
|
|
= new (C) Designator[NumDesignators - 1 + NumNewDesignators];
|
2009-04-15 14:41:24 +08:00
|
|
|
std::copy(Designators, Designators + Idx, NewDesignators);
|
|
|
|
std::copy(First, Last, NewDesignators + Idx);
|
|
|
|
std::copy(Designators + Idx + 1, Designators + NumDesignators,
|
|
|
|
NewDesignators + Idx + NumNewDesignators);
|
|
|
|
Designators = NewDesignators;
|
|
|
|
NumDesignators = NumDesignators - 1 + NumNewDesignators;
|
|
|
|
}
|
|
|
|
|
2015-06-10 08:27:52 +08:00
|
|
|
DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C,
|
|
|
|
SourceLocation lBraceLoc, Expr *baseExpr, SourceLocation rBraceLoc)
|
|
|
|
: Expr(DesignatedInitUpdateExprClass, baseExpr->getType(), VK_RValue,
|
|
|
|
OK_Ordinary, false, false, false, false) {
|
|
|
|
BaseAndUpdaterExprs[0] = baseExpr;
|
|
|
|
|
|
|
|
InitListExpr *ILE = new (C) InitListExpr(C, lBraceLoc, None, rBraceLoc);
|
|
|
|
ILE->setType(baseExpr->getType());
|
|
|
|
BaseAndUpdaterExprs[1] = ILE;
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:03 +08:00
|
|
|
SourceLocation DesignatedInitUpdateExpr::getBeginLoc() const {
|
2018-08-10 05:08:08 +08:00
|
|
|
return getBase()->getBeginLoc();
|
2015-06-10 08:27:52 +08:00
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:47 +08:00
|
|
|
SourceLocation DesignatedInitUpdateExpr::getEndLoc() const {
|
2018-08-10 05:09:38 +08:00
|
|
|
return getBase()->getEndLoc();
|
2015-06-10 08:27:52 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 00:20:40 +08:00
|
|
|
ParenListExpr::ParenListExpr(SourceLocation LParenLoc, ArrayRef<Expr *> Exprs,
|
|
|
|
SourceLocation RParenLoc)
|
|
|
|
: Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
|
|
|
|
false, false),
|
|
|
|
LParenLoc(LParenLoc), RParenLoc(RParenLoc) {
|
|
|
|
ParenListExprBits.NumExprs = Exprs.size();
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = Exprs.size(); I != N; ++I) {
|
|
|
|
if (Exprs[I]->isTypeDependent())
|
2010-12-15 09:34:56 +08:00
|
|
|
ExprBits.TypeDependent = true;
|
2018-11-21 00:20:40 +08:00
|
|
|
if (Exprs[I]->isValueDependent())
|
2010-12-15 09:34:56 +08:00
|
|
|
ExprBits.ValueDependent = true;
|
2018-11-21 00:20:40 +08:00
|
|
|
if (Exprs[I]->isInstantiationDependent())
|
2011-07-01 09:22:09 +08:00
|
|
|
ExprBits.InstantiationDependent = true;
|
2018-11-21 00:20:40 +08:00
|
|
|
if (Exprs[I]->containsUnexpandedParameterPack())
|
2010-12-15 09:34:56 +08:00
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
|
|
|
|
2018-11-21 00:20:40 +08:00
|
|
|
getTrailingObjects<Stmt *>()[I] = Exprs[I];
|
2010-12-15 09:34:56 +08:00
|
|
|
}
|
2009-08-11 07:49:36 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 00:20:40 +08:00
|
|
|
ParenListExpr::ParenListExpr(EmptyShell Empty, unsigned NumExprs)
|
|
|
|
: Expr(ParenListExprClass, Empty) {
|
|
|
|
ParenListExprBits.NumExprs = NumExprs;
|
|
|
|
}
|
|
|
|
|
|
|
|
ParenListExpr *ParenListExpr::Create(const ASTContext &Ctx,
|
|
|
|
SourceLocation LParenLoc,
|
|
|
|
ArrayRef<Expr *> Exprs,
|
|
|
|
SourceLocation RParenLoc) {
|
|
|
|
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(Exprs.size()),
|
|
|
|
alignof(ParenListExpr));
|
|
|
|
return new (Mem) ParenListExpr(LParenLoc, Exprs, RParenLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx,
|
|
|
|
unsigned NumExprs) {
|
|
|
|
void *Mem =
|
|
|
|
Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumExprs), alignof(ParenListExpr));
|
|
|
|
return new (Mem) ParenListExpr(EmptyShell(), NumExprs);
|
|
|
|
}
|
|
|
|
|
2011-02-16 16:02:54 +08:00
|
|
|
const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
|
|
|
|
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
|
|
|
|
e = ewc->getSubExpr();
|
2011-06-22 01:03:29 +08:00
|
|
|
if (const MaterializeTemporaryExpr *m = dyn_cast<MaterializeTemporaryExpr>(e))
|
2019-11-17 18:41:55 +08:00
|
|
|
e = m->getSubExpr();
|
2011-02-16 16:02:54 +08:00
|
|
|
e = cast<CXXConstructExpr>(e)->getArg(0);
|
|
|
|
while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
|
|
|
|
e = ice->getSubExpr();
|
|
|
|
return cast<OpaqueValueExpr>(e);
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &Context,
|
|
|
|
EmptyShell sh,
|
2011-11-06 17:01:30 +08:00
|
|
|
unsigned numSemanticExprs) {
|
2015-12-31 12:18:25 +08:00
|
|
|
void *buffer =
|
|
|
|
Context.Allocate(totalSizeToAlloc<Expr *>(1 + numSemanticExprs),
|
2016-10-20 22:27:22 +08:00
|
|
|
alignof(PseudoObjectExpr));
|
2011-11-06 17:01:30 +08:00
|
|
|
return new(buffer) PseudoObjectExpr(sh, numSemanticExprs);
|
|
|
|
}
|
|
|
|
|
|
|
|
PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
|
|
|
|
: Expr(PseudoObjectExprClass, shell) {
|
|
|
|
PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &C, Expr *syntax,
|
2011-11-06 17:01:30 +08:00
|
|
|
ArrayRef<Expr*> semantics,
|
|
|
|
unsigned resultIndex) {
|
|
|
|
assert(syntax && "no syntactic expression!");
|
2017-11-18 02:09:48 +08:00
|
|
|
assert(semantics.size() && "no semantic expressions!");
|
2011-11-06 17:01:30 +08:00
|
|
|
|
|
|
|
QualType type;
|
|
|
|
ExprValueKind VK;
|
|
|
|
if (resultIndex == NoResult) {
|
|
|
|
type = C.VoidTy;
|
|
|
|
VK = VK_RValue;
|
|
|
|
} else {
|
|
|
|
assert(resultIndex < semantics.size());
|
|
|
|
type = semantics[resultIndex]->getType();
|
|
|
|
VK = semantics[resultIndex]->getValueKind();
|
|
|
|
assert(semantics[resultIndex]->getObjectKind() == OK_Ordinary);
|
|
|
|
}
|
|
|
|
|
2015-12-31 12:18:25 +08:00
|
|
|
void *buffer = C.Allocate(totalSizeToAlloc<Expr *>(semantics.size() + 1),
|
2016-10-20 22:27:22 +08:00
|
|
|
alignof(PseudoObjectExpr));
|
2011-11-06 17:01:30 +08:00
|
|
|
return new(buffer) PseudoObjectExpr(type, VK, syntax, semantics,
|
|
|
|
resultIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
PseudoObjectExpr::PseudoObjectExpr(QualType type, ExprValueKind VK,
|
|
|
|
Expr *syntax, ArrayRef<Expr*> semantics,
|
|
|
|
unsigned resultIndex)
|
|
|
|
: Expr(PseudoObjectExprClass, type, VK, OK_Ordinary,
|
|
|
|
/*filled in at end of ctor*/ false, false, false, false) {
|
|
|
|
PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
|
|
|
|
PseudoObjectExprBits.ResultIndex = resultIndex + 1;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
|
|
|
|
Expr *E = (i == 0 ? syntax : semantics[i-1]);
|
|
|
|
getSubExprsBuffer()[i] = E;
|
|
|
|
|
|
|
|
if (E->isTypeDependent())
|
|
|
|
ExprBits.TypeDependent = true;
|
|
|
|
if (E->isValueDependent())
|
|
|
|
ExprBits.ValueDependent = true;
|
|
|
|
if (E->isInstantiationDependent())
|
|
|
|
ExprBits.InstantiationDependent = true;
|
|
|
|
if (E->containsUnexpandedParameterPack())
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
|
|
|
|
|
|
|
if (isa<OpaqueValueExpr>(E))
|
2014-05-12 13:36:57 +08:00
|
|
|
assert(cast<OpaqueValueExpr>(E)->getSourceExpr() != nullptr &&
|
2011-11-06 17:01:30 +08:00
|
|
|
"opaque-value semantic expressions for pseudo-object "
|
|
|
|
"operations must have sources");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-25 02:13:47 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Child Iterators for iterating over subexpressions/substatements
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-03-12 03:24:49 +08:00
|
|
|
// UnaryExprOrTypeTraitExpr
|
|
|
|
Stmt::child_range UnaryExprOrTypeTraitExpr::children() {
|
2017-04-12 04:21:30 +08:00
|
|
|
const_child_range CCR =
|
|
|
|
const_cast<const UnaryExprOrTypeTraitExpr *>(this)->children();
|
|
|
|
return child_range(cast_away_const(CCR.begin()), cast_away_const(CCR.end()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt::const_child_range UnaryExprOrTypeTraitExpr::children() const {
|
2008-11-12 01:56:53 +08:00
|
|
|
// If this is of a type and the type is a VLA type (and not a typedef), the
|
|
|
|
// size expression of the VLA needs to be treated as an executable expression.
|
|
|
|
// Why isn't this weirdness documented better in StmtIterator?
|
|
|
|
if (isArgumentType()) {
|
2017-04-12 04:21:30 +08:00
|
|
|
if (const VariableArrayType *T =
|
|
|
|
dyn_cast<VariableArrayType>(getArgumentType().getTypePtr()))
|
|
|
|
return const_child_range(const_child_iterator(T), const_child_iterator());
|
|
|
|
return const_child_range(const_child_iterator(), const_child_iterator());
|
2008-11-12 01:56:53 +08:00
|
|
|
}
|
2017-04-12 04:21:30 +08:00
|
|
|
return const_child_range(&Argument.Ex, &Argument.Ex + 1);
|
2007-10-19 07:28:49 +08:00
|
|
|
}
|
2007-10-18 00:58:11 +08:00
|
|
|
|
2012-08-24 19:54:20 +08:00
|
|
|
AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args,
|
2011-10-15 06:48:56 +08:00
|
|
|
QualType t, AtomicOp op, SourceLocation RP)
|
2017-11-18 02:09:48 +08:00
|
|
|
: Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary,
|
|
|
|
false, false, false, false),
|
|
|
|
NumSubExprs(args.size()), BuiltinLoc(BLoc), RParenLoc(RP), Op(op)
|
|
|
|
{
|
2012-08-24 19:54:20 +08:00
|
|
|
assert(args.size() == getNumSubExprs(op) && "wrong number of subexpressions");
|
|
|
|
for (unsigned i = 0; i != args.size(); i++) {
|
2011-10-15 06:48:56 +08:00
|
|
|
if (args[i]->isTypeDependent())
|
|
|
|
ExprBits.TypeDependent = true;
|
|
|
|
if (args[i]->isValueDependent())
|
|
|
|
ExprBits.ValueDependent = true;
|
|
|
|
if (args[i]->isInstantiationDependent())
|
|
|
|
ExprBits.InstantiationDependent = true;
|
|
|
|
if (args[i]->containsUnexpandedParameterPack())
|
|
|
|
ExprBits.ContainsUnexpandedParameterPack = true;
|
|
|
|
|
|
|
|
SubExprs[i] = args[i];
|
|
|
|
}
|
|
|
|
}
|
2012-04-11 06:49:28 +08:00
|
|
|
|
|
|
|
unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
|
|
|
|
switch (Op) {
|
2012-04-12 13:08:17 +08:00
|
|
|
case AO__c11_atomic_init:
|
2017-08-05 02:16:31 +08:00
|
|
|
case AO__opencl_atomic_init:
|
2012-04-12 13:08:17 +08:00
|
|
|
case AO__c11_atomic_load:
|
|
|
|
case AO__atomic_load_n:
|
2017-08-16 00:02:49 +08:00
|
|
|
return 2;
|
2012-04-12 13:08:17 +08:00
|
|
|
|
2017-08-16 00:02:49 +08:00
|
|
|
case AO__opencl_atomic_load:
|
2012-04-12 13:08:17 +08:00
|
|
|
case AO__c11_atomic_store:
|
|
|
|
case AO__c11_atomic_exchange:
|
|
|
|
case AO__atomic_load:
|
|
|
|
case AO__atomic_store:
|
|
|
|
case AO__atomic_store_n:
|
|
|
|
case AO__atomic_exchange_n:
|
|
|
|
case AO__c11_atomic_fetch_add:
|
|
|
|
case AO__c11_atomic_fetch_sub:
|
|
|
|
case AO__c11_atomic_fetch_and:
|
|
|
|
case AO__c11_atomic_fetch_or:
|
|
|
|
case AO__c11_atomic_fetch_xor:
|
2019-11-21 18:31:30 +08:00
|
|
|
case AO__c11_atomic_fetch_max:
|
|
|
|
case AO__c11_atomic_fetch_min:
|
2012-04-12 13:08:17 +08:00
|
|
|
case AO__atomic_fetch_add:
|
|
|
|
case AO__atomic_fetch_sub:
|
|
|
|
case AO__atomic_fetch_and:
|
|
|
|
case AO__atomic_fetch_or:
|
|
|
|
case AO__atomic_fetch_xor:
|
2012-04-13 14:31:38 +08:00
|
|
|
case AO__atomic_fetch_nand:
|
2012-04-12 13:08:17 +08:00
|
|
|
case AO__atomic_add_fetch:
|
|
|
|
case AO__atomic_sub_fetch:
|
|
|
|
case AO__atomic_and_fetch:
|
|
|
|
case AO__atomic_or_fetch:
|
|
|
|
case AO__atomic_xor_fetch:
|
2012-04-13 14:31:38 +08:00
|
|
|
case AO__atomic_nand_fetch:
|
2019-11-21 18:31:30 +08:00
|
|
|
case AO__atomic_min_fetch:
|
|
|
|
case AO__atomic_max_fetch:
|
2018-05-13 15:45:58 +08:00
|
|
|
case AO__atomic_fetch_min:
|
|
|
|
case AO__atomic_fetch_max:
|
2017-08-16 00:02:49 +08:00
|
|
|
return 3;
|
2012-04-12 13:08:17 +08:00
|
|
|
|
2017-08-16 00:02:49 +08:00
|
|
|
case AO__opencl_atomic_store:
|
|
|
|
case AO__opencl_atomic_exchange:
|
|
|
|
case AO__opencl_atomic_fetch_add:
|
|
|
|
case AO__opencl_atomic_fetch_sub:
|
|
|
|
case AO__opencl_atomic_fetch_and:
|
|
|
|
case AO__opencl_atomic_fetch_or:
|
|
|
|
case AO__opencl_atomic_fetch_xor:
|
|
|
|
case AO__opencl_atomic_fetch_min:
|
|
|
|
case AO__opencl_atomic_fetch_max:
|
2012-04-12 13:08:17 +08:00
|
|
|
case AO__atomic_exchange:
|
2017-08-16 00:02:49 +08:00
|
|
|
return 4;
|
2012-04-12 13:08:17 +08:00
|
|
|
|
|
|
|
case AO__c11_atomic_compare_exchange_strong:
|
|
|
|
case AO__c11_atomic_compare_exchange_weak:
|
2017-08-16 00:02:49 +08:00
|
|
|
return 5;
|
|
|
|
|
2017-08-05 02:16:31 +08:00
|
|
|
case AO__opencl_atomic_compare_exchange_strong:
|
|
|
|
case AO__opencl_atomic_compare_exchange_weak:
|
2012-04-12 13:08:17 +08:00
|
|
|
case AO__atomic_compare_exchange:
|
|
|
|
case AO__atomic_compare_exchange_n:
|
2017-08-16 00:02:49 +08:00
|
|
|
return 6;
|
2012-04-11 06:49:28 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("unknown atomic op");
|
|
|
|
}
|
2015-09-30 17:22:36 +08:00
|
|
|
|
2017-08-05 02:16:31 +08:00
|
|
|
QualType AtomicExpr::getValueType() const {
|
|
|
|
auto T = getPtr()->getType()->castAs<PointerType>()->getPointeeType();
|
|
|
|
if (auto AT = T->getAs<AtomicType>())
|
|
|
|
return AT->getValueType();
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
2016-02-04 19:27:03 +08:00
|
|
|
QualType OMPArraySectionExpr::getBaseOriginalType(const Expr *Base) {
|
2015-09-30 17:22:36 +08:00
|
|
|
unsigned ArraySectionCount = 0;
|
|
|
|
while (auto *OASE = dyn_cast<OMPArraySectionExpr>(Base->IgnoreParens())) {
|
|
|
|
Base = OASE->getBase();
|
|
|
|
++ArraySectionCount;
|
|
|
|
}
|
2016-02-04 19:27:03 +08:00
|
|
|
while (auto *ASE =
|
|
|
|
dyn_cast<ArraySubscriptExpr>(Base->IgnoreParenImpCasts())) {
|
2015-10-08 17:10:53 +08:00
|
|
|
Base = ASE->getBase();
|
|
|
|
++ArraySectionCount;
|
|
|
|
}
|
2016-02-04 19:27:03 +08:00
|
|
|
Base = Base->IgnoreParenImpCasts();
|
2015-09-30 17:22:36 +08:00
|
|
|
auto OriginalTy = Base->getType();
|
|
|
|
if (auto *DRE = dyn_cast<DeclRefExpr>(Base))
|
|
|
|
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
|
|
|
|
OriginalTy = PVD->getOriginalType().getNonReferenceType();
|
|
|
|
|
|
|
|
for (unsigned Cnt = 0; Cnt < ArraySectionCount; ++Cnt) {
|
|
|
|
if (OriginalTy->isAnyPointerType())
|
|
|
|
OriginalTy = OriginalTy->getPointeeType();
|
|
|
|
else {
|
2017-11-18 02:09:48 +08:00
|
|
|
assert (OriginalTy->isArrayType());
|
2015-09-30 17:22:36 +08:00
|
|
|
OriginalTy = OriginalTy->castAsArrayTypeUnsafe()->getElementType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return OriginalTy;
|
|
|
|
}
|