summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2013-05-10 10:08:40 +0000
committerHans Wennborg <hans@hanshq.net>2013-05-10 10:08:40 +0000
commit15f92bad58c8650b1306729744b1a1230197497a (patch)
tree5cc22ac3531caff665c992d70e0bd268649218bb
parent6ea933c7e8f6988d5647af4a0eafd393a4c3685a (diff)
downloadclang-15f92bad58c8650b1306729744b1a1230197497a.tar.gz
clang-15f92bad58c8650b1306729744b1a1230197497a.tar.bz2
clang-15f92bad58c8650b1306729744b1a1230197497a.tar.xz
Add support for __wchar_t in -fms-extensions mode.
MSVC provides __wchar_t. This is the same as the built-in wchar_t type from C++, but it is also available with -fno-wchar and in C. The commit changes ASTContext to have two different types for this: - WCharTy is the built-in type used for wchar_t in C++ and __wchar_t. - WideCharTy is the type of a wide character literal. In C++ this is the same as WCharTy, and in C it is an integer type compatible with the type in <stddef.h>. This fixes PR15815. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181587 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h13
-rw-r--r--include/clang/AST/PrettyPrinter.h7
-rw-r--r--include/clang/Basic/TokenKinds.def1
-rw-r--r--lib/AST/ASTContext.cpp18
-rw-r--r--lib/AST/Type.cpp2
-rw-r--r--lib/Analysis/FormatString.cpp4
-rw-r--r--lib/Analysis/PrintfFormatString.cpp2
-rw-r--r--lib/Analysis/ScanfFormatString.cpp4
-rw-r--r--lib/Sema/SemaDeclCXX.cpp4
-rw-r--r--lib/Sema/SemaExpr.cpp6
-rw-r--r--lib/Sema/SemaExprObjC.cpp4
-rw-r--r--lib/Sema/SemaInit.cpp2
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp2
-rw-r--r--test/Sema/ms-wchar.c15
-rw-r--r--test/SemaCXX/ms-wchar.cpp9
15 files changed, 66 insertions, 27 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index c5d3337fd2..2d08c49e1d 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -740,7 +740,8 @@ public:
CanQualType VoidTy;
CanQualType BoolTy;
CanQualType CharTy;
- CanQualType WCharTy; // [C++ 3.9.1p5], integer type in C99.
+ CanQualType WCharTy; // [C++ 3.9.1p5].
+ CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99.
CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions.
CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99.
CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99.
@@ -1130,11 +1131,15 @@ public:
/// <stdint.h>.
CanQualType getUIntMaxType() const;
- /// \brief In C++, this returns the unique wchar_t type. In C99, this
- /// returns a type compatible with the type defined in <stddef.h> as defined
- /// by the target.
+ /// \brief Return the unique wchar_t type available in C++ (and available as
+ /// __wchar_t as a Microsoft extension).
QualType getWCharType() const { return WCharTy; }
+ /// \brief Return the type of wide characters. In C++, this returns the
+ /// unique wchar_t type. In C99, this returns a type compatible with the type
+ /// defined in <stddef.h> as defined by the target.
+ QualType getWideCharType() const { return WideCharTy; }
+
/// \brief Return the type of "signed wchar_t".
///
/// Used when in C++, as a GCC extension.
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index e3c09e7b41..adfd1ac936 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -40,7 +40,8 @@ struct PrintingPolicy {
SuppressUnwrittenScope(false), SuppressInitializers(false),
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
SuppressStrongLifetime(false), Bool(LO.Bool),
- TerseOutput(false), PolishForDeclaration(false) { }
+ TerseOutput(false), PolishForDeclaration(false),
+ MSWChar(LO.MicrosoftExt && !LO.WChar) { }
/// \brief What language we're printing.
LangOptions LangOpts;
@@ -146,6 +147,10 @@ struct PrintingPolicy {
/// declaration tag; such as, do not print attributes attached to the declaration.
///
unsigned PolishForDeclaration : 1;
+
+ /// \brief When true, print the built-in wchar_t type as __wchar_t. For use in
+ /// Microsoft mode when wchar_t is not available.
+ unsigned MSWChar : 1;
};
} // end namespace clang
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index bcf0f31dcb..0dbff81d34 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -524,6 +524,7 @@ KEYWORD(__interface , KEYMS)
ALIAS("__int8" , char , KEYMS)
ALIAS("__int16" , short , KEYMS)
ALIAS("__int32" , int , KEYMS)
+ALIAS("__wchar_t" , wchar_t , KEYMS)
ALIAS("_asm" , asm , KEYMS)
ALIAS("_alignof" , __alignof , KEYMS)
ALIAS("__builtin_alignof", __alignof , KEYMS)
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index ffcf6b5d7a..960f261816 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -897,13 +897,17 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(Int128Ty, BuiltinType::Int128);
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
- if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5
- if (TargetInfo::isTypeSigned(Target.getWCharType()))
- InitBuiltinType(WCharTy, BuiltinType::WChar_S);
- else // -fshort-wchar makes wchar_t be unsigned.
- InitBuiltinType(WCharTy, BuiltinType::WChar_U);
- } else // C99 (or C++ using -fno-wchar)
- WCharTy = getFromTargetType(Target.getWCharType());
+ // C++ 3.9.1p5
+ if (TargetInfo::isTypeSigned(Target.getWCharType()))
+ InitBuiltinType(WCharTy, BuiltinType::WChar_S);
+ else // -fshort-wchar makes wchar_t be unsigned.
+ InitBuiltinType(WCharTy, BuiltinType::WChar_U);
+ if (LangOpts.CPlusPlus && LangOpts.WChar)
+ WideCharTy = WCharTy;
+ else {
+ // C99 (or C++ using -fno-wchar).
+ WideCharTy = getFromTargetType(Target.getWCharType());
+ }
WIntTy = getFromTargetType(Target.getWIntType());
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index fa16facb63..a1f0b08494 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1521,7 +1521,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Double: return "double";
case LongDouble: return "long double";
case WChar_S:
- case WChar_U: return "wchar_t";
+ case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t";
case Char16: return "char16_t";
case Char32: return "char32_t";
case NullPtr: return "nullptr_t";
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index ad0dce4444..382be24dca 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -334,7 +334,7 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const {
return false;
QualType pointeeTy =
C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
- return pointeeTy == C.getWCharType();
+ return pointeeTy == C.getWideCharType();
}
case WIntTy: {
@@ -398,7 +398,7 @@ QualType ArgType::getRepresentativeType(ASTContext &C) const {
Res = C.getPointerType(C.CharTy);
break;
case WCStrTy:
- Res = C.getPointerType(C.getWCharType());
+ Res = C.getPointerType(C.getWideCharType());
break;
case ObjCPointerTy:
Res = C.ObjCBuiltinIdTy;
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 8f151b9358..60f9517e7f 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -372,7 +372,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case ConversionSpecifier::CArg:
if (IsObjCLiteral)
return ArgType(Ctx.UnsignedShortTy, "unichar");
- return ArgType(Ctx.WCharTy, "wchar_t");
+ return ArgType(Ctx.WideCharTy, "wchar_t");
case ConversionSpecifier::pArg:
return ArgType::CPointerTy;
case ConversionSpecifier::ObjCObjArg:
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 2dbc9e4948..676b68f391 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -311,7 +311,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::None:
return ArgType::PtrTo(ArgType::AnyCharTy);
case LengthModifier::AsLong:
- return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
+ return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ArgType::PtrTo(ArgType::CStrTy);
@@ -323,7 +323,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
// FIXME: Mac OS X specific?
switch (LM.getKind()) {
case LengthModifier::None:
- return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
+ return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b86a2b9277..e5d0316f73 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -10408,7 +10408,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
Context.hasSameType(T, Context.LongDoubleTy) ||
Context.hasSameType(T, Context.CharTy) ||
- Context.hasSameType(T, Context.WCharTy) ||
+ Context.hasSameType(T, Context.WideCharTy) ||
Context.hasSameType(T, Context.Char16Ty) ||
Context.hasSameType(T, Context.Char32Ty)) {
if (++Param == FnDecl->param_end())
@@ -10438,7 +10438,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
// 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.WCharTy) ||
+ Context.hasSameType(T, Context.WideCharTy) ||
Context.hasSameType(T, Context.Char16Ty) ||
Context.hasSameType(T, Context.Char32Ty)))
goto FinishedParams;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 031a631f6c..ef7e0f2e33 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1448,7 +1448,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
QualType StrTy = Context.CharTy;
if (Literal.isWide())
- StrTy = Context.getWCharType();
+ StrTy = Context.getWideCharType();
else if (Literal.isUTF16())
StrTy = Context.Char16Ty;
else if (Literal.isUTF32())
@@ -2720,7 +2720,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
llvm::APInt LengthI(32, Length + 1);
if (IT == PredefinedExpr::LFunction)
- ResTy = Context.WCharTy.withConst();
+ ResTy = Context.WideCharTy.withConst();
else
ResTy = Context.CharTy.withConst();
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
@@ -2742,7 +2742,7 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
QualType Ty;
if (Literal.isWide())
- Ty = Context.WCharTy; // L'x' -> wchar_t in C and C++.
+ Ty = Context.WideCharTy; // L'x' -> wchar_t in C and C++.
else if (Literal.isUTF16())
Ty = Context.Char16Ty; // u'x' -> char16_t in C11 and C++11.
else if (Literal.isUTF32())
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 0e3dc003ab..d37f61ab8a 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -266,7 +266,7 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
break;
case CharacterLiteral::Wide:
- NumberType = Context.getWCharType();
+ NumberType = Context.getWideCharType();
break;
case CharacterLiteral::UTF16:
@@ -521,7 +521,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
break;
case CharacterLiteral::Wide:
- ValueType = Context.getWCharType();
+ ValueType = Context.getWideCharType();
break;
case CharacterLiteral::UTF16:
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 9e8936e17b..7016e565da 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -65,7 +65,7 @@ static Expr *IsStringInit(Expr *Init, const ArrayType *AT,
// correction from DR343): "An array with element type compatible with a
// qualified or unqualified version of wchar_t may be initialized by a wide
// string literal, optionally enclosed in braces."
- if (Context.typesAreCompatible(Context.getWCharType(),
+ if (Context.typesAreCompatible(Context.getWideCharType(),
ElemTy.getUnqualifiedType()))
return Init;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 7ef04e964d..862334a82a 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1105,7 +1105,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
llvm::APInt LengthI(32, Length + 1);
QualType ResTy;
if (IT == PredefinedExpr::LFunction)
- ResTy = getSema().Context.WCharTy.withConst();
+ ResTy = getSema().Context.WideCharTy.withConst();
else
ResTy = getSema().Context.CharTy.withConst();
ResTy = getSema().Context.getConstantArrayType(ResTy, LengthI,
diff --git a/test/Sema/ms-wchar.c b/test/Sema/ms-wchar.c
new file mode 100644
index 0000000000..52a736c640
--- /dev/null
+++ b/test/Sema/ms-wchar.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+// C++ mode with -fno-wchar works the same as C mode for wchar_t.
+// RUN: %clang_cc1 -x c++ -fno-wchar -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+wchar_t f(); // expected-error{{unknown type name 'wchar_t'}}
+
+// __wchar_t is available as an MS extension.
+__wchar_t g = L'a'; // expected-note {{previous}}
+
+// __wchar_t is a distinct type, separate from the target's integer type for wide chars.
+unsigned short g; // expected-error {{redefinition of 'g' with a different type: 'unsigned short' vs '__wchar_t'}}
+
+// The type of a wide string literal is actually not __wchar_t.
+__wchar_t s[] = L"Hello world!"; // expected-error {{array initializer must be an initializer list}}
diff --git a/test/SemaCXX/ms-wchar.cpp b/test/SemaCXX/ms-wchar.cpp
new file mode 100644
index 0000000000..2cbf745d33
--- /dev/null
+++ b/test/SemaCXX/ms-wchar.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+wchar_t f();
+__wchar_t f(); // No error, wchar_t and __wchar_t are the same type.
+
+__wchar_t g = L'a';
+__wchar_t s[] = L"Hello world!";
+
+unsigned short t[] = L"Hello world!"; // expected-error{{array initializer must be an initializer list}}