From: Hans Wennborg Date: Fri, 10 May 2013 10:08:40 +0000 (+0000) Subject: Add support for __wchar_t in -fms-extensions mode. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=15f92bad58c8650b1306729744b1a1230197497a;p=clang 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 . This fixes PR15815. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181587 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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: /// . 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 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 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}}