From 40a8d3b5eea52db1c328646df4ac9b10ab919dd7 Mon Sep 17 00:00:00 2001 From: Saar Raz Date: Tue, 15 Oct 2019 15:24:26 +0000 Subject: [Concepts] Concept Specialization Expressions Part of C++20 Concepts implementation effort. Added Concept Specialization Expressions that are created when a concept is refe$ D41217 on Phabricator. (recommit after fixing failing Parser test on windows) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@374903 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExprCXX.h | 121 +++++++++++++++++++++++++++++ include/clang/AST/RecursiveASTVisitor.h | 6 ++ include/clang/Basic/DiagnosticSemaKinds.td | 11 ++- include/clang/Basic/StmtNodes.td | 3 + include/clang/Sema/Sema.h | 43 +++++++++- include/clang/Serialization/ASTBitCodes.h | 1 + 6 files changed, 179 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 61e7a91d9f..57ccba8b81 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -17,6 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" @@ -56,6 +57,7 @@ class IdentifierInfo; class LambdaCapture; class NonTypeTemplateParmDecl; class TemplateParameterList; +class Sema; //===--------------------------------------------------------------------===// // C++ Expressions. @@ -4750,6 +4752,125 @@ public: } }; +/// \brief Represents the specialization of a concept - evaluates to a prvalue +/// of type bool. +/// +/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the +/// specialization of a concept results in a prvalue of type bool. +class ConceptSpecializationExpr final : public Expr, + private llvm::TrailingObjects { + friend class ASTStmtReader; + friend TrailingObjects; + + // \brief The optional nested name specifier used when naming the concept. + NestedNameSpecifierLoc NestedNameSpec; + + /// \brief The location of the template keyword, if specified when naming the + /// concept. + SourceLocation TemplateKWLoc; + + /// \brief The location of the concept name in the expression. + SourceLocation ConceptNameLoc; + + /// \brief The declaration found by name lookup when the expression was + /// created. + /// Can differ from NamedConcept when, for example, the concept was found + /// through a UsingShadowDecl. + NamedDecl *FoundDecl; + + /// \brief The concept named, and whether or not the concept with the given + /// arguments was satisfied when the expression was created. + /// If any of the template arguments are dependent (this expr would then be + /// isValueDependent()), this bit is to be ignored. + llvm::PointerIntPair NamedConcept; + + /// \brief The template argument list source info used to specialize the + /// concept. + const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; + + /// \brief The number of template arguments in the tail-allocated list of + /// converted template arguments. + unsigned NumTemplateArgs; + + ConceptSpecializationExpr(ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, + SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef ConvertedArgs, + Optional IsSatisfied); + + ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs); + +public: + + static ConceptSpecializationExpr * + Create(ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef ConvertedArgs, Optional IsSatisfied); + + static ConceptSpecializationExpr * + Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs); + + const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { + return NestedNameSpec; + } + + NamedDecl *getFoundDecl() const { + return FoundDecl; + } + + ConceptDecl *getNamedConcept() const { + return NamedConcept.getPointer(); + } + + ArrayRef getTemplateArguments() const { + return ArrayRef(getTrailingObjects(), + NumTemplateArgs); + } + + const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { + return ArgsAsWritten; + } + + /// \brief Set new template arguments for this concept specialization. + void setTemplateArguments(const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef Converted); + + /// \brief Whether or not the concept with the given arguments was satisfied + /// when the expression was created. This method assumes that the expression + /// is not dependent! + bool isSatisfied() const { + assert(!isValueDependent() + && "isSatisfied called on a dependent ConceptSpecializationExpr"); + return NamedConcept.getInt(); + } + + SourceLocation getConceptNameLoc() const { return ConceptNameLoc; } + + SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConceptSpecializationExprClass; + } + + SourceLocation getBeginLoc() const LLVM_READONLY { return ConceptNameLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return ArgsAsWritten->RAngleLoc; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + } // namespace clang #endif // LLVM_CLANG_AST_EXPRCXX_H diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 09a6f7840d..998cf9238c 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2659,6 +2659,12 @@ DEF_TRAVERSE_STMT(CoyieldExpr, { } }) +DEF_TRAVERSE_STMT(ConceptSpecializationExpr, { + TRY_TO(TraverseTemplateArgumentLocsHelper( + S->getTemplateArgsAsWritten()->getTemplateArgs(), + S->getTemplateArgsAsWritten()->NumTemplateArgs)); +}) + // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) DEF_TRAVERSE_STMT(FixedPointLiteral, {}) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 47a1deef98..968c2dbd56 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2526,8 +2526,6 @@ def note_private_extern : Note< "use __attribute__((visibility(\"hidden\"))) attribute instead">; // C++ Concepts -def err_concept_initialized_with_non_bool_type : Error< - "constraint expression must be of type 'bool' but is of type %0">; def err_concept_decls_may_only_appear_in_global_namespace_scope : Error< "concept declarations may only appear in global or namespace scope">; def err_concept_no_parameters : Error< @@ -2539,6 +2537,11 @@ def err_concept_no_associated_constraints : Error< "concept cannot have associated constraints">; def err_concept_not_implemented : Error< "sorry, unimplemented concepts feature %0 used">; +def err_non_constant_constraint_expression : Error< + "substitution into constraint expression resulted in a non-constant " + "expression">; +def err_non_bool_atomic_constraint : Error< + "atomic constraint must be of type 'bool' (found %0)">; def err_template_different_associated_constraints : Error< "associated constraints differ in template redeclaration">; @@ -4496,6 +4499,10 @@ def note_prior_template_arg_substitution : Note< " template parameter%1 %2">; def note_template_default_arg_checking : Note< "while checking a default template argument used here">; +def note_concept_specialization_here : Note< + "while checking the satisfaction of concept '%0' requested here">; +def note_constraint_substitution_here : Note< + "while substituting template arguments into constraint expression here">; def note_instantiation_contexts_suppressed : Note< "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " "see all)">; diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 1cef89f371..6231484e2b 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -163,6 +163,9 @@ def CoawaitExpr : DStmt; def DependentCoawaitExpr : DStmt; def CoyieldExpr : DStmt; +// C++2a Concepts expressions +def ConceptSpecializationExpr : DStmt; + // Obj-C Expressions. def ObjCStringLiteral : DStmt; def ObjCBoxedExpr : DStmt; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0403df4ba7..6b2d603206 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6047,7 +6047,16 @@ public: CXXConversionDecl *Conv, Expr *Src); - // ParseObjCStringLiteral - Parse Objective-C string literals. + /// Check whether the given expression is a valid constraint expression. + /// A diagnostic is emitted if it is not, and false is returned. + bool CheckConstraintExpression(Expr *CE); + + bool CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, + MultiLevelTemplateArgumentList &MLTAL, + Expr *ConstraintExpr, + bool &IsSatisfied); + + // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef Strings); @@ -6718,9 +6727,9 @@ public: ExprResult CheckConceptTemplateId(const CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo, - ConceptDecl *Template, - SourceLocation TemplateLoc, + SourceLocation TemplateKWLoc, + SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs); void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc); @@ -7639,6 +7648,15 @@ public: /// member). DefiningSynthesizedFunction, + // We are checking the constraints associated with a constrained entity or + // the constraint expression of a concept. This includes the checks that + // atomic constraints have the type 'bool' and that they can be constant + // evaluated. + ConstraintsCheck, + + // We are substituting template arguments into a constraint expression. + ConstraintSubstitution, + /// Added for Template instantiation observation. /// Memoization means we are _not_ instantiating a template because /// it is already instantiated (but we entered a context where we @@ -7899,6 +7917,23 @@ public: ArrayRef TemplateArgs, SourceRange InstantiationRange); + struct ConstraintsCheck {}; + /// \brief Note that we are checking the constraints associated with some + /// constrained entity (a concept declaration or a template with associated + /// constraints). + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ConstraintsCheck, TemplateDecl *Template, + ArrayRef TemplateArgs, + SourceRange InstantiationRange); + + struct ConstraintSubstitution {}; + /// \brief Note that we are checking a constraint expression associated + /// with a template declaration or as part of the satisfaction check of a + /// concept. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ConstraintSubstitution, TemplateDecl *Template, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange); /// Note that we have finished instantiating this template. void Clear(); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index eab1ec86db..0d3971dd27 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1915,6 +1915,7 @@ namespace serialization { EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr EXPR_CXX_FOLD, // CXXFoldExpr + EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr // CUDA EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr -- cgit v1.2.1