Skip to content

Commit

Permalink
[Concepts] Implement a portion of Concepts TS[dcl.spec.concept]p1 by
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Wilson-N committed Feb 8, 2016
1 parent be748c2 commit de49845
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 24 deletions.
53 changes: 31 additions & 22 deletions clang/include/clang/AST/DeclTemplate.h
Expand Up @@ -332,32 +332,31 @@ 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 {
return TemplateParams;
}

/// 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()); }
Expand All @@ -367,20 +366,30 @@ class TemplateDecl : public NamedDecl {

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;
}
};
Expand Down Expand Up @@ -889,7 +898,7 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {

/// 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
Expand Down Expand Up @@ -1982,7 +1991,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {

/// \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
Expand Down Expand Up @@ -2245,7 +2254,7 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
public:
/// Get the underlying function declaration of the template.
TypeAliasDecl *getTemplatedDecl() const {
return static_cast<TypeAliasDecl*>(TemplatedDecl);
return static_cast<TypeAliasDecl *>(TemplatedDecl.getPointer());
}


Expand Down Expand Up @@ -2808,7 +2817,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {

/// \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
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -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<
Expand Down
25 changes: 23 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Expand Up @@ -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.
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Expand Up @@ -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
Expand Down
Expand Up @@ -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}}

0 comments on commit de49845

Please sign in to comment.