Skip to content

Commit

Permalink
PR42071: Reject weird names for non-type template parameters.
Browse files Browse the repository at this point in the history
Also reject default arguments appearing in invalid locations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@363447 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
zygoloid committed Jun 14, 2019
1 parent b444e60 commit ba78be7
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 25 deletions.
2 changes: 2 additions & 0 deletions include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ def err_bad_variable_name : Error<
"%0 cannot be the name of a variable or data member">;
def err_bad_parameter_name : Error<
"%0 cannot be the name of a parameter">;
def err_bad_parameter_name_template_id : Error<
"parameter name cannot have template arguments">;
def err_parameter_name_omitted : Error<"parameter name omitted">;
def err_anyx86_interrupt_attribute : Error<
"%select{x86|x86-64}0 'interrupt' attribute only applies to functions that "
Expand Down
4 changes: 3 additions & 1 deletion include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2083,7 +2083,9 @@ class Sema {
QualType NewT, QualType OldT);
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition);
Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
bool IsDefinition);
void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D);
Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
Expand Down
66 changes: 42 additions & 24 deletions lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12453,6 +12453,45 @@ void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) {
}
}

/// Common checks for a parameter-declaration that should apply to both function
/// parameters and non-type template parameters.
void Sema::CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D) {
// Check that there are no default arguments inside the type of this
// parameter.
if (getLangOpts().CPlusPlus)
CheckExtraCXXDefaultArguments(D);

// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
<< D.getCXXScopeSpec().getRange();
}

// [dcl.meaning]p1: An unqualified-id occurring in a declarator-id shall be a
// simple identifier except [...irrelevant cases...].
switch (D.getName().getKind()) {
case UnqualifiedIdKind::IK_Identifier:
break;

case UnqualifiedIdKind::IK_OperatorFunctionId:
case UnqualifiedIdKind::IK_ConversionFunctionId:
case UnqualifiedIdKind::IK_LiteralOperatorId:
case UnqualifiedIdKind::IK_ConstructorName:
case UnqualifiedIdKind::IK_DestructorName:
case UnqualifiedIdKind::IK_ImplicitSelfParam:
case UnqualifiedIdKind::IK_DeductionGuideName:
Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name)
<< GetNameForDeclarator(D).getName();
break;

case UnqualifiedIdKind::IK_TemplateId:
case UnqualifiedIdKind::IK_ConstructorTemplateId:
// GetNameForDeclarator would not produce a useful name in this case.
Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name_template_id);
break;
}
}

/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
/// to introduce parameters into function prototype scope.
Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
Expand Down Expand Up @@ -12493,34 +12532,13 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {

DiagnoseFunctionSpecifiers(DS);

CheckFunctionOrTemplateParamDeclarator(S, D);

TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType parmDeclType = TInfo->getType();

if (getLangOpts().CPlusPlus) {
// Check that there are no default arguments inside the type of this
// parameter.
CheckExtraCXXDefaultArguments(D);

// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
<< D.getCXXScopeSpec().getRange();
D.getCXXScopeSpec().clear();
}
}

// Ensure we have a valid name
IdentifierInfo *II = nullptr;
if (D.hasName()) {
II = D.getIdentifier();
if (!II) {
Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name)
<< GetNameForDeclarator(D).getName();
D.setInvalidType(true);
}
}

// Check for redeclaration of parameters, e.g. int foo(int x, int x);
IdentifierInfo *II = D.getIdentifier();
if (II) {
LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName,
ForVisibleRedeclaration);
Expand Down
2 changes: 2 additions & 0 deletions lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,8 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
Invalid = true;
}

CheckFunctionOrTemplateParamDeclarator(S, D);

IdentifierInfo *ParamName = D.getIdentifier();
bool IsParameterPack = D.hasEllipsis();
NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(
Expand Down
8 changes: 8 additions & 0 deletions test/Parser/cxx-template-decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,11 @@ namespace class_scope_instantiation {
void f(double);
};
}

namespace PR42071 {
template<int SomeTemplateName<void>> struct A; // expected-error {{parameter name cannot have template arguments}}
template<int operator+> struct B; // expected-error {{'operator+' cannot be the name of a parameter}}
struct Q {};
template<int Q::N> struct C; // expected-error {{parameter declarator cannot be qualified}}
template<int f(int a = 0)> struct D; // expected-error {{default arguments can only be specified for parameters in a function declaration}}
}

0 comments on commit ba78be7

Please sign in to comment.