Author: saar.raz Date: Tue Oct 15 08:24:26 2019 New Revision: 374903 URL: http://llvm.org/viewvc/llvm-project?rev=374903&view=rev Log: [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) Added: cfe/trunk/lib/Sema/SemaConcept.cpp cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp cfe/trunk/test/CXX/temp/temp.constr/ cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/ cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp Removed: cfe/trunk/test/CXX/concepts-ts/ Modified: cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/include/clang/AST/RecursiveASTVisitor.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Basic/StmtNodes.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/include/clang/Serialization/ASTBitCodes.h cfe/trunk/lib/AST/Expr.cpp cfe/trunk/lib/AST/ExprCXX.cpp cfe/trunk/lib/AST/ExprClassification.cpp cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/AST/StmtPrinter.cpp cfe/trunk/lib/AST/StmtProfile.cpp cfe/trunk/lib/CodeGen/CGExprScalar.cpp cfe/trunk/lib/Frontend/FrontendActions.cpp cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Sema/CMakeLists.txt cfe/trunk/lib/Sema/SemaExceptionSpec.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/lib/Serialization/ASTReaderStmt.cpp cfe/trunk/lib/Serialization/ASTWriterStmt.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp cfe/trunk/tools/libclang/CXCursor.cpp Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Oct 15 08:24:26 2019 @@ -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<ConceptSpecializationExpr, + TemplateArgument> { + 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<ConceptDecl *, 1, bool> 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<TemplateArgument> ConvertedArgs, + Optional<bool> 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<TemplateArgument> ConvertedArgs, Optional<bool> 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<TemplateArgument> getTemplateArguments() const { + return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(), + NumTemplateArgs); + } + + const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { + return ArgsAsWritten; + } + + /// \brief Set new template arguments for this concept specialization. + void setTemplateArguments(const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef<TemplateArgument> 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 Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Tue Oct 15 08:24:26 2019 @@ -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, {}) Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 15 08:24:26 2019 @@ -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_constraint "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 " 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)">; Modified: cfe/trunk/include/clang/Basic/StmtNodes.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/StmtNodes.td (original) +++ cfe/trunk/include/clang/Basic/StmtNodes.td Tue Oct 15 08:24:26 2019 @@ -163,6 +163,9 @@ def CoawaitExpr : DStmt<CoroutineSuspend def DependentCoawaitExpr : DStmt<Expr>; def CoyieldExpr : DStmt<CoroutineSuspendExpr>; +// C++2a Concepts expressions +def ConceptSpecializationExpr : DStmt<Expr>; + // Obj-C Expressions. def ObjCStringLiteral : DStmt<Expr>; def ObjCBoxedExpr : DStmt<Expr>; Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct 15 08:24:26 2019 @@ -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<Expr *> 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<TemplateArgument> 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<TemplateArgument> 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(); Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original) +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Tue Oct 15 08:24:26 2019 @@ -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 Modified: cfe/trunk/lib/AST/Expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/AST/Expr.cpp (original) +++ cfe/trunk/lib/AST/Expr.cpp Tue Oct 15 08:24:26 2019 @@ -3403,6 +3403,7 @@ bool Expr::HasSideEffects(const ASTConte case CXXUuidofExprClass: case OpaqueValueExprClass: case SourceLocExprClass: + case ConceptSpecializationExprClass: // These never have a side-effect. return false; Modified: cfe/trunk/lib/AST/ExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprCXX.cpp (original) +++ cfe/trunk/lib/AST/ExprCXX.cpp Tue Oct 15 08:24:26 2019 @@ -28,6 +28,9 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Sema/Template.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/Sema.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" @@ -1680,3 +1683,82 @@ CUDAKernelCallExpr *CUDAKernelCallExpr:: alignof(CUDAKernelCallExpr)); return new (Mem) CUDAKernelCallExpr(NumArgs, Empty); } + +ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C, + NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, + SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool> IsSatisfied) + : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + // All the flags below are set in setTemplateArguments. + /*ValueDependent=*/!IsSatisfied.hasValue(), + /*InstantiationDependent=*/false, + /*ContainsUnexpandedParameterPacks=*/false), + NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc), + ConceptNameLoc(ConceptNameLoc), FoundDecl(FoundDecl), + NamedConcept(NamedConcept, IsSatisfied ? *IsSatisfied : true), + NumTemplateArgs(ConvertedArgs.size()) { + + setTemplateArguments(ArgsAsWritten, ConvertedArgs); +} + +ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, + unsigned NumTemplateArgs) + : Expr(ConceptSpecializationExprClass, Empty), + NumTemplateArgs(NumTemplateArgs) { } + +void ConceptSpecializationExpr::setTemplateArguments( + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef<TemplateArgument> Converted) { + assert(Converted.size() == NumTemplateArgs); + assert(!this->ArgsAsWritten && "setTemplateArguments can only be used once"); + this->ArgsAsWritten = ArgsAsWritten; + std::uninitialized_copy(Converted.begin(), Converted.end(), + getTrailingObjects<TemplateArgument>()); + bool IsInstantiationDependent = false; + bool ContainsUnexpandedParameterPack = false; + for (const TemplateArgumentLoc& LocInfo : ArgsAsWritten->arguments()) { + if (LocInfo.getArgument().isInstantiationDependent()) + IsInstantiationDependent = true; + if (LocInfo.getArgument().containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + if (ContainsUnexpandedParameterPack && IsInstantiationDependent) + break; + } + + // Currently guaranteed by the fact concepts can only be at namespace-scope. + assert(!NestedNameSpec || + (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() && + !NestedNameSpec.getNestedNameSpecifier() + ->containsUnexpandedParameterPack())); + setInstantiationDependent(IsInstantiationDependent); + setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); + assert((!isValueDependent() || isInstantiationDependent()) && + "should not be value-dependent"); +} + +ConceptSpecializationExpr * +ConceptSpecializationExpr::Create(ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, + SourceLocation ConceptNameLoc, + NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + ArrayRef<TemplateArgument> ConvertedArgs, + Optional<bool> IsSatisfied) { + void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( + ConvertedArgs.size())); + return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc, + ConceptNameLoc, FoundDecl, + NamedConcept, ArgsAsWritten, + ConvertedArgs, IsSatisfied); +} + +ConceptSpecializationExpr * +ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty, + unsigned NumTemplateArgs) { + void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( + NumTemplateArgs)); + return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs); +} \ No newline at end of file Modified: cfe/trunk/lib/AST/ExprClassification.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprClassification.cpp (original) +++ cfe/trunk/lib/AST/ExprClassification.cpp Tue Oct 15 08:24:26 2019 @@ -192,6 +192,7 @@ static Cl::Kinds ClassifyInternal(ASTCon case Expr::NoInitExprClass: case Expr::DesignatedInitUpdateExprClass: case Expr::SourceLocExprClass: + case Expr::ConceptSpecializationExprClass: return Cl::CL_PRValue; case Expr::ConstantExprClass: Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Oct 15 08:24:26 2019 @@ -9768,6 +9768,7 @@ public: bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E); bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); bool VisitSourceLocExpr(const SourceLocExpr *E); + bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E); // FIXME: Missing: array subscript of vector, member of vector }; @@ -12250,6 +12251,12 @@ bool IntExprEvaluator::VisitCXXNoexceptE return Success(E->getValue(), E); } +bool IntExprEvaluator::VisitConceptSpecializationExpr( + const ConceptSpecializationExpr *E) { + return Success(E->isSatisfied(), E); +} + + bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { switch (E->getOpcode()) { default: @@ -13923,6 +13930,7 @@ static ICEDiag CheckICE(const Expr* E, c case Expr::CXXBoolLiteralExprClass: case Expr::CXXScalarValueInitExprClass: case Expr::TypeTraitExprClass: + case Expr::ConceptSpecializationExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::CXXNoexceptExprClass: Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue Oct 15 08:24:26 2019 @@ -3658,6 +3658,7 @@ recurse: case Expr::ConvertVectorExprClass: case Expr::StmtExprClass: case Expr::TypeTraitExprClass: + case Expr::ConceptSpecializationExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::VAArgExprClass: Modified: cfe/trunk/lib/AST/StmtPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/AST/StmtPrinter.cpp (original) +++ cfe/trunk/lib/AST/StmtPrinter.cpp Tue Oct 15 08:24:26 2019 @@ -2231,6 +2231,17 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFo OS << ")"; } +void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) { + NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc(); + if (NNS) + NNS.getNestedNameSpecifier()->print(OS, Policy); + if (E->getTemplateKWLoc().isValid()) + OS << "template "; + OS << E->getFoundDecl()->getName(); + printTemplateArgumentList(OS, E->getTemplateArgsAsWritten()->arguments(), + Policy); +} + // C++ Coroutines TS void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { Modified: cfe/trunk/lib/AST/StmtProfile.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/AST/StmtProfile.cpp (original) +++ cfe/trunk/lib/AST/StmtProfile.cpp Tue Oct 15 08:24:26 2019 @@ -1309,6 +1309,14 @@ void StmtProfiler::VisitAtomicExpr(const ID.AddInteger(S->getOp()); } +void StmtProfiler::VisitConceptSpecializationExpr( + const ConceptSpecializationExpr *S) { + VisitExpr(S); + VisitDecl(S->getFoundDecl()); + VisitTemplateArguments(S->getTemplateArgsAsWritten()->getTemplateArgs(), + S->getTemplateArgsAsWritten()->NumTemplateArgs); +} + static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, UnaryOperatorKind &UnaryOp, BinaryOperatorKind &BinaryOp) { Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Oct 15 08:24:26 2019 @@ -673,6 +673,10 @@ public: return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } + Value *VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E) { + return Builder.getInt1(E->isSatisfied()); + } + Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue()); } Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/FrontendActions.cpp (original) +++ cfe/trunk/lib/Frontend/FrontendActions.cpp Tue Oct 15 08:24:26 2019 @@ -417,6 +417,10 @@ private: return "DefiningSynthesizedFunction"; case CodeSynthesisContext::Memoization: return "Memoization"; + case CodeSynthesisContext::ConstraintsCheck: + return "ConstraintsCheck"; + case CodeSynthesisContext::ConstraintSubstitution: + return "ConstraintSubstitution"; } return ""; } Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Oct 15 08:24:26 2019 @@ -228,18 +228,16 @@ ExprResult Parser::ParseCaseExpression(S /// Parse a constraint-expression. /// /// \verbatim -/// constraint-expression: [Concepts TS temp.constr.decl p1] +/// constraint-expression: C++2a[temp.constr.decl]p1 /// logical-or-expression /// \endverbatim ExprResult Parser::ParseConstraintExpression() { - // FIXME: this may erroneously consume a function-body as the braced - // initializer list of a compound literal - // - // FIXME: this may erroneously consume a parenthesized rvalue reference - // declarator as a parenthesized address-of-label expression + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); - + if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) + return ExprError(); return Res; } Modified: cfe/trunk/lib/Sema/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Sema/CMakeLists.txt (original) +++ cfe/trunk/lib/Sema/CMakeLists.txt Tue Oct 15 08:24:26 2019 @@ -32,6 +32,7 @@ add_clang_library(clangSema SemaCast.cpp SemaChecking.cpp SemaCodeComplete.cpp + SemaConcept.cpp SemaConsumer.cpp SemaCoroutine.cpp SemaCUDA.cpp Added: cfe/trunk/lib/Sema/SemaConcept.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaConcept.cpp?rev=374903&view=auto ============================================================================== --- cfe/trunk/lib/Sema/SemaConcept.cpp (added) +++ cfe/trunk/lib/Sema/SemaConcept.cpp Tue Oct 15 08:24:26 2019 @@ -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; +} Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original) +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Tue Oct 15 08:24:26 2019 @@ -1314,6 +1314,7 @@ CanThrowResult Sema::canThrow(const Expr case Expr::SizeOfPackExprClass: case Expr::StringLiteralClass: case Expr::SourceLocExprClass: + case Expr::ConceptSpecializationExprClass: // These expressions can never throw. return CT_Cannot; Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Oct 15 08:24:26 2019 @@ -4271,14 +4271,47 @@ void Sema::diagnoseMissingTemplateArgume 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(con } 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 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. Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Oct 15 08:24:26 2019 @@ -198,12 +198,14 @@ bool Sema::CodeSynthesisContext::isInsta 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::Instantiati 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:: 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:: 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; Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct 15 08:24:26 2019 @@ -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>::TransformTypeTra 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) Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Oct 15 08:24:26 2019 @@ -734,6 +734,24 @@ void ASTStmtReader::VisitUnaryExprOrType E->setRParenLoc(ReadSourceLocation()); } +void ASTStmtReader::VisitConceptSpecializationExpr( + ConceptSpecializationExpr *E) { + VisitExpr(E); + unsigned NumTemplateArgs = Record.readInt(); + E->NestedNameSpec = Record.readNestedNameSpecifierLoc(); + E->TemplateKWLoc = Record.readSourceLocation(); + E->ConceptNameLoc = Record.readSourceLocation(); + E->FoundDecl = ReadDeclAs<NamedDecl>(); + E->NamedConcept.setPointer(ReadDeclAs<ConceptDecl>()); + const ASTTemplateArgumentListInfo *ArgsAsWritten = + Record.readASTTemplateArgumentListInfo(); + llvm::SmallVector<TemplateArgument, 4> Args; + for (unsigned I = 0; I < NumTemplateArgs; ++I) + Args.push_back(Record.readTemplateArgument()); + E->setTemplateArguments(ArgsAsWritten, Args); + E->NamedConcept.setInt(Record.readInt() == 1); +} + void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { VisitExpr(E); E->setLHS(Record.readSubExpr()); @@ -3490,6 +3508,12 @@ Stmt *ASTReader::ReadStmtFromStream(Modu case EXPR_DEPENDENT_COAWAIT: S = new (Context) DependentCoawaitExpr(Empty); break; + + case EXPR_CONCEPT_SPECIALIZATION: + unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields]; + S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs); + break; + } // We hit a STMT_STOP, so we're done with this expression. Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Oct 15 08:24:26 2019 @@ -388,6 +388,24 @@ void ASTStmtWriter::VisitDependentCoawai Code = serialization::EXPR_DEPENDENT_COAWAIT; } +void ASTStmtWriter::VisitConceptSpecializationExpr( + ConceptSpecializationExpr *E) { + VisitExpr(E); + ArrayRef<TemplateArgument> TemplateArgs = E->getTemplateArguments(); + Record.push_back(TemplateArgs.size()); + Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc()); + Record.AddSourceLocation(E->getTemplateKWLoc()); + Record.AddSourceLocation(E->getConceptNameLoc()); + Record.AddDeclRef(E->getFoundDecl()); + Record.AddDeclRef(E->getNamedConcept()); + Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten()); + for (const TemplateArgument &Arg : TemplateArgs) + Record.AddTemplateArgument(Arg); + Record.push_back(E->isSatisfied()); + Code = serialization::EXPR_CONCEPT_SPECIALIZATION; +} + + void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); // NumCaptures Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Oct 15 08:24:26 2019 @@ -1370,6 +1370,7 @@ void ExprEngine::Visit(const Stmt *S, Ex case Stmt::CUDAKernelCallExprClass: case Stmt::OpaqueValueExprClass: case Stmt::AsTypeExprClass: + case Stmt::ConceptSpecializationExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp?rev=374903&view=auto ============================================================================== --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp (added) +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp Tue Oct 15 08:24:26 2019 @@ -0,0 +1,149 @@ +// RUN: %clang_cc1 -std=c++2a -verify -triple x86_64-linux-gnu %s + +template<typename T> concept C1 = true; // expected-note{{template is declared here}} +static_assert(C1<int>); +static_assert(C1); +// expected-error@-1{{use of concept 'C1' requires template arguments}} + +template<typename T> concept C2 = sizeof(T) == 4; +static_assert(C2<int>); +static_assert(!C2<long long int>); +static_assert(C2<char[4]>); +static_assert(!C2<char[5]>); + +template<typename T> concept C3 = sizeof(*T{}) == 4; +static_assert(C3<int*>); +static_assert(!C3<long long int>); + +struct A { + static constexpr int add(int a, int b) { + return a + b; + } +}; +struct B { + static int add(int a, int b) { // expected-note{{declared here}} + return a + b; + } +}; +template<typename U> +concept C4 = U::add(1, 2) == 3; +// expected-error@-1{{substitution into constraint expression resulted in a non-constant expression}} +// expected-note@-2{{non-constexpr function 'add' cannot be used in a constant expression}} +static_assert(C4<A>); +static_assert(!C4<B>); // expected-note {{while checking the satisfaction of concept 'C4<B>' requested here}} + +template<typename T, typename U> +constexpr bool is_same_v = false; + +template<typename T> +constexpr bool is_same_v<T, T> = true; + +template<typename T, typename U> +concept Same = is_same_v<T, U>; + +static_assert(Same<int, int>); +static_assert(Same<int, decltype(1)>); +static_assert(!Same<int, unsigned int>); +static_assert(!Same<A, B>); +static_assert(Same<A, A>); + +static_assert(Same<bool, decltype(C1<int>)>); +static_assert(Same<bool, decltype(C2<int>)>); +static_assert(Same<bool, decltype(C3<int*>)>); +static_assert(Same<bool, decltype(C4<A>)>); + +template<typename T> concept C5 = T{}; // expected-error {{atomic constraint must be of type 'bool' (found 'int')}} +constexpr bool x = C5<int>; // expected-note {{while checking the satisfaction of concept 'C5<int>' requested here}} + +template<int x> +concept IsEven = (x % 2) == 0; + +static_assert(IsEven<20>); +static_assert(!IsEven<11>); + +template<template<typename T> typename P> +concept IsTypePredicate = is_same_v<decltype(P<bool>::value), const bool> + && is_same_v<decltype(P<int>::value), const bool> + && is_same_v<decltype(P<long long>::value), const bool>; + +template<typename T> struct T1 {}; +template<typename T> struct T2 { static constexpr bool value = sizeof(T) == 2; }; + +static_assert(IsTypePredicate<T2>); +static_assert(!IsTypePredicate<T1>); + +namespace piecewise_substitution { + template <typename T> + concept True = true; + + template <typename T> + concept A = True<T> || T::value; + + template <typename T> + concept B = (True<T> || T::value); + + template <typename T> + concept C = !True<T> && T::value || true; + + template <typename T> + concept D = (!True<T> && T::value) || true; + + template <typename T> + concept E = T::value || True<T>; + + template <typename T> + concept F = (T::value || True<T>); + + template <typename T> + concept G = T::value && !True<T> || true; + + template <typename T> + concept H = (T::value && !True<T>) || true; + + template <typename T> + concept I = T::value; + + static_assert(A<int>); + static_assert(B<int>); + static_assert(C<int>); + static_assert(D<int>); + static_assert(E<int>); + static_assert(F<int>); + static_assert(G<int>); + static_assert(H<int>); + static_assert(!I<int>); +} + +// Short ciruiting + +template<typename T> struct T3 { using type = typename T::type; }; +// expected-error@-1{{type 'char' cannot be used prior to '::' because it has no members}} +// expected-error@-2{{type 'short' cannot be used prior to '::' because it has no members}} + +template<typename T> +concept C6 = sizeof(T) == 1 && sizeof(typename T3<T>::type) == 1; +// expected-note@-1{{while substituting template arguments into constraint expression here}} +// expected-note@-2{{in instantiation of template class 'T3<char>' requested here}} + +template<typename T> +concept C7 = sizeof(T) == 1 || sizeof( +// expected-note@-1{{while substituting template arguments into constraint expression here}} + typename + T3<T> +// expected-note@-1{{in instantiation of template class 'T3<short>' requested here}} + ::type) == 1; + +static_assert(!C6<short>); +static_assert(!C6<char>); // expected-note{{while checking the satisfaction of concept 'C6<char>' requested here}} +static_assert(C7<char>); +static_assert(!C7<short>); // expected-note{{while checking the satisfaction of concept 'C7<short>' requested here}} + +// Make sure argument list is converted when instantiating a CSE. + +template<typename T, typename U = int> +concept SameSize = sizeof(T) == sizeof(U); + +template<typename T> +struct X { static constexpr bool a = SameSize<T>; }; + +static_assert(X<unsigned>::a); Added: cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp?rev=374903&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp Tue Oct 15 08:24:26 2019 @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s + +namespace nodiag { + +template <typename T> requires bool(T()) +struct A; +template <typename U> requires bool(U()) +struct A; + +} // end namespace nodiag + +namespace diag { + +template <typename T> requires true // expected-note{{previous template declaration is here}} +struct A; +template <typename T> struct A; // expected-error{{associated constraints differ in template redeclaration}} + +template <typename T> struct B; // expected-note{{previous template declaration is here}} +template <typename T> requires true // expected-error{{associated constraints differ in template redeclaration}} +struct B; + +template <typename T> requires true // expected-note{{previous template declaration is here}} +struct C; +template <typename T> requires !0 // expected-error{{associated constraints differ in template redeclaration}} +struct C; + +} // end namespace diag + +namespace nodiag { + +struct AA { + template <typename T> requires someFunc(T()) + struct A; +}; + +template <typename T> requires someFunc(T()) +struct AA::A { }; + +struct AAF { + template <typename T> requires someFunc(T()) + friend struct AA::A; +}; + +} // end namespace nodiag + +namespace diag { + +template <unsigned N> +struct TA { + template <template <unsigned> class TT> requires TT<N>::happy // expected-note 2{{previous template declaration is here}} + struct A; + + struct AF; +}; + +template <unsigned N> +template <template <unsigned> class TT> struct TA<N>::A { }; // expected-error{{associated constraints differ in template redeclaration}} + +template <unsigned N> +struct TA<N>::AF { + template <template <unsigned> class TT> requires TT<N + 0>::happy // expected-error{{associated constraints differ in template redeclaration}} + friend struct TA::A; +}; + +} // end namespace diag Added: cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp?rev=374903&view=auto ============================================================================== --- cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp (added) +++ cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp Tue Oct 15 08:24:26 2019 @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t +// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s + +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +template<typename... T> +concept C = true; + +namespace n { + template<typename... T> + concept C = true; +} + +void f() { + (void)C<int>; + (void)C<int, void>; + (void)n::C<void>; +} + +#else /*included pch*/ + +int main() { + (void)C<int>; + (void)C<int, void>; + (void)n::C<void>; + f(); +} + +#endif // HEADER Modified: cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp (original) +++ cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp Tue Oct 15 08:24:26 2019 @@ -14,8 +14,6 @@ template<template<typename> concept T> c // expected-error@-2{{template template parameter requires 'class' after the parameter list}} // expected-error@-3{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}} -template<typename T> concept C2 = 0.f; // expected-error {{constraint expression must be of type 'bool' but is of type 'float'}} - struct S1 { template<typename T> concept C1 = true; // expected-error {{concept declarations may only appear in global or namespace scope}} }; @@ -26,15 +24,15 @@ extern "C++" { template<typename A> template<typename B> -concept C4 = true; // expected-error {{extraneous template parameter list in concept definition}} +concept C2 = true; // expected-error {{extraneous template parameter list in concept definition}} -template<typename T> concept C5 = true; // expected-note {{previous}} expected-note {{previous}} -int C5; // expected-error {{redefinition}} -struct C5 {}; // expected-error {{redefinition}} - -struct C6 {}; // expected-note{{previous definition is here}} -template<typename T> concept C6 = true; -// expected-error@-1{{redefinition of 'C6' as different kind of symbol}} +template<typename T> concept C3 = true; // expected-note {{previous}} expected-note {{previous}} +int C3; // expected-error {{redefinition}} +struct C3 {}; // expected-error {{redefinition}} + +struct C4 {}; // expected-note{{previous definition is here}} +template<typename T> concept C4 = true; +// expected-error@-1{{redefinition of 'C4' as different kind of symbol}} // TODO: Add test to prevent explicit specialization, partial specialization // and explicit instantiation of concepts. @@ -43,31 +41,60 @@ template<typename T, T v> struct integral_constant { static constexpr T value = v; }; namespace N { - template<typename T> concept C7 = true; + template<typename T> concept C5 = true; } -using N::C7; +using N::C5; -template <bool word> concept C8 = integral_constant<bool, wor>::value; +template <bool word> concept C6 = integral_constant<bool, wor>::value; // expected-error@-1{{use of undeclared identifier 'wor'; did you mean 'word'?}} // expected-note@-2{{'word' declared here}} -template<typename T> concept bool C9 = true; +template<typename T> concept bool C7 = true; // expected-warning@-1{{ISO C++2a does not permit the 'bool' keyword after 'concept'}} -template<> concept C10 = false; +template<> concept C8 = false; // expected-error@-1{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}} -template<> concept C9<int> = false; +template<> concept C7<int> = false; // expected-error@-1{{name defined in concept definition must be an identifier}} -template<typename T> concept N::C11 = false; +template<typename T> concept N::C9 = false; // expected-error@-1{{name defined in concept definition must be an identifier}} class A { }; // expected-note@-1{{'A' declared here}} -template<typename T> concept A::C12 = false; +template<typename T> concept A::C10 = false; // expected-error@-1{{expected namespace name}} template<typename T> concept operator int = false; // expected-error@-1{{name defined in concept definition must be an identifier}} + +template<bool x> concept C11 = 2; // expected-error {{atomic constraint must be of type 'bool' (found 'int')}} +template<bool x> concept C12 = 2 && x; // expected-error {{atomic constraint must be of type 'bool' (found 'int')}} +template<bool x> concept C13 = x || 2 || x; // expected-error {{atomic constraint must be of type 'bool' (found 'int')}} +template<bool x> concept C14 = 8ull && x || x; // expected-error {{atomic constraint must be of type 'bool' (found 'unsigned long long')}} +template<typename T> concept C15 = sizeof(T); // expected-error {{atomic constraint must be of type 'bool'}} +template<typename T> concept C16 = true && (0 && 0); // expected-error {{atomic constraint must be of type 'bool' (found 'int')}} +// expected-warning@-1{{use of logical '&&' with constant operand}} +// expected-note@-2{{use '&' for a bitwise operation}} +// expected-note@-3{{remove constant to silence this warning}} +template<typename T> concept C17 = T{}; +static_assert(!C17<bool>); +template<typename T> concept C18 = (bool&&)true; +static_assert(C18<int>); +template<typename T> concept C19 = (const bool&)true; +static_assert(C19<int>); +template<typename T> concept C20 = (const bool)true; +static_assert(C20<int>); +template <bool c> concept C21 = integral_constant<bool, c>::value && true; +static_assert(C21<true>); +static_assert(!C21<false>); +template <bool c> concept C22 = integral_constant<bool, c>::value; +static_assert(C22<true>); +static_assert(!C22<false>); + +template <bool word> concept C23 = integral_constant<bool, wor>::value; +// expected-error@-1{{use of undeclared identifier 'wor'; did you mean 'word'?}} +// expected-note@-2{{'word' declared here}} + Modified: cfe/trunk/tools/libclang/CXCursor.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=374903&r1=374902&r2=374903&view=diff ============================================================================== --- cfe/trunk/tools/libclang/CXCursor.cpp (original) +++ cfe/trunk/tools/libclang/CXCursor.cpp Tue Oct 15 08:24:26 2019 @@ -256,6 +256,7 @@ CXCursor cxcursor::MakeCXCursor(const St case Stmt::BinaryConditionalOperatorClass: case Stmt::TypeTraitExprClass: case Stmt::CoawaitExprClass: + case Stmt::ConceptSpecializationExprClass: case Stmt::DependentCoawaitExprClass: case Stmt::CoyieldExprClass: case Stmt::CXXBindTemporaryExprClass: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits