blob: 69924572c3d770c282fcb54742b2f9e5bce35fb8 [file]
//===--- ExprUtils.cpp - Shared expression emission queries ---------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "clang/CodeGenUtils/ExprUtils.h"
#include "clang/AST/Attr.h"
#include "clang/AST/ExprCXX.h"
namespace clang::CodeGenUtils {
QualType getFixedSizeElementType(const ASTContext &Ctx,
const VariableArrayType *VLA) {
QualType EltType;
do {
EltType = VLA->getElementType();
} while ((VLA = Ctx.getAsVariableArrayType(EltType)));
return EltType;
}
bool isBlockVarRef(const Expr *E) {
// Make sure we look through parens.
E = E->IgnoreParens();
// Check for a direct reference to a __block variable.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
const VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl());
return (Var && Var->hasAttr<BlocksAttr>());
}
// More complicated stuff.
// Binary operators.
if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
// For an assignment or pointer-to-member operation, just care
// about the LHS.
if (Op->isAssignmentOp() || Op->isPtrMemOp())
return isBlockVarRef(Op->getLHS());
// For a comma, just care about the RHS.
if (Op->getOpcode() == BO_Comma)
return isBlockVarRef(Op->getRHS());
// FIXME: pointer arithmetic?
return false;
// Check both sides of a conditional operator.
} else if (const AbstractConditionalOperator *Op =
dyn_cast<AbstractConditionalOperator>(E)) {
return isBlockVarRef(Op->getTrueExpr()) ||
isBlockVarRef(Op->getFalseExpr());
// OVEs are required to support BinaryConditionalOperators.
} else if (const OpaqueValueExpr *Op = dyn_cast<OpaqueValueExpr>(E)) {
if (const Expr *Src = Op->getSourceExpr())
return isBlockVarRef(Src);
// Casts are necessary to get things like (*(int*)&var) = foo().
// We don't really care about the kind of cast here, except
// we don't want to look through l2r casts, because it's okay
// to get the *value* in a __block variable.
} else if (const CastExpr *Cast = dyn_cast<CastExpr>(E)) {
if (Cast->getCastKind() == CK_LValueToRValue)
return false;
return isBlockVarRef(Cast->getSubExpr());
// Handle unary operators. Again, just aggressively look through
// it, ignoring the operation.
} else if (const UnaryOperator *UOp = dyn_cast<UnaryOperator>(E)) {
return isBlockVarRef(UOp->getSubExpr());
// Look into the base of a field access.
} else if (const MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
return isBlockVarRef(Mem->getBase());
// Look into the base of a subscript.
} else if (const ArraySubscriptExpr *Sub = dyn_cast<ArraySubscriptExpr>(E)) {
return isBlockVarRef(Sub->getBase());
}
return false;
}
bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
const ASTContext &Ctx) {
// Anything that is an integer or floating point constant is fine.
return E->IgnoreParens()->isEvaluatable(Ctx);
// Even non-volatile automatic variables can't be evaluated unconditionally.
// Referencing a thread_local may cause non-trivial initialization work to
// occur. If we're inside a lambda and one of the variables is from the scope
// outside the lambda, that function may have returned already. Reading its
// locals is a bad idea. Also, these reads may introduce races there didn't
// exist in the source-level program.
}
bool isTrivialFiller(const Expr *E) {
if (!E)
return true;
if (isa<ImplicitValueInitExpr>(E))
return true;
if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
if (ILE->getNumInits())
return false;
return isTrivialFiller(ILE->getArrayFiller());
}
if (const auto *Cons = dyn_cast_or_null<CXXConstructExpr>(E))
return Cons->getConstructor()->isDefaultConstructor() &&
Cons->getConstructor()->isTrivial();
// FIXME: Are there other cases where we can avoid emitting an initializer?
return false;
}
bool onlyHasInlineBuiltinDeclaration(const FunctionDecl *FD) {
for (const FunctionDecl *PD = FD; PD; PD = PD->getPreviousDecl())
if (!PD->isInlineBuiltinDeclaration())
return false;
return true;
}
} // namespace clang::CodeGenUtils