本文整理汇总了C++中ASTContext::getLangOpts方法的典型用法代码示例。如果您正苦于以下问题:C++ ASTContext::getLangOpts方法的具体用法?C++ ASTContext::getLangOpts怎么用?C++ ASTContext::getLangOpts使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类ASTContext
的用法示例。
在下文中一共展示了ASTContext::getLangOpts方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: HandleTagDeclDefinition
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
/// to (e.g. struct, union, enum, class) is completed. This allows the
/// client hack on the type, which can occur at any point in the file
/// (because these can be defined in declspecs).
void HandleTagDeclDefinition(TagDecl *D) override {
if (Diags.hasErrorOccurred())
return;
Builder->UpdateCompletedType(D);
// For MSVC compatibility, treat declarations of static data members with
// inline initializers as definitions.
if (Ctx->getLangOpts().MSVCCompat) {
for (Decl *Member : D->decls()) {
if (VarDecl *VD = dyn_cast<VarDecl>(Member)) {
if (Ctx->isMSStaticDataMemberInlineDefinition(VD) &&
Ctx->DeclMustBeEmitted(VD)) {
Builder->EmitGlobal(VD);
}
}
}
}
}
示例2: printSourceRange
static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
raw_ostream &OS) {
SourceManager &SM = Ctx.getSourceManager();
const LangOptions &langOpts = Ctx.getLangOpts();
PresumedLoc PL = SM.getPresumedLoc(range.getBegin());
OS << llvm::sys::path::filename(PL.getFilename());
OS << " [" << PL.getLine() << ":"
<< PL.getColumn();
OS << " - ";
SourceLocation end = range.getEnd();
PL = SM.getPresumedLoc(end);
unsigned endCol = PL.getColumn() - 1;
if (!range.isTokenRange())
endCol += Lexer::MeasureTokenLength(end, SM, langOpts);
OS << PL.getLine() << ":" << endCol << "]";
}
示例3: handleMoveFix
void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl &Var,
const DeclRefExpr &CopyArgument,
const ASTContext &Context) {
auto Diag = diag(CopyArgument.getLocStart(),
"parameter %0 is passed by value and only copied once; "
"consider moving it to avoid unnecessary copies")
<< &Var;
// Do not propose fixes in macros since we cannot place them correctly.
if (CopyArgument.getLocStart().isMacroID())
return;
const auto &SM = Context.getSourceManager();
auto EndLoc = Lexer::getLocForEndOfToken(CopyArgument.getLocation(), 0, SM,
Context.getLangOpts());
Diag << FixItHint::CreateInsertion(CopyArgument.getLocStart(), "std::move(")
<< FixItHint::CreateInsertion(EndLoc, ")");
if (auto IncludeFixit = Inserter->CreateIncludeInsertion(
SM.getFileID(CopyArgument.getLocStart()), "utility",
/*IsAngled=*/true))
Diag << *IncludeFixit;
}
示例4: ClassifyConditional
static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True,
const Expr *False) {
assert(Ctx.getLangOpts().CPlusPlus &&
"This is only relevant for C++.");
// C++ [expr.cond]p2
// If either the second or the third operand has type (cv) void, [...]
// the result [...] is a prvalue.
if (True->getType()->isVoidType() || False->getType()->isVoidType())
return Cl::CL_PRValue;
// Note that at this point, we have already performed all conversions
// according to [expr.cond]p3.
// C++ [expr.cond]p4: If the second and third operands are glvalues of the
// same value category [...], the result is of that [...] value category.
// C++ [expr.cond]p5: Otherwise, the result is a prvalue.
Cl::Kinds LCl = ClassifyInternal(Ctx, True),
RCl = ClassifyInternal(Ctx, False);
return LCl == RCl ? LCl : Cl::CL_PRValue;
}
示例5: CheckRemoval
// Checks if 'typedef' keyword can be removed - we do it only if
// it is the only declaration in a declaration chain.
static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart,
const SourceLocation &LocEnd, ASTContext &Context,
SourceRange &ResultRange) {
FileID FID = SM.getFileID(LocEnd);
llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd);
Lexer DeclLexer(SM.getLocForStartOfFile(FID), Context.getLangOpts(),
Buffer->getBufferStart(), SM.getCharacterData(LocStart),
Buffer->getBufferEnd());
Token DeclToken;
bool result = false;
int parenthesisLevel = 0;
while (!DeclLexer.LexFromRawLexer(DeclToken)) {
if (DeclToken.getKind() == tok::TokenKind::l_paren)
parenthesisLevel++;
if (DeclToken.getKind() == tok::TokenKind::r_paren)
parenthesisLevel--;
if (DeclToken.getKind() == tok::TokenKind::semi)
break;
// if there is comma and we are not between open parenthesis then it is
// two or more declatarions in this chain
if (parenthesisLevel == 0 && DeclToken.getKind() == tok::TokenKind::comma)
return false;
if (DeclToken.isOneOf(tok::TokenKind::identifier,
tok::TokenKind::raw_identifier)) {
auto TokenStr = DeclToken.getRawIdentifier().str();
if (TokenStr == "typedef") {
ResultRange =
SourceRange(DeclToken.getLocation(), DeclToken.getEndLoc());
result = true;
}
}
}
// assert if there was keyword 'typedef' in declaration
assert(result && "No typedef found");
return result;
}
示例6: ClassifyImpl
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
assert(!TR->isReferenceType() && "Expressions can't have reference type.");
Cl::Kinds kind = ClassifyInternal(Ctx, this);
// C99 6.3.2.1: An lvalue is an expression with an object type or an
// incomplete type other than void.
if (!Ctx.getLangOpts().CPlusPlus) {
// Thus, no functions.
if (TR->isFunctionType() || TR == Ctx.OverloadTy)
kind = Cl::CL_Function;
// No void either, but qualified void is OK because it is "other than void".
// Void "lvalues" are classified as addressable void values, which are void
// expressions whose address can be taken.
else if (TR->isVoidType() && !TR.hasQualifiers())
kind = (kind == Cl::CL_LValue ? Cl::CL_AddressableVoid : Cl::CL_Void);
}
// Enable this assertion for testing.
switch (kind) {
case Cl::CL_LValue: assert(getValueKind() == VK_LValue); break;
case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break;
case Cl::CL_Function:
case Cl::CL_Void:
case Cl::CL_AddressableVoid:
case Cl::CL_DuplicateVectorComponents:
case Cl::CL_MemberFunction:
case Cl::CL_SubObjCPropertySetting:
case Cl::CL_ClassTemporary:
case Cl::CL_ArrayTemporary:
case Cl::CL_ObjCMessageRValue:
case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break;
}
Cl::ModifiableType modifiable = Cl::CM_Untested;
if (Loc)
modifiable = IsModifiable(Ctx, this, kind, *Loc);
return Classification(kind, modifiable);
}
示例7: ClassifyDecl
/// ClassifyDecl - Return the classification of an expression referencing the
/// given declaration.
static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
// C++ [expr.prim.general]p6: The result is an lvalue if the entity is a
// function, variable, or data member and a prvalue otherwise.
// In C, functions are not lvalues.
// In addition, NonTypeTemplateParmDecl derives from VarDecl but isn't an
// lvalue unless it's a reference type (C++ [temp.param]p6), so we need to
// special-case this.
if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())
return Cl::CL_MemberFunction;
bool islvalue;
if (const NonTypeTemplateParmDecl *NTTParm =
dyn_cast<NonTypeTemplateParmDecl>(D))
islvalue = NTTParm->getType()->isReferenceType();
else
islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||
isa<IndirectFieldDecl>(D) ||
(Ctx.getLangOpts().CPlusPlus &&
(isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)));
return islvalue ? Cl::CL_LValue : Cl::CL_PRValue;
}
示例8: HandleTranslationUnit
void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
D != DEnd; ++D) {
if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
migrateObjCInterfaceDecl(Ctx, CDecl);
}
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
RewritesReceiver Rec(rewriter);
Editor->applyRewrites(Rec);
for (Rewriter::buffer_iterator
I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
FileID FID = I->first;
RewriteBuffer &buf = I->second;
const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
assert(file);
SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
vecOS.flush();
llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
StringRef(newText.data(), newText.size()), file->getName());
SmallString<64> filePath(file->getName());
FileMgr.FixupRelativePath(filePath);
Remapper.remap(filePath.str(), memBuf);
}
if (IsOutputFile) {
Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
} else {
Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
}
}
示例9: AnalyzeAsmString
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
const ASTContext &C, unsigned &DiagOffs) const {
StringRef Str = getAsmString()->getString();
const char *StrStart = Str.begin();
const char *StrEnd = Str.end();
const char *CurPtr = StrStart;
// "Simple" inline asms have no constraints or operands, just convert the asm
// string to escape $'s.
if (isSimple()) {
std::string Result;
for (; CurPtr != StrEnd; ++CurPtr) {
switch (*CurPtr) {
case '$':
Result += "$$";
break;
default:
Result += *CurPtr;
break;
}
}
Pieces.push_back(AsmStringPiece(Result));
return 0;
}
// CurStringPiece - The current string that we are building up as we scan the
// asm string.
std::string CurStringPiece;
bool HasVariants = !C.getTargetInfo().hasNoAsmVariants();
while (1) {
// Done with the string?
if (CurPtr == StrEnd) {
if (!CurStringPiece.empty())
Pieces.push_back(AsmStringPiece(CurStringPiece));
return 0;
}
char CurChar = *CurPtr++;
switch (CurChar) {
case '$': CurStringPiece += "$$"; continue;
case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue;
case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue;
case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue;
case '%':
break;
default:
CurStringPiece += CurChar;
continue;
}
// Escaped "%" character in asm string.
if (CurPtr == StrEnd) {
// % at end of string is invalid (no escape).
DiagOffs = CurPtr-StrStart-1;
return diag::err_asm_invalid_escape;
}
char EscapedChar = *CurPtr++;
if (EscapedChar == '%') { // %% -> %
// Escaped percentage sign.
CurStringPiece += '%';
continue;
}
if (EscapedChar == '=') { // %= -> Generate an unique ID.
CurStringPiece += "${:uid}";
continue;
}
// Otherwise, we have an operand. If we have accumulated a string so far,
// add it to the Pieces list.
if (!CurStringPiece.empty()) {
Pieces.push_back(AsmStringPiece(CurStringPiece));
CurStringPiece.clear();
}
// Handle operands that have asmSymbolicName (e.g., %x[foo]) and those that
// don't (e.g., %x4). 'x' following the '%' is the constraint modifier.
const char *Begin = CurPtr - 1; // Points to the character following '%'.
const char *Percent = Begin - 1; // Points to '%'.
if (isLetter(EscapedChar)) {
if (CurPtr == StrEnd) { // Premature end.
DiagOffs = CurPtr-StrStart-1;
return diag::err_asm_invalid_escape;
}
EscapedChar = *CurPtr++;
}
const TargetInfo &TI = C.getTargetInfo();
const SourceManager &SM = C.getSourceManager();
const LangOptions &LO = C.getLangOpts();
// Handle operands that don't have asmSymbolicName (e.g., %x4).
//.........这里部分代码省略.........
示例10: InserterVisitor
explicit InserterVisitor(CompilerInstance *CI)
: astContext(&(CI->getASTContext()))
{
rewriter.setSourceMgr(astContext->getSourceManager(), astContext->getLangOpts());
}
示例11: GetDiagForGotoScopeDecl
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
/// diagnostic that should be emitted if control goes over it. If not, return 0.
static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
unsigned InDiag = 0;
if (VD->getType()->isVariablyModifiedType())
InDiag = diag::note_protected_by_vla;
if (VD->hasAttr<BlocksAttr>())
return ScopePair(diag::note_protected_by___block,
diag::note_exits___block);
if (VD->hasAttr<CleanupAttr>())
return ScopePair(diag::note_protected_by_cleanup,
diag::note_exits_cleanup);
if (Context.getLangOpts().ObjCAutoRefCount && VD->hasLocalStorage()) {
switch (VD->getType().getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
break;
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
return ScopePair(diag::note_protected_by_objc_ownership,
diag::note_exits_objc_ownership);
}
}
if (Context.getLangOpts().CPlusPlus && VD->hasLocalStorage()) {
// C++11 [stmt.dcl]p3:
// A program that jumps from a point where a variable with automatic
// storage duration is not in scope to a point where it is in scope
// is ill-formed unless the variable has scalar type, class type with
// a trivial default constructor and a trivial destructor, a
// cv-qualified version of one of these types, or an array of one of
// the preceding types and is declared without an initializer.
// C++03 [stmt.dcl.p3:
// A program that jumps from a point where a local variable
// with automatic storage duration is not in scope to a point
// where it is in scope is ill-formed unless the variable has
// POD type and is declared without an initializer.
const Expr *Init = VD->getInit();
if (!Init)
return ScopePair(InDiag, 0);
const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init);
if (EWC)
Init = EWC->getSubExpr();
const MaterializeTemporaryExpr *M = NULL;
Init = Init->findMaterializedTemporary(M);
SmallVector<SubobjectAdjustment, 2> Adjustments;
Init = Init->skipRValueSubobjectAdjustments(Adjustments);
QualType QT = Init->getType();
if (QT.isNull())
return ScopePair(diag::note_protected_by_variable_init, 0);
const Type *T = QT.getTypePtr();
if (T->isArrayType())
T = T->getBaseElementTypeUnsafe();
const CXXRecordDecl *Record = T->getAsCXXRecordDecl();
if (!Record)
return ScopePair(diag::note_protected_by_variable_init, 0);
// If we need to call a non trivial destructor for this variable,
// record an out diagnostic.
unsigned OutDiag = 0;
if (!Init->isGLValue() && !Record->hasTrivialDestructor())
OutDiag = diag::note_exits_dtor;
if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) {
const CXXConstructorDecl *ctor = cce->getConstructor();
if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
if (OutDiag)
InDiag = diag::note_protected_by_variable_nontriv_destructor;
else if (!Record->isPOD())
InDiag = diag::note_protected_by_variable_non_pod;
return ScopePair(InDiag, OutDiag);
}
}
return ScopePair(diag::note_protected_by_variable_init, OutDiag);
}
return ScopePair(InDiag, 0);
}
if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
return ScopePair(diag::note_protected_by_vla_typedef, 0);
}
if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) {
//.........这里部分代码省略.........
示例12: checkReturnValueType
static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E,
QualType &DeducedType,
QualType &AlternateType) {
// Handle ReturnStmts with no expressions.
if (!E) {
if (AlternateType.isNull())
AlternateType = Ctx.VoidTy;
return Ctx.hasSameType(DeducedType, Ctx.VoidTy);
}
QualType StrictType = E->getType();
QualType LooseType = StrictType;
// In C, enum constants have the type of their underlying integer type,
// not the enum. When inferring block return types, we should allow
// the enum type if an enum constant is used, unless the enum is
// anonymous (in which case there can be no variables of its type).
if (!Ctx.getLangOpts().CPlusPlus) {
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
if (DRE) {
const Decl *D = DRE->getDecl();
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl())
LooseType = Ctx.getTypeDeclType(Enum);
}
}
}
// Special case for the first return statement we find.
// The return type has already been tentatively set, but we might still
// have an alternate type we should prefer.
if (AlternateType.isNull())
AlternateType = LooseType;
if (Ctx.hasSameType(DeducedType, StrictType)) {
// FIXME: The loose type is different when there are constants from two
// different enums. We could consider warning here.
if (AlternateType != Ctx.DependentTy)
if (!Ctx.hasSameType(AlternateType, LooseType))
AlternateType = Ctx.VoidTy;
return true;
}
if (Ctx.hasSameType(DeducedType, LooseType)) {
// Use DependentTy to signal that we're using an alternate type and may
// need to add casts somewhere.
AlternateType = Ctx.DependentTy;
return true;
}
if (Ctx.hasSameType(AlternateType, StrictType) ||
Ctx.hasSameType(AlternateType, LooseType)) {
DeducedType = AlternateType;
// Use DependentTy to signal that we're using an alternate type and may
// need to add casts somewhere.
AlternateType = Ctx.DependentTy;
return true;
}
return false;
}
示例13: Initialize
void HTMLPrinter::Initialize(ASTContext &context) {
R.setSourceMgr(context.getSourceManager(), context.getLangOpts());
}
示例14: ExampleVisitor
explicit ExampleVisitor(CompilerInstance *CI)
: astContext(&(CI->getASTContext())) // initialize private members
{
rewriter.setSourceMgr(astContext->getSourceManager(), astContext->getLangOpts());
}
示例15: ClassifyInternal
static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// This function takes the first stab at classifying expressions.
const LangOptions &Lang = Ctx.getLangOpts();
switch (E->getStmtClass()) {
case Stmt::NoStmtClass:
#define ABSTRACT_STMT(Kind)
#define STMT(Kind, Base) case Expr::Kind##Class:
#define EXPR(Kind, Base)
#include "clang/AST/StmtNodes.inc"
llvm_unreachable("cannot classify a statement");
// First come the expressions that are always lvalues, unconditionally.
case Expr::ObjCIsaExprClass:
// C++ [expr.prim.general]p1: A string literal is an lvalue.
case Expr::StringLiteralClass:
// @encode is equivalent to its string
case Expr::ObjCEncodeExprClass:
// __func__ and friends are too.
case Expr::PredefinedExprClass:
// Property references are lvalues
case Expr::ObjCSubscriptRefExprClass:
case Expr::ObjCPropertyRefExprClass:
// C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of...
case Expr::CXXTypeidExprClass:
// Unresolved lookups and uncorrected typos get classified as lvalues.
// FIXME: Is this wise? Should they get their own kind?
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
case Expr::TypoExprClass:
case Expr::DependentCoawaitExprClass:
case Expr::CXXDependentScopeMemberExprClass:
case Expr::DependentScopeDeclRefExprClass:
// ObjC instance variables are lvalues
// FIXME: ObjC++0x might have different rules
case Expr::ObjCIvarRefExprClass:
case Expr::FunctionParmPackExprClass:
case Expr::MSPropertyRefExprClass:
case Expr::MSPropertySubscriptExprClass:
case Expr::OMPArraySectionExprClass:
return Cl::CL_LValue;
// C99 6.5.2.5p5 says that compound literals are lvalues.
// In C++, they're prvalue temporaries, except for file-scope arrays.
case Expr::CompoundLiteralExprClass:
return !E->isLValue() ? ClassifyTemporary(E->getType()) : Cl::CL_LValue;
// Expressions that are prvalues.
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXPseudoDestructorExprClass:
case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::CXXNewExprClass:
case Expr::CXXThisExprClass:
case Expr::CXXNullPtrLiteralExprClass:
case Expr::ImaginaryLiteralClass:
case Expr::GNUNullExprClass:
case Expr::OffsetOfExprClass:
case Expr::CXXThrowExprClass:
case Expr::ShuffleVectorExprClass:
case Expr::ConvertVectorExprClass:
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::AddrLabelExprClass:
case Expr::CXXDeleteExprClass:
case Expr::ImplicitValueInitExprClass:
case Expr::BlockExprClass:
case Expr::FloatingLiteralClass:
case Expr::CXXNoexceptExprClass:
case Expr::CXXScalarValueInitExprClass:
case Expr::TypeTraitExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCProtocolExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCBoxedExprClass:
case Expr::ObjCArrayLiteralClass:
case Expr::ObjCDictionaryLiteralClass:
case Expr::ObjCBoolLiteralExprClass:
case Expr::ObjCAvailabilityCheckExprClass:
case Expr::ParenListExprClass:
case Expr::SizeOfPackExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::AtomicExprClass:
case Expr::CXXFoldExprClass:
case Expr::ArrayInitLoopExprClass:
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
case Expr::CoyieldExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
case Expr::SubstNonTypeTemplateParmExprClass:
return ClassifyInternal(Ctx,
cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
// C, C++98 [expr.sub]p1: The result is an lvalue of type "T".
//.........这里部分代码省略.........