Improve diagnostics for ill-formed literal operator declarations.

Patch by Erik Pilkington!

llvm-svn: 261034
This commit is contained in:
Richard Smith
2016-02-17 00:04:04 +00:00
parent b68464eb78
commit c28aee6a51
5 changed files with 163 additions and 97 deletions

View File

@@ -11765,6 +11765,49 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
return false;
}
static bool
checkLiteralOperatorTemplateParameterList(Sema &SemaRef,
FunctionTemplateDecl *TpDecl) {
TemplateParameterList *TemplateParams = TpDecl->getTemplateParameters();
// Must have one or two template parameters.
if (TemplateParams->size() == 1) {
NonTypeTemplateParmDecl *PmDecl =
dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(0));
// The template parameter must be a char parameter pack.
if (PmDecl && PmDecl->isTemplateParameterPack() &&
SemaRef.Context.hasSameType(PmDecl->getType(), SemaRef.Context.CharTy))
return false;
} else if (TemplateParams->size() == 2) {
TemplateTypeParmDecl *PmType =
dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(0));
NonTypeTemplateParmDecl *PmArgs =
dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(1));
// The second template parameter must be a parameter pack with the
// first template parameter as its type.
if (PmType && PmArgs && !PmType->isTemplateParameterPack() &&
PmArgs->isTemplateParameterPack()) {
const TemplateTypeParmType *TArgs =
PmArgs->getType()->getAs<TemplateTypeParmType>();
if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
TArgs->getIndex() == PmType->getIndex()) {
if (SemaRef.ActiveTemplateInstantiations.empty())
SemaRef.Diag(TpDecl->getLocation(),
diag::ext_string_literal_operator_template);
return false;
}
}
}
SemaRef.Diag(TpDecl->getTemplateParameters()->getSourceRange().getBegin(),
diag::err_literal_operator_template)
<< TpDecl->getTemplateParameters()->getSourceRange();
return true;
}
/// CheckLiteralOperatorDeclaration - Check whether the declaration
/// of this literal operator function is well-formed. If so, returns
/// false; otherwise, emits appropriate diagnostics and returns true.
@@ -11780,10 +11823,9 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
return true;
}
bool Valid = false;
// This might be the definition of a literal operator template.
FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate();
// This might be a specialization of a literal operator template.
if (!TpDecl)
TpDecl = FnDecl->getPrimaryTemplate();
@@ -11792,101 +11834,117 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
// template <class T, T...> type operator "" name() are the only valid
// template signatures, and the only valid signatures with no parameters.
if (TpDecl) {
if (FnDecl->param_size() == 0) {
// Must have one or two template parameters
TemplateParameterList *Params = TpDecl->getTemplateParameters();
if (Params->size() == 1) {
NonTypeTemplateParmDecl *PmDecl =
dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(0));
// The template parameter must be a char parameter pack.
if (PmDecl && PmDecl->isTemplateParameterPack() &&
Context.hasSameType(PmDecl->getType(), Context.CharTy))
Valid = true;
} else if (Params->size() == 2) {
TemplateTypeParmDecl *PmType =
dyn_cast<TemplateTypeParmDecl>(Params->getParam(0));
NonTypeTemplateParmDecl *PmArgs =
dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1));
// The second template parameter must be a parameter pack with the
// first template parameter as its type.
if (PmType && PmArgs &&
!PmType->isTemplateParameterPack() &&
PmArgs->isTemplateParameterPack()) {
const TemplateTypeParmType *TArgs =
PmArgs->getType()->getAs<TemplateTypeParmType>();
if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
TArgs->getIndex() == PmType->getIndex()) {
Valid = true;
if (ActiveTemplateInstantiations.empty())
Diag(FnDecl->getLocation(),
diag::ext_string_literal_operator_template);
}
}
}
if (FnDecl->param_size() != 0) {
Diag(FnDecl->getLocation(),
diag::err_literal_operator_template_with_params);
return true;
}
} else if (FnDecl->param_size()) {
// Check the first parameter
if (checkLiteralOperatorTemplateParameterList(*this, TpDecl))
return true;
} else if (FnDecl->param_size() == 1) {
const ParmVarDecl *Param = FnDecl->getParamDecl(0);
QualType ParamType = Param->getType().getUnqualifiedType();
// Only unsigned long long int, long double, any character type, and const
// char * are allowed as the only parameters.
if (ParamType->isSpecificBuiltinType(BuiltinType::ULongLong) ||
ParamType->isSpecificBuiltinType(BuiltinType::LongDouble) ||
Context.hasSameType(ParamType, Context.CharTy) ||
Context.hasSameType(ParamType, Context.WideCharTy) ||
Context.hasSameType(ParamType, Context.Char16Ty) ||
Context.hasSameType(ParamType, Context.Char32Ty)) {
} else if (const PointerType *Ptr = ParamType->getAs<PointerType>()) {
QualType InnerType = Ptr->getPointeeType();
// Pointer parameter must be a const char *.
if (!(Context.hasSameType(InnerType.getUnqualifiedType(),
Context.CharTy) &&
InnerType.isConstQualified() && !InnerType.isVolatileQualified())) {
Diag(Param->getSourceRange().getBegin(),
diag::err_literal_operator_param)
<< ParamType << "'const char *'" << Param->getSourceRange();
return true;
}
} else if (ParamType->isRealFloatingType()) {
Diag(Param->getSourceRange().getBegin(), diag::err_literal_operator_param)
<< ParamType << Context.LongDoubleTy << Param->getSourceRange();
return true;
} else if (ParamType->isIntegerType()) {
Diag(Param->getSourceRange().getBegin(), diag::err_literal_operator_param)
<< ParamType << Context.UnsignedLongLongTy << Param->getSourceRange();
return true;
} else {
Diag(Param->getSourceRange().getBegin(),
diag::err_literal_operator_invalid_param)
<< ParamType << Param->getSourceRange();
return true;
}
} else if (FnDecl->param_size() == 2) {
FunctionDecl::param_iterator Param = FnDecl->param_begin();
QualType T = (*Param)->getType().getUnqualifiedType();
// First, verify that the first parameter is correct.
// unsigned long long int, long double, and any character type are allowed
// as the only parameters.
if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
Context.hasSameType(T, Context.LongDoubleTy) ||
Context.hasSameType(T, Context.CharTy) ||
Context.hasSameType(T, Context.WideCharTy) ||
Context.hasSameType(T, Context.Char16Ty) ||
Context.hasSameType(T, Context.Char32Ty)) {
if (++Param == FnDecl->param_end())
Valid = true;
goto FinishedParams;
QualType FirstParamType = (*Param)->getType().getUnqualifiedType();
// Two parameter function must have a pointer to const as a
// first parameter; let's strip those qualifiers.
const PointerType *PT = FirstParamType->getAs<PointerType>();
if (!PT) {
Diag((*Param)->getSourceRange().getBegin(),
diag::err_literal_operator_param)
<< FirstParamType << "'const char *'" << (*Param)->getSourceRange();
return true;
}
// Otherwise it must be a pointer to const; let's strip those qualifiers.
const PointerType *PT = T->getAs<PointerType>();
if (!PT)
goto FinishedParams;
T = PT->getPointeeType();
if (!T.isConstQualified() || T.isVolatileQualified())
goto FinishedParams;
T = T.getUnqualifiedType();
QualType PointeeType = PT->getPointeeType();
// First parameter must be const
if (!PointeeType.isConstQualified() || PointeeType.isVolatileQualified()) {
Diag((*Param)->getSourceRange().getBegin(),
diag::err_literal_operator_param)
<< FirstParamType << "'const char *'" << (*Param)->getSourceRange();
return true;
}
// Move on to the second parameter;
QualType InnerType = PointeeType.getUnqualifiedType();
// Only const char *, const wchar_t*, const char16_t*, and const char32_t*
// are allowed as the first parameter to a two-parameter function
if (!(Context.hasSameType(InnerType, Context.CharTy) ||
Context.hasSameType(InnerType, Context.WideCharTy) ||
Context.hasSameType(InnerType, Context.Char16Ty) ||
Context.hasSameType(InnerType, Context.Char32Ty))) {
Diag((*Param)->getSourceRange().getBegin(),
diag::err_literal_operator_param)
<< FirstParamType << "'const char *'" << (*Param)->getSourceRange();
return true;
}
// Move on to the second and final parameter.
++Param;
// If there is no second parameter, the first must be a const char *
if (Param == FnDecl->param_end()) {
if (Context.hasSameType(T, Context.CharTy))
Valid = true;
goto FinishedParams;
// The second parameter must be a std::size_t.
QualType SecondParamType = (*Param)->getType().getUnqualifiedType();
if (!Context.hasSameType(SecondParamType, Context.getSizeType())) {
Diag((*Param)->getSourceRange().getBegin(),
diag::err_literal_operator_param)
<< SecondParamType << Context.getSizeType()
<< (*Param)->getSourceRange();
return true;
}
// const char *, const wchar_t*, const char16_t*, and const char32_t*
// are allowed as the first parameter to a two-parameter function
if (!(Context.hasSameType(T, Context.CharTy) ||
Context.hasSameType(T, Context.WideCharTy) ||
Context.hasSameType(T, Context.Char16Ty) ||
Context.hasSameType(T, Context.Char32Ty)))
goto FinishedParams;
// The second and final parameter must be an std::size_t
T = (*Param)->getType().getUnqualifiedType();
if (Context.hasSameType(T, Context.getSizeType()) &&
++Param == FnDecl->param_end())
Valid = true;
}
// FIXME: This diagnostic is absolutely terrible.
FinishedParams:
if (!Valid) {
Diag(FnDecl->getLocation(), diag::err_literal_operator_params)
<< FnDecl->getDeclName();
} else {
Diag(FnDecl->getLocation(), diag::err_literal_operator_bad_param_count);
return true;
}
// Parameters are good.
// A parameter-declaration-clause containing a default argument is not
// equivalent to any of the permitted forms.
for (auto Param : FnDecl->params()) {