diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-02-17 00:04:04 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-02-17 00:04:04 +0000 |
commit | c28aee6a51a9eceb4c34269330d3f3d97e01f936 (patch) | |
tree | 4fac39109dce0a0a8835ed13ce610251a0784524 /clang/lib/Sema/SemaDeclCXX.cpp | |
parent | b68464eb7825a83fa8d3cb867adfd7339a255c45 (diff) | |
download | bcm5719-llvm-c28aee6a51a9eceb4c34269330d3f3d97e01f936.tar.gz bcm5719-llvm-c28aee6a51a9eceb4c34269330d3f3d97e01f936.zip |
Improve diagnostics for ill-formed literal operator declarations.
Patch by Erik Pilkington!
llvm-svn: 261034
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 230 |
1 files changed, 144 insertions, 86 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index b7e03e3eb6c..c160f444ca5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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; + } + + 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()) { - // Check the first parameter + + } else if (FnDecl->param_size() == 2) { FunctionDecl::param_iterator Param = FnDecl->param_begin(); - QualType T = (*Param)->getType().getUnqualifiedType(); - - // 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; - } - - // 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(); - - // Move on to the second parameter; - ++Param; + // First, verify that the first parameter is correct. + + 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 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; + if (!PT) { + Diag((*Param)->getSourceRange().getBegin(), + diag::err_literal_operator_param) + << FirstParamType << "'const char *'" << (*Param)->getSourceRange(); + return true; } - // const char *, const wchar_t*, const char16_t*, and const char32_t* + 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; + } + + 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(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(); + 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; + + // 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; + } + } 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()) { |