r374882 - [Concepts] Concept Specialization Expressions
Nico Weber via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 15 05:58:26 PDT 2019
The test is failing on Windows. Please take a look, and if it takes a while
to fix please revert while you investigate:
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/11533/steps/stage%201%20check/logs/stdio
On Tue, Oct 15, 2019 at 7:46 AM Saar Raz via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: saar.raz
> Date: Tue Oct 15 04:48:58 2019
> New Revision: 374882
>
> URL: http://llvm.org/viewvc/llvm-project?rev=374882&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 referenced with arguments,
> and tests thereof.
>
>
>
> 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/ExprCXX.h (original)
> +++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
> +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Tue Oct 15 04:48:58
> 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 15
> 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/StmtNodes.td (original)
> +++ cfe/trunk/include/clang/Basic/StmtNodes.td Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
> +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Tue Oct 15
> 04:48:58 2019
> @@ -1912,6 +1912,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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/Expr.cpp (original)
> +++ cfe/trunk/lib/AST/Expr.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprCXX.cpp (original)
> +++ cfe/trunk/lib/AST/ExprCXX.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprClassification.cpp (original)
> +++ cfe/trunk/lib/AST/ExprClassification.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
> +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
> +++ cfe/trunk/lib/AST/StmtPrinter.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/StmtProfile.cpp (original)
> +++ cfe/trunk/lib/AST/StmtProfile.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
> +++ cfe/trunk/lib/Frontend/FrontendActions.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Sema/CMakeLists.txt Tue Oct 15 04:48:58 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=374882&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaConcept.cpp (added)
> +++ cfe/trunk/lib/Sema/SemaConcept.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/TreeTransform.h (original)
> +++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Oct 15 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
> +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Oct 15 04:48:58
> 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=374882&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
> 04:48:58 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 at -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 at -1{{substitution into constraint expression resulted
> in a non-constant expression}}
> +// expected-note at -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 at -1{{type 'char' cannot be used prior to '::' because
> it has no members}}
> +// expected-error at -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 at -1{{while substituting template arguments into
> constraint expression here}}
> +// expected-note at -2{{in instantiation of template class 'T3<char>'
> requested here}}
> +
> +template<typename T>
> +concept C7 = sizeof(T) == 1 || sizeof(
> +// expected-note at -1{{while substituting template arguments into
> constraint expression here}}
> + typename
> + T3<T>
> +// expected-note at -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=374882&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 04:48:58 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=374882&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp (added)
> +++ cfe/trunk/test/PCH/cxx2a-concept-specialization-expr.cpp Tue Oct 15
> 04:48:58 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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp (original)
> +++ cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp Tue Oct 15
> 04:48:58 2019
> @@ -14,8 +14,6 @@ template<template<typename> concept T> c
> // expected-error at -2{{template template parameter requires 'class' after
> the parameter list}}
> // expected-error at -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 at -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 at -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 at -1{{use of undeclared identifier 'wor'; did you mean
> 'word'?}}
> // expected-note at -2{{'word' declared here}}
>
> -template<typename T> concept bool C9 = true;
> +template<typename T> concept bool C7 = true;
> // expected-warning at -1{{ISO C++2a does not permit the 'bool' keyword
> after 'concept'}}
>
> -template<> concept C10 = false;
> +template<> concept C8 = false;
> // expected-error at -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 at -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 at -1{{name defined in concept definition must be an
> identifier}}
>
> class A { };
> // expected-note at -1{{'A' declared here}}
>
> -template<typename T> concept A::C12 = false;
> +template<typename T> concept A::C10 = false;
> // expected-error at -1{{expected namespace name}}
>
> template<typename T> concept operator int = false;
> // expected-error at -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' (found 'unsigned long')}}
> +template<typename T> concept C16 = true && (0 && 0); // expected-error
> {{atomic constraint must be of type 'bool' (found 'int')}}
> +// expected-warning at -1{{use of logical '&&' with constant operand}}
> +// expected-note at -2{{use '&' for a bitwise operation}}
> +// expected-note at -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 at -1{{use of undeclared identifier 'wor'; did you mean
> 'word'?}}
> +// expected-note at -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=374882&r1=374881&r2=374882&view=diff
>
> ==============================================================================
> --- cfe/trunk/tools/libclang/CXCursor.cpp (original)
> +++ cfe/trunk/tools/libclang/CXCursor.cpp Tue Oct 15 04:48:58 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 at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20191015/da35eaf3/attachment-0001.html>
More information about the cfe-commits
mailing list