forked from OSchip/llvm-project
[Concepts] Implement a portion of Concepts TS[dcl.spec.concept]p1 by
diagnosing when 'concept' is specified on a function or template specialization. Since a concept can only be applied to a function or variable template, the concept bit is stored in TemplateDecl as a PointerIntPair. Reviewers: rsmith, faisalv, aaron.ballman, hubert.reinterpretcast Differential Revision: http://reviews.llvm.org/D13357 llvm-svn: 260074
This commit is contained in:
parent
be748c2033
commit
de49845b05
|
@ -332,24 +332,23 @@ class TemplateDecl : public NamedDecl {
|
|||
void anchor() override;
|
||||
protected:
|
||||
// This is probably never used.
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr),
|
||||
TemplateParams(nullptr) {}
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
|
||||
TemplateParams(nullptr) {}
|
||||
|
||||
// Construct a template decl with the given name and parameters.
|
||||
// Used when there is not templated element (tt-params).
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr),
|
||||
TemplateParams(Params) {}
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
|
||||
TemplateParams(Params) {}
|
||||
|
||||
// Construct a template decl with name, parameters, and templated element.
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
DeclarationName Name, TemplateParameterList *Params,
|
||||
NamedDecl *Decl)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl),
|
||||
TemplateParams(Params) { }
|
||||
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params, NamedDecl *Decl)
|
||||
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false),
|
||||
TemplateParams(Params) {}
|
||||
|
||||
public:
|
||||
/// Get the list of template parameters
|
||||
TemplateParameterList *getTemplateParameters() const {
|
||||
|
@ -357,7 +356,7 @@ public:
|
|||
}
|
||||
|
||||
/// Get the underlying, templated declaration.
|
||||
NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
|
||||
NamedDecl *getTemplatedDecl() const { return TemplatedDecl.getPointer(); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
|
@ -367,20 +366,30 @@ public:
|
|||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange(TemplateParams->getTemplateLoc(),
|
||||
TemplatedDecl->getSourceRange().getEnd());
|
||||
TemplatedDecl.getPointer()->getSourceRange().getEnd());
|
||||
}
|
||||
|
||||
/// Whether this is a (C++ Concepts TS) function or variable concept.
|
||||
bool isConcept() const { return TemplatedDecl.getInt(); }
|
||||
void setConcept() { TemplatedDecl.setInt(true); }
|
||||
|
||||
protected:
|
||||
NamedDecl *TemplatedDecl;
|
||||
/// \brief The named declaration from which this template was instantiated.
|
||||
/// (or null).
|
||||
///
|
||||
/// The boolean value will be true to indicate that this template
|
||||
/// (function or variable) is a concept.
|
||||
llvm::PointerIntPair<NamedDecl *, 1, bool> TemplatedDecl;
|
||||
|
||||
TemplateParameterList* TemplateParams;
|
||||
|
||||
public:
|
||||
/// \brief Initialize the underlying templated declaration and
|
||||
/// template parameters.
|
||||
void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) {
|
||||
assert(!TemplatedDecl && "TemplatedDecl already set!");
|
||||
assert(!TemplatedDecl.getPointer() && "TemplatedDecl already set!");
|
||||
assert(!TemplateParams && "TemplateParams already set!");
|
||||
TemplatedDecl = templatedDecl;
|
||||
TemplatedDecl.setPointer(templatedDecl);
|
||||
TemplateParams = templateParams;
|
||||
}
|
||||
};
|
||||
|
@ -889,7 +898,7 @@ public:
|
|||
|
||||
/// Get the underlying function declaration of the template.
|
||||
FunctionDecl *getTemplatedDecl() const {
|
||||
return static_cast<FunctionDecl*>(TemplatedDecl);
|
||||
return static_cast<FunctionDecl *>(TemplatedDecl.getPointer());
|
||||
}
|
||||
|
||||
/// Returns whether this template declaration defines the primary
|
||||
|
@ -1982,7 +1991,7 @@ public:
|
|||
|
||||
/// \brief Get the underlying class declarations of the template.
|
||||
CXXRecordDecl *getTemplatedDecl() const {
|
||||
return static_cast<CXXRecordDecl *>(TemplatedDecl);
|
||||
return static_cast<CXXRecordDecl *>(TemplatedDecl.getPointer());
|
||||
}
|
||||
|
||||
/// \brief Returns whether this template declaration defines the primary
|
||||
|
@ -2245,7 +2254,7 @@ protected:
|
|||
public:
|
||||
/// Get the underlying function declaration of the template.
|
||||
TypeAliasDecl *getTemplatedDecl() const {
|
||||
return static_cast<TypeAliasDecl*>(TemplatedDecl);
|
||||
return static_cast<TypeAliasDecl *>(TemplatedDecl.getPointer());
|
||||
}
|
||||
|
||||
|
||||
|
@ -2808,7 +2817,7 @@ public:
|
|||
|
||||
/// \brief Get the underlying variable declarations of the template.
|
||||
VarDecl *getTemplatedDecl() const {
|
||||
return static_cast<VarDecl *>(TemplatedDecl);
|
||||
return static_cast<VarDecl *>(TemplatedDecl.getPointer());
|
||||
}
|
||||
|
||||
/// \brief Returns whether this template declaration defines the primary
|
||||
|
|
|
@ -2080,6 +2080,9 @@ def err_function_concept_bool_ret : Error<
|
|||
"declared return type of function concept must be 'bool'">;
|
||||
def err_variable_concept_bool_decl : Error<
|
||||
"declared type of variable concept must be 'bool'">;
|
||||
def err_concept_specified_specialization : Error<
|
||||
"'concept' cannot be applied on an "
|
||||
"%select{explicit instantiation|explicit specialization|partial specialization}0">;
|
||||
|
||||
// C++11 char16_t/char32_t
|
||||
def warn_cxx98_compat_unicode_type : Warning<
|
||||
|
|
|
@ -6002,6 +6002,15 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
NewVD->setInvalidDecl(true);
|
||||
}
|
||||
|
||||
// C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
|
||||
// applied only to the definition of a function template or variable
|
||||
// template, declared in namespace scope.
|
||||
if (IsVariableTemplateSpecialization) {
|
||||
Diag(D.getDeclSpec().getConceptSpecLoc(),
|
||||
diag::err_concept_specified_specialization)
|
||||
<< (IsPartialSpecialization ? 2 : 1);
|
||||
}
|
||||
|
||||
// C++ Concepts TS [dcl.spec.concept]p6: A variable concept has the
|
||||
// following restrictions:
|
||||
// - The declared type shall have the type bool.
|
||||
|
@ -7667,6 +7676,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
}
|
||||
|
||||
if (isConcept) {
|
||||
// This is a function concept.
|
||||
if (FunctionTemplateDecl *FTD = NewFD->getDescribedFunctionTemplate())
|
||||
FTD->setConcept();
|
||||
|
||||
// C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
|
||||
// applied only to the definition of a function template [...]
|
||||
if (!D.isFunctionDefinition()) {
|
||||
|
@ -7733,6 +7746,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
<< 1 << 3;
|
||||
NewFD->setInvalidDecl(true);
|
||||
}
|
||||
|
||||
// C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
|
||||
// applied only to the definition of a function template or variable
|
||||
// template, declared in namespace scope.
|
||||
if (isFunctionTemplateSpecialization) {
|
||||
Diag(D.getDeclSpec().getConceptSpecLoc(),
|
||||
diag::err_concept_specified_specialization) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If __module_private__ was specified, mark the function accordingly.
|
||||
|
@ -7994,9 +8015,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
TemplateId->NumArgs);
|
||||
translateTemplateArguments(TemplateArgsPtr,
|
||||
TemplateArgs);
|
||||
|
||||
|
||||
HasExplicitTemplateArgs = true;
|
||||
|
||||
|
||||
if (NewFD->isInvalidDecl()) {
|
||||
HasExplicitTemplateArgs = false;
|
||||
} else if (FunctionTemplate) {
|
||||
|
|
|
@ -7673,6 +7673,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
Diag(D.getDeclSpec().getConstexprSpecLoc(),
|
||||
diag::err_explicit_instantiation_constexpr);
|
||||
|
||||
// C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
|
||||
// applied only to the definition of a function template or variable template,
|
||||
// declared in namespace scope.
|
||||
if (D.getDeclSpec().isConceptSpecified()) {
|
||||
Diag(D.getDeclSpec().getConceptSpecLoc(),
|
||||
diag::err_concept_specified_specialization) << 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// C++0x [temp.explicit]p2:
|
||||
// There are two forms of explicit instantiation: an explicit instantiation
|
||||
// definition and an explicit instantiation declaration. An explicit
|
||||
|
|
|
@ -41,3 +41,20 @@ typedef concept int CI; // expected-error {{'concept' can only appear on the def
|
|||
void fpc(concept int i) {} // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
|
||||
|
||||
concept bool; // expected-error {{'concept' can only appear on the definition of a function template or variable template}}
|
||||
|
||||
template <typename T> concept bool VCEI{ true };
|
||||
template concept bool VCEI<int>; // expected-error {{'concept' cannot be applied on an explicit instantiation}}
|
||||
extern template concept bool VCEI<int>; // expected-error {{'concept' cannot be applied on an explicit instantiation}}
|
||||
|
||||
template <typename T> concept bool VCPS{ true };
|
||||
template <typename T> concept bool VCPS<T *>{ true }; // expected-error {{'concept' cannot be applied on an partial specialization}}
|
||||
|
||||
template <typename T> concept bool VCES{ true };
|
||||
template <> concept bool VCES<int>{ true }; // expected-error {{'concept' cannot be applied on an explicit specialization}}
|
||||
|
||||
template <typename T> concept bool FCEI() { return true; }
|
||||
template concept bool FCEI<int>(); // expected-error {{'concept' cannot be applied on an explicit instantiation}}
|
||||
extern template concept bool FCEI<int>(); // expected-error {{'concept' cannot be applied on an explicit instantiation}}
|
||||
|
||||
template <typename T> concept bool FCES() { return true; }
|
||||
template <> concept bool FCES<bool>() { return true; } // expected-error {{'concept' cannot be applied on an explicit specialization}}
|
||||
|
|
Loading…
Reference in New Issue