summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/CMakeLists.txt1
-rw-r--r--clang/lib/Sema/SemaConcept.cpp125
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp69
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp51
-rw-r--r--clang/lib/Sema/TreeTransform.h36
6 files changed, 257 insertions, 26 deletions
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 742343583d1..89c3f6c47b4 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -32,6 +32,7 @@ add_clang_library(clangSema
SemaCast.cpp
SemaChecking.cpp
SemaCodeComplete.cpp
+ SemaConcept.cpp
SemaConsumer.cpp
SemaCoroutine.cpp
SemaCUDA.cpp
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
new file mode 100644
index 00000000000..3131609390a
--- /dev/null
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -0,0 +1,125 @@
+//===-- 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;
+}
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 0f3a27233ee..76fd10d2e63 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1314,6 +1314,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::SizeOfPackExprClass:
case Expr::StringLiteralClass:
case Expr::SourceLocExprClass:
+ case Expr::ConceptSpecializationExprClass:
// These expressions can never throw.
return CT_Cannot;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 284962f3e07..cb756eb30f6 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4271,14 +4271,47 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
ExprResult
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- ConceptDecl *Template,
- SourceLocation TemplateLoc,
+ SourceLocation TemplateKWLoc,
+ SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
const TemplateArgumentListInfo *TemplateArgs) {
- // TODO: Do concept specialization here.
- Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) <<
- "concept specialization";
- return ExprError();
+ assert(NamedConcept && "A concept template id without a template?");
+
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc,
+ const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
+ /*PartialTemplateArgs=*/false, Converted,
+ /*UpdateArgsWithConversion=*/false))
+ return ExprError();
+
+ Optional<bool> IsSatisfied;
+ bool AreArgsDependent = false;
+ for (TemplateArgument &Arg : Converted) {
+ if (Arg.isDependent()) {
+ AreArgsDependent = true;
+ break;
+ }
+ }
+ if (!AreArgsDependent) {
+ InstantiatingTemplate Inst(*this, ConceptNameLoc,
+ InstantiatingTemplate::ConstraintsCheck{}, NamedConcept, Converted,
+ SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc,
+ TemplateArgs->getRAngleLoc()));
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(Converted);
+ bool Satisfied;
+ if (CalculateConstraintSatisfaction(NamedConcept, MLTAL,
+ NamedConcept->getConstraintExpr(),
+ Satisfied))
+ return ExprError();
+ IsSatisfied = Satisfied;
+ }
+ return ConceptSpecializationExpr::Create(Context,
+ SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
+ TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept,
+ ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
+ IsSatisfied);
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
@@ -4322,9 +4355,10 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
}
if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) {
- return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
- R.getAsSingle<ConceptDecl>(),
- TemplateKWLoc, TemplateArgs);
+ return CheckConceptTemplateId(SS, TemplateKWLoc,
+ R.getLookupNameInfo().getBeginLoc(),
+ R.getFoundDecl(),
+ R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
// We don't want lookup warnings at this point.
@@ -8054,20 +8088,7 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
TemplateParameterLists.front(),
ConstraintExpr);
-
- if (!ConstraintExpr->isTypeDependent() &&
- ConstraintExpr->getType() != Context.BoolTy) {
- // C++2a [temp.constr.atomic]p3:
- // E shall be a constant expression of type bool.
- // TODO: Do this check for individual atomic constraints
- // and not the constraint expression. Probably should do it in
- // ParseConstraintExpression.
- Diag(ConstraintExpr->getSourceRange().getBegin(),
- diag::err_concept_initialized_with_non_bool_type)
- << ConstraintExpr->getType();
- NewDecl->setInvalidDecl();
- }
-
+
if (NewDecl->getAssociatedConstraints()) {
// C++2a [temp.concept]p4:
// A concept shall not have associated constraints.
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 9091bc5b80d..42411c9c33f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -198,12 +198,14 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
case PriorTemplateArgumentSubstitution:
+ case ConstraintsCheck:
return true;
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
case DefiningSynthesizedFunction:
case ExceptionSpecEvaluation:
+ case ConstraintSubstitution:
return false;
// This function should never be called when Kind's value is Memoization.
@@ -358,6 +360,24 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintsCheck, TemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ConstraintsCheck,
+ PointOfInstantiation, InstantiationRange, Template, nullptr,
+ TemplateArgs) {}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintSubstitution, TemplateDecl *Template,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ConstraintSubstitution,
+ PointOfInstantiation, InstantiationRange, Template, nullptr,
+ {}, &DeductionInfo) {}
+
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
@@ -664,6 +684,30 @@ void Sema::PrintInstantiationStack() {
case CodeSynthesisContext::Memoization:
break;
+
+ case CodeSynthesisContext::ConstraintsCheck:
+ if (auto *CD = dyn_cast<ConceptDecl>(Active->Entity)) {
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ CD->printName(OS);
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_concept_specialization_here)
+ << OS.str()
+ << Active->InstantiationRange;
+ break;
+ }
+ // TODO: Concepts - implement this for constrained templates and partial
+ // specializations.
+ llvm_unreachable("only concept constraints are supported right now");
+ break;
+
+ case CodeSynthesisContext::ConstraintSubstitution:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_constraint_substitution_here)
+ << Active->InstantiationRange;
+ break;
}
}
}
@@ -687,6 +731,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
LLVM_FALLTHROUGH;
case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
case CodeSynthesisContext::ExceptionSpecInstantiation:
+ case CodeSynthesisContext::ConstraintsCheck:
// This is a template instantiation, so there is no SFINAE.
return None;
@@ -700,8 +745,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
- // We're either substitution explicitly-specified template arguments
- // or deduced template arguments, so SFINAE applies.
+ case CodeSynthesisContext::ConstraintSubstitution:
+ // We're either substituting explicitly-specified template arguments
+ // or deduced template arguments or a constraint expression, so SFINAE
+ // applies.
assert(Active->DeductionInfo && "Missing deduction info pointer");
return Active->DeductionInfo;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 59cac787876..8184d4c09b4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3019,6 +3019,25 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ TemplateArgumentListInfo *TALI) {
+ CXXScopeSpec SS;
+ SS.Adopt(NNS);
+ ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc,
+ ConceptNameLoc,
+ FoundDecl,
+ NamedConcept, TALI);
+ if (Result.isInvalid())
+ return ExprError();
+ return Result;
+ }
+
+ /// \brief Build a new Objective-C boxed expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
return getSema().BuildObjCBoxedExpr(SR, ValueExpr);
}
@@ -11016,6 +11035,23 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc);
+ if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
+ Old->NumTemplateArgs, TransArgs))
+ return ExprError();
+
+ return getDerived().RebuildConceptSpecializationExpr(
+ E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
+ E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(),
+ &TransArgs);
+}
+
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo());
if (!T)
OpenPOWER on IntegriCloud