forked from OSchip/llvm-project
126 lines
4.6 KiB
C++
126 lines
4.6 KiB
C++
//===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements semantic analysis for C++ constraints and concepts.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Sema/Sema.h"
|
|
#include "clang/Sema/SemaDiagnostic.h"
|
|
#include "clang/Sema/TemplateDeduction.h"
|
|
#include "clang/Sema/Template.h"
|
|
#include "clang/AST/ExprCXX.h"
|
|
using namespace clang;
|
|
using namespace sema;
|
|
|
|
bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
|
|
// C++2a [temp.constr.atomic]p1
|
|
// ..E shall be a constant expression of type bool.
|
|
|
|
ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
|
|
|
|
if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
|
|
if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
|
|
return CheckConstraintExpression(BinOp->getLHS()) &&
|
|
CheckConstraintExpression(BinOp->getRHS());
|
|
} else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
|
|
return CheckConstraintExpression(C->getSubExpr());
|
|
|
|
// An atomic constraint!
|
|
if (ConstraintExpression->isTypeDependent())
|
|
return true;
|
|
|
|
QualType Type = ConstraintExpression->getType();
|
|
if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
|
|
Diag(ConstraintExpression->getExprLoc(),
|
|
diag::err_non_bool_atomic_constraint) << Type
|
|
<< ConstraintExpression->getSourceRange();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept,
|
|
MultiLevelTemplateArgumentList &MLTAL,
|
|
Expr *ConstraintExpr,
|
|
bool &IsSatisfied) {
|
|
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
|
|
|
|
if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) {
|
|
if (BO->getOpcode() == BO_LAnd) {
|
|
if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
|
|
IsSatisfied))
|
|
return true;
|
|
if (!IsSatisfied)
|
|
return false;
|
|
return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
|
|
IsSatisfied);
|
|
} else if (BO->getOpcode() == BO_LOr) {
|
|
if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
|
|
IsSatisfied))
|
|
return true;
|
|
if (IsSatisfied)
|
|
return false;
|
|
return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
|
|
IsSatisfied);
|
|
}
|
|
}
|
|
else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
|
|
return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(),
|
|
IsSatisfied);
|
|
|
|
EnterExpressionEvaluationContext ConstantEvaluated(
|
|
*this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
|
|
|
// Atomic constraint - substitute arguments and check satisfaction.
|
|
ExprResult E;
|
|
{
|
|
TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc());
|
|
InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(),
|
|
InstantiatingTemplate::ConstraintSubstitution{},
|
|
NamedConcept, Info,
|
|
ConstraintExpr->getSourceRange());
|
|
if (Inst.isInvalid())
|
|
return true;
|
|
// We do not want error diagnostics escaping here.
|
|
Sema::SFINAETrap Trap(*this);
|
|
|
|
E = SubstExpr(ConstraintExpr, MLTAL);
|
|
if (E.isInvalid() || Trap.hasErrorOccurred()) {
|
|
// C++2a [temp.constr.atomic]p1
|
|
// ...If substitution results in an invalid type or expression, the
|
|
// constraint is not satisfied.
|
|
IsSatisfied = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!CheckConstraintExpression(E.get()))
|
|
return true;
|
|
|
|
SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
|
|
Expr::EvalResult EvalResult;
|
|
EvalResult.Diag = &EvaluationDiags;
|
|
if (!E.get()->EvaluateAsRValue(EvalResult, Context)) {
|
|
// C++2a [temp.constr.atomic]p1
|
|
// ...E shall be a constant expression of type bool.
|
|
Diag(E.get()->getBeginLoc(),
|
|
diag::err_non_constant_constraint_expression)
|
|
<< E.get()->getSourceRange();
|
|
for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
|
|
Diag(PDiag.first, PDiag.second);
|
|
return true;
|
|
}
|
|
|
|
IsSatisfied = EvalResult.Val.getInt().getBoolValue();
|
|
|
|
return false;
|
|
}
|