summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-10-07 19:57:58 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-10-07 19:57:58 +0000
commitb8b41d3ea4445c9d3d4e0cd7c9b6a11c6ce1640a (patch)
treee748182e1c2360a8249f84b772b7b27680d50c01 /clang/lib
parentd29406233b051f3dcc9dc5316d204401016bef6b (diff)
downloadbcm5719-llvm-b8b41d3ea4445c9d3d4e0cd7c9b6a11c6ce1640a.tar.gz
bcm5719-llvm-b8b41d3ea4445c9d3d4e0cd7c9b6a11c6ce1640a.zip
Add support for WG21 N3599 (literal operator template for strings) as a GNU
extension. The GCC folks have decided to support this even though the standard committee have not yet approved this feature. Patch by Hristo Venev! llvm-svn: 192128
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp28
-rw-r--r--clang/lib/Sema/SemaExpr.cpp110
-rw-r--r--clang/lib/Sema/SemaLookup.cpp45
3 files changed, 135 insertions, 48 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 518f3156a9f..6d357e7be05 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -10917,11 +10917,12 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
if (!TpDecl)
TpDecl = FnDecl->getPrimaryTemplate();
- // template <char...> type operator "" name() is the only valid template
- // signature, and the only valid signature with no parameters.
+ // template <char...> type operator "" name() and
+ // 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 only one template parameter
+ // Must have one or two template parameters
TemplateParameterList *Params = TpDecl->getTemplateParameters();
if (Params->size() == 1) {
NonTypeTemplateParmDecl *PmDecl =
@@ -10931,6 +10932,27 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
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);
+ }
+ }
}
}
} else if (FnDecl->param_size()) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 9188808bcef..12e6a260ac9 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1461,7 +1461,8 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName);
if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()),
- /*AllowRawAndTemplate*/false) == Sema::LOLR_Error)
+ /*AllowRaw*/false, /*AllowTemplate*/false,
+ /*AllowStringTemplate*/false) == Sema::LOLR_Error)
return ExprError();
return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
@@ -1486,36 +1487,34 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
for (unsigned i = 0; i != NumStringToks; ++i)
StringTokLocs.push_back(StringToks[i].getLocation());
- QualType StrTy = Context.CharTy;
- if (Literal.isWide())
- StrTy = Context.getWideCharType();
- else if (Literal.isUTF16())
- StrTy = Context.Char16Ty;
- else if (Literal.isUTF32())
- StrTy = Context.Char32Ty;
- else if (Literal.isPascal())
- StrTy = Context.UnsignedCharTy;
-
+ QualType CharTy = Context.CharTy;
StringLiteral::StringKind Kind = StringLiteral::Ascii;
- if (Literal.isWide())
+ if (Literal.isWide()) {
+ CharTy = Context.getWideCharType();
Kind = StringLiteral::Wide;
- else if (Literal.isUTF8())
+ } else if (Literal.isUTF8()) {
Kind = StringLiteral::UTF8;
- else if (Literal.isUTF16())
+ } else if (Literal.isUTF16()) {
+ CharTy = Context.Char16Ty;
Kind = StringLiteral::UTF16;
- else if (Literal.isUTF32())
+ } else if (Literal.isUTF32()) {
+ CharTy = Context.Char32Ty;
Kind = StringLiteral::UTF32;
+ } else if (Literal.isPascal()) {
+ CharTy = Context.UnsignedCharTy;
+ }
+ QualType CharTyConst = CharTy;
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings)
- StrTy.addConst();
+ CharTyConst.addConst();
// Get an array type for the string, according to C99 6.4.5. This includes
// the nul terminator character as well as the string length for pascal
// strings.
- StrTy = Context.getConstantArrayType(StrTy,
+ QualType StrTy = Context.getConstantArrayType(CharTyConst,
llvm::APInt(32, Literal.GetNumStringChars()+1),
- ArrayType::Normal, 0);
+ ArrayType::Normal, 0);
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(),
@@ -1538,12 +1537,57 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
// C++11 [lex.ext]p5: The literal L is treated as a call of the form
// operator "" X (str, len)
QualType SizeType = Context.getSizeType();
- llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars());
- IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType,
- StringTokLocs[0]);
- Expr *Args[] = { Lit, LenArg };
- return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc,
- Args, StringTokLocs.back());
+
+ DeclarationName OpName =
+ Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
+ DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
+ OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
+
+ QualType ArgTy[] = {
+ Context.getArrayDecayedType(StrTy), SizeType
+ };
+
+ LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
+ switch (LookupLiteralOperator(UDLScope, R, ArgTy,
+ /*AllowRaw*/false, /*AllowTemplate*/false,
+ /*AllowStringTemplate*/true)) {
+
+ case LOLR_Cooked: {
+ llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars());
+ IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType,
+ StringTokLocs[0]);
+ Expr *Args[] = { Lit, LenArg };
+
+ return BuildLiteralOperatorCall(R, OpNameInfo, Args, StringTokLocs.back());
+ }
+
+ case LOLR_StringTemplate: {
+ TemplateArgumentListInfo ExplicitArgs;
+
+ unsigned CharBits = Context.getIntWidth(CharTy);
+ bool CharIsUnsigned = CharTy->isUnsignedIntegerType();
+ llvm::APSInt Value(CharBits, CharIsUnsigned);
+
+ TemplateArgument TypeArg(CharTy);
+ TemplateArgumentLocInfo TypeArgInfo(Context.getTrivialTypeSourceInfo(CharTy));
+ ExplicitArgs.addArgument(TemplateArgumentLoc(TypeArg, TypeArgInfo));
+
+ for (unsigned I = 0, N = Lit->getLength(); I != N; ++I) {
+ Value = Lit->getCodeUnit(I);
+ TemplateArgument Arg(Context, Value, CharTy);
+ TemplateArgumentLocInfo ArgInfo;
+ ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
+ }
+ return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(),
+ &ExplicitArgs);
+ }
+ case LOLR_Raw:
+ case LOLR_Template:
+ llvm_unreachable("unexpected literal operator lookup result");
+ case LOLR_Error:
+ return ExprError();
+ }
+ llvm_unreachable("unexpected literal operator lookup result");
}
ExprResult
@@ -2942,11 +2986,14 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
+ SourceLocation TokLoc = Tok.getLocation();
+
// Perform literal operator lookup to determine if we're building a raw
// literal or a cooked one.
LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
switch (LookupLiteralOperator(UDLScope, R, CookedTy,
- /*AllowRawAndTemplate*/true)) {
+ /*AllowRaw*/true, /*AllowTemplate*/true,
+ /*AllowStringTemplate*/false)) {
case LOLR_Error:
return ExprError();
@@ -2961,15 +3008,13 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy,
Tok.getLocation());
}
- return BuildLiteralOperatorCall(R, OpNameInfo, Lit,
- Tok.getLocation());
+ return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc);
}
case LOLR_Raw: {
// C++11 [lit.ext]p3, p4: If S contains a raw literal operator, the
// literal is treated as a call of the form
// operator "" X ("n")
- SourceLocation TokLoc = Tok.getLocation();
unsigned Length = Literal.getUDSuffixOffset();
QualType StrTy = Context.getConstantArrayType(
Context.CharTy.withConst(), llvm::APInt(32, Length + 1),
@@ -2980,7 +3025,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc);
}
- case LOLR_Template:
+ case LOLR_Template: {
// C++11 [lit.ext]p3, p4: Otherwise (S contains a literal operator
// template), L is treated as a call fo the form
// operator "" X <'c1', 'c2', ... 'ck'>()
@@ -2995,11 +3040,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
}
- return BuildLiteralOperatorCall(R, OpNameInfo, None, Tok.getLocation(),
+ return BuildLiteralOperatorCall(R, OpNameInfo, None, TokLoc,
&ExplicitArgs);
}
-
- llvm_unreachable("unexpected literal operator lookup result");
+ case LOLR_StringTemplate:
+ llvm_unreachable("unexpected literal operator lookup result");
+ }
}
Expr *Res;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 44d457e1e1d..2b7c0b1cf86 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2711,7 +2711,8 @@ CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
Sema::LiteralOperatorLookupResult
Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
ArrayRef<QualType> ArgTys,
- bool AllowRawAndTemplate) {
+ bool AllowRaw, bool AllowTemplate,
+ bool AllowStringTemplate) {
LookupName(R, S);
assert(R.getResultKind() != LookupResult::Ambiguous &&
"literal operator lookup can't be ambiguous");
@@ -2719,8 +2720,9 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
// Filter the lookup results appropriately.
LookupResult::Filter F = R.makeFilter();
- bool FoundTemplate = false;
bool FoundRaw = false;
+ bool FoundTemplate = false;
+ bool FoundStringTemplate = false;
bool FoundExactMatch = false;
while (F.hasNext()) {
@@ -2728,16 +2730,17 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
D = USD->getTargetDecl();
- bool IsTemplate = isa<FunctionTemplateDecl>(D);
- bool IsRaw = false;
- bool IsExactMatch = false;
-
// If the declaration we found is invalid, skip it.
if (D->isInvalidDecl()) {
F.erase();
continue;
}
+ bool IsRaw = false;
+ bool IsTemplate = false;
+ bool IsStringTemplate = false;
+ bool IsExactMatch = false;
+
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getNumParams() == 1 &&
FD->getParamDecl(0)->getType()->getAs<PointerType>())
@@ -2753,19 +2756,31 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
}
}
}
+ if (FunctionTemplateDecl *FD = dyn_cast<FunctionTemplateDecl>(D)) {
+ TemplateParameterList *Params = FD->getTemplateParameters();
+ if (Params->size() == 1)
+ IsTemplate = true;
+ else
+ IsStringTemplate = true;
+ }
if (IsExactMatch) {
FoundExactMatch = true;
- AllowRawAndTemplate = false;
- if (FoundRaw || FoundTemplate) {
+ AllowRaw = false;
+ AllowTemplate = false;
+ AllowStringTemplate = false;
+ if (FoundRaw || FoundTemplate || FoundStringTemplate) {
// Go through again and remove the raw and template decls we've
// already found.
F.restart();
- FoundRaw = FoundTemplate = false;
+ FoundRaw = FoundTemplate = FoundStringTemplate = false;
}
- } else if (AllowRawAndTemplate && (IsTemplate || IsRaw)) {
- FoundTemplate |= IsTemplate;
- FoundRaw |= IsRaw;
+ } else if (AllowRaw && IsRaw) {
+ FoundRaw = true;
+ } else if (AllowTemplate && IsTemplate) {
+ FoundTemplate = true;
+ } else if (AllowStringTemplate && IsStringTemplate) {
+ FoundStringTemplate = true;
} else {
F.erase();
}
@@ -2800,10 +2815,14 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (FoundTemplate)
return LOLR_Template;
+ if (FoundStringTemplate)
+ return LOLR_StringTemplate;
+
// Didn't find anything we could use.
Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator)
<< R.getLookupName() << (int)ArgTys.size() << ArgTys[0]
- << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRawAndTemplate;
+ << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw
+ << (AllowTemplate || AllowStringTemplate);
return LOLR_Error;
}
OpenPOWER on IntegriCloud