aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST/ByteCode
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/ByteCode')
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp18
-rw-r--r--clang/lib/AST/ByteCode/Interp.cpp80
-rw-r--r--clang/lib/AST/ByteCode/Interp.h1
-rw-r--r--clang/lib/AST/ByteCode/Opcodes.td3
4 files changed, 69 insertions, 33 deletions
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 7353cbc..20836f6 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2508,7 +2508,7 @@ bool Compiler<Emitter>::VisitAbstractConditionalOperator(
};
if (std::optional<bool> BoolValue = getBoolValue(Condition)) {
- if (BoolValue)
+ if (*BoolValue)
return visitChildExpr(TrueExpr);
return visitChildExpr(FalseExpr);
}
@@ -3235,7 +3235,8 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return this->visitInitializer(E->getArg(0));
// Zero initialization.
- if (E->requiresZeroInitialization()) {
+ bool ZeroInit = E->requiresZeroInitialization();
+ if (ZeroInit) {
const Record *R = getRecord(E->getType());
if (!this->visitZeroRecordInitializer(R, E))
@@ -3246,6 +3247,19 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return true;
}
+ // Avoid materializing a temporary for an elidable copy/move constructor.
+ if (!ZeroInit && E->isElidable()) {
+ const Expr *SrcObj = E->getArg(0);
+ assert(SrcObj->isTemporaryObject(Ctx.getASTContext(), Ctor->getParent()));
+ assert(Ctx.getASTContext().hasSameUnqualifiedType(E->getType(),
+ SrcObj->getType()));
+ if (const auto *ME = dyn_cast<MaterializeTemporaryExpr>(SrcObj)) {
+ if (!this->emitCheckFunctionDecl(Ctor, E))
+ return false;
+ return this->visitInitializer(ME->getSubExpr());
+ }
+ }
+
const Function *Func = getFunction(Ctor);
if (!Func)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index a2fb0fb..1f2ae92 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -919,33 +919,8 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return true;
}
-static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
-
- if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
- const SourceLocation &Loc = S.Current->getLocation(OpPC);
- S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
- return false;
- }
-
- if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)
- return false;
-
- if (F->isValid() && F->hasBody() && F->isConstexpr())
- return true;
-
- const FunctionDecl *DiagDecl = F->getDecl();
- const FunctionDecl *Definition = nullptr;
- DiagDecl->getBody(Definition);
-
- if (!Definition && S.checkingPotentialConstantExpression() &&
- DiagDecl->isConstexpr()) {
- return false;
- }
-
- // Implicitly constexpr.
- if (F->isLambdaStaticInvoker())
- return true;
-
+static bool diagnoseCallableDecl(InterpState &S, CodePtr OpPC,
+ const FunctionDecl *DiagDecl) {
// Bail out if the function declaration itself is invalid. We will
// have produced a relevant diagnostic while parsing it, so just
// note the problematic sub-expression.
@@ -953,11 +928,10 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
return Invalid(S, OpPC);
// Diagnose failed assertions specially.
- if (S.Current->getLocation(OpPC).isMacroID() &&
- F->getDecl()->getIdentifier()) {
+ if (S.Current->getLocation(OpPC).isMacroID() && DiagDecl->getIdentifier()) {
// FIXME: Instead of checking for an implementation-defined function,
// check and evaluate the assert() macro.
- StringRef Name = F->getDecl()->getName();
+ StringRef Name = DiagDecl->getName();
bool AssertFailed =
Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert";
if (AssertFailed) {
@@ -1004,7 +978,7 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
// for a constant expression. It might be defined at the point we're
// actually calling it.
bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
- bool IsDefined = F->isDefined();
+ bool IsDefined = DiagDecl->isDefined();
if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&
S.checkingPotentialConstantExpression())
return false;
@@ -1027,6 +1001,35 @@ static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
return false;
}
+static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
+ if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
+ return false;
+ }
+
+ if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)
+ return false;
+
+ if (F->isValid() && F->hasBody() && F->isConstexpr())
+ return true;
+
+ const FunctionDecl *DiagDecl = F->getDecl();
+ const FunctionDecl *Definition = nullptr;
+ DiagDecl->getBody(Definition);
+
+ if (!Definition && S.checkingPotentialConstantExpression() &&
+ DiagDecl->isConstexpr()) {
+ return false;
+ }
+
+ // Implicitly constexpr.
+ if (F->isLambdaStaticInvoker())
+ return true;
+
+ return diagnoseCallableDecl(S, OpPC, DiagDecl);
+}
+
static bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
S.FFDiag(S.Current->getSource(OpPC),
@@ -1500,6 +1503,21 @@ bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return CheckActive(S, OpPC, Ptr, AK_Destroy);
}
+/// Opcode. Check if the function decl can be called at compile time.
+bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD) {
+ if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)
+ return false;
+
+ const FunctionDecl *Definition = nullptr;
+ const Stmt *Body = FD->getBody(Definition);
+
+ if (Definition && Body &&
+ (Definition->isConstexpr() || Definition->hasAttr<MSConstexprAttr>()))
+ return true;
+
+ return diagnoseCallableDecl(S, OpPC, FD);
+}
+
static void compileFunction(InterpState &S, const Function *Func) {
const FunctionDecl *Definition = Func->getDecl()->getDefinition();
if (!Definition)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 6877b03..c16408c 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -117,6 +117,7 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
bool TargetIsUCharOrByte);
bool CheckBCPResult(InterpState &S, const Pointer &Ptr);
bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD);
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
const FixedPoint &FP);
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 1c17ad9e..a2eaa61 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -53,6 +53,7 @@ def ArgBool : ArgType { let Name = "bool"; }
def ArgFixedPoint : ArgType { let Name = "FixedPoint"; let AsRef = true; }
def ArgFunction : ArgType { let Name = "const Function *"; }
+def ArgFunctionDecl : ArgType { let Name = "const FunctionDecl *"; }
def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; }
def ArgRecordField : ArgType { let Name = "const Record::Field *"; }
def ArgFltSemantics : ArgType { let Name = "const llvm::fltSemantics *"; }
@@ -422,6 +423,8 @@ def CheckLiteralType : Opcode {
def CheckArraySize : Opcode { let Args = [ArgUint64]; }
+def CheckFunctionDecl : Opcode { let Args = [ArgFunctionDecl]; }
+
// [] -> [Value]
def GetGlobal : AccessOpcode;
def GetGlobalUnchecked : AccessOpcode;